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
271 ProcFlagsInit const& typeMask, ProcFlagsSpellType spellTypeMask,
272 ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask,
273 Spell* spell, DamageInfo* damageInfo,
274 HealInfo* healInfo) :
275 _actor(actor), _actionTarget(actionTarget),
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 {
348 }
349 // implement 50% base damage from offhand
351
352 for (uint32 i = 0; i < uint32(AttackPowerModIndex::End); ++i)
353 {
357 }
358
359 for (uint8 i = 0; i < MAX_ATTACK; ++i)
360 {
363 }
364
365 m_floatStatPosBuff = { };
366 m_floatStatNegBuff = { };
367
368 m_attacking = nullptr;
369 m_modMeleeHitChance = 0.0f;
371 m_modSpellHitChance = 0.0f;
373
374 m_speed_rate.fill(1.0f);
375 SetFlightCapabilityID(0, false);
376
377 // remove aurastates allowing special moves
378 m_reactiveTimer = { };
379
380 m_cleanupDone = false;
382
384
385 _lastLiquid = nullptr;
386
387 _oldFactionId = 0;
388 _isWalkingBeforeCharm = false;
389 _instantCast = false;
390 _isCombatDisallowed = false;
391
393}
394
396// Methods of class Unit
398{
399 // set current spells as deletable
400 for (size_t i = 0; i < m_currentSpells.size(); ++i)
401 {
402 if (m_currentSpells[i])
403 {
404 m_currentSpells[i]->SetReferencedFromCurrent(false);
405 m_currentSpells[i] = nullptr;
406 }
407 }
408
410
412
415 ASSERT(m_attackers.empty());
416 ASSERT(m_sharedVision.empty());
417 ASSERT(m_Controlled.empty());
418 ASSERT(m_appliedAuras.empty());
419 ASSERT(m_ownedAuras.empty());
420 ASSERT(m_removedAuras.empty());
421 ASSERT(m_dynObj.empty());
422 ASSERT(m_gameObj.empty());
423 ASSERT(m_areaTrigger.empty());
426}
427
429{
430 // WARNING! Order of execution here is important, do not change.
431 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
432 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
433 WorldObject::Update(p_time);
434
435 if (!IsInWorld())
436 return;
437
438 _UpdateSpells(p_time);
439
440 // If this is set during update SetCantProc(false) call is missing somewhere in the code
441 // Having this would prevent spells from being proced, so let's crash
443
444 m_combatManager.Update(p_time);
445
448 {
449 while (!extraAttacksTargets.empty())
450 {
451 auto itr = extraAttacksTargets.begin();
452 ObjectGuid targetGuid = itr->first;
453 uint32 count = itr->second;
454 extraAttacksTargets.erase(itr);
455 if (Unit* victim = ObjectAccessor::GetUnit(*this, targetGuid))
456 HandleProcExtraAttackFor(victim, count);
457 }
459 }
460
461 auto spellPausesCombatTimer = [&](CurrentSpellTypes type)
462 {
464 };
465
466 if (!spellPausesCombatTimer(CURRENT_GENERIC_SPELL) && !spellPausesCombatTimer(CURRENT_CHANNELED_SPELL))
467 {
468 if (uint32 base_att = getAttackTimer(BASE_ATTACK))
469 setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time));
470 if (uint32 off_att = getAttackTimer(OFF_ATTACK))
471 setAttackTimer(OFF_ATTACK, (p_time >= off_att ? 0 : off_att - p_time));
472 if (uint32 ranged_att = getAttackTimer(RANGED_ATTACK))
473 setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time));
474 }
475
476 // update abilities available only for fraction of time
477 UpdateReactives(p_time);
478
479 if (IsAlive())
480 {
488 }
489
490 UpdateSplineMovement(p_time);
491 i_motionMaster->Update(p_time);
492
493 // Wait with the aura interrupts until we have updated our movement generators and position
494 if (GetTypeId() == TYPEID_PLAYER)
496 else if (!movespline->Finalized())
498
499 // All position info based actions have been executed, reset info
501
504 RefreshAI();
505}
506
508{
510
511 // SMSG_FLIGHT_SPLINE_SYNC for cyclic splines
513
514 // Trigger heartbeat procs and generic aura behavior such as food emotes and invoking aura script hooks
516
517 // Update Vignette position and visibility
518 if (m_vignette)
520}
521
523{
524 for (auto const& [_, auraApplication] : m_appliedAuras)
525 auraApplication->GetBase()->Heartbeat();
526
528}
529
531{
532 if (Player const* player = ToPlayer())
533 return player->GetWeaponForAttack(OFF_ATTACK, true) != nullptr;
534
535 return CanDualWield();
536}
537
538void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath, bool forceDestination)
539{
540 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
541 {
542 init.MoveTo(x, y, z, generatePath, forceDestination);
543 init.SetVelocity(speed);
544 };
546}
547
572
574{
575 switch (type)
576 {
578 if (GetMap()->IsRaid())
581 break;
582 default:
583 break;
584 }
585
587 {
588 SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(cooldown.SpellId, DIFFICULTY_NONE);
590 return true;
591
592 if (SpellCategoryEntry const* category = sSpellCategoryStore.LookupEntry(spellInfo->CategoryId))
593 if (category->GetFlags().HasFlag(SpellCategoryFlags::ResetCooldownUponEndingEncounter))
594 return true;
595
596 return false;
597 }, true);
598}
599
601{
602 if (movespline->Finalized())
603 return;
604
605 movespline->updateState(t_diff);
606 bool arrived = movespline->Finalized();
607
608 if (arrived)
609 {
611
612 if (Optional<AnimTier> animTier = movespline->GetAnimation())
613 SetAnimTier(*animTier);
614 }
615
617}
618
620{
621 Movement::Location loc = movespline->ComputePosition();
622
623 if (movespline->onTransport)
624 {
626 pos.m_positionX = loc.x;
627 pos.m_positionY = loc.y;
628 pos.m_positionZ = loc.z;
630
631 if (TransportBase* transport = GetDirectTransport())
632 transport->GetPositionWithOffset(pos).GetPosition(loc.x, loc.y, loc.z, loc.orientation);
633 else
634 return;
635 }
636
639
640 UpdatePosition(loc.x, loc.y, loc.z, loc.orientation);
641}
642
644{
645 if (!movespline->isCyclic() || movespline->Finalized())
646 return;
647
649 flightSplineSync.Guid = GetGUID();
650 flightSplineSync.SplineDist = float(movespline->timePassed()) / movespline->Duration();
651 SendMessageToSet(flightSplineSync.Write(), true);
652}
653
655{
656 // TODO: Check if orientation transport offset changed instead of only global orientation
659
662}
663
669
674
675bool Unit::IsWithinCombatRange(Unit const* obj, float dist2compare) const
676{
677 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
678 return false;
679
680 float dx = GetPositionX() - obj->GetPositionX();
681 float dy = GetPositionY() - obj->GetPositionY();
682 float dz = GetPositionZ() - obj->GetPositionZ();
683 float distsq = dx * dx + dy * dy + dz * dz;
684
685 float sizefactor = GetCombatReach() + obj->GetCombatReach();
686 float maxdist = dist2compare + sizefactor;
687
688 return distsq < maxdist * maxdist;
689}
690
691bool Unit::IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const
692{
693 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
694 return false;
695
696 float dx = pos.GetPositionX() - obj->GetPositionX();
697 float dy = pos.GetPositionY() - obj->GetPositionY();
698 float dz = pos.GetPositionZ() - obj->GetPositionZ();
699 float distsq = dx*dx + dy*dy + dz*dz;
700
702
703 return distsq <= maxdist * maxdist;
704}
705
706float Unit::GetMeleeRange(Unit const* target) const
707{
708 float range = GetCombatReach() + target->GetCombatReach() + 4.0f / 3.0f;
709 return std::max(range, NOMINAL_MELEE_RANGE);
710}
711
712bool Unit::IsWithinBoundaryRadius(const Unit* obj) const
713{
714 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
715 return false;
716
717 float objBoundaryRadius = std::max(obj->GetBoundingRadius(), MIN_MELEE_REACH);
718
719 return IsInDist(obj, objBoundaryRadius);
720}
721
723{
724 m_visibleAuras.insert(aurApp);
725 m_visibleAurasToUpdate.insert(aurApp);
727}
728
730{
731 m_visibleAuras.erase(aurApp);
732 m_visibleAurasToUpdate.erase(aurApp);
734}
735
737{
738 m_visibleAurasToUpdate.insert(aurApp);
739}
740
745
747{
750 for (AuraApplication const* aurApp : m_interruptableAuras)
751 {
752 m_interruptMask |= aurApp->GetBase()->GetSpellInfo()->AuraInterruptFlags;
753 m_interruptMask2 |= aurApp->GetBase()->GetSpellInfo()->AuraInterruptFlags2;
754 }
755
757 {
758 if (spell->getState() == SPELL_STATE_CHANNELING)
759 {
760 m_interruptMask |= spell->m_spellInfo->ChannelInterruptFlags;
761 m_interruptMask2 |= spell->m_spellInfo->ChannelInterruptFlags2;
762 }
763 }
764}
765
766bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag128 familyFlags) const
767{
768 for (AuraEffect const* aura : GetAuraEffectsByType(auraType))
769 if (aura->GetSpellInfo()->SpellFamilyName == familyName && aura->GetSpellInfo()->SpellFamilyFlags & familyFlags)
770 return true;
771 return false;
772}
773
775{
776 for (AuraEffect const* aura : GetAuraEffectsByType(type))
777 if ((!excludeAura || excludeAura != aura->GetSpellInfo()->Id) && //Avoid self interrupt of channeled Crowd Control spells like Seduction
778 aura->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::AnyDamageMask))
779 return true;
780 return false;
781}
782
783bool Unit::HasBreakableByDamageCrowdControlAura(Unit const* excludeCasterChannel) const
784{
786 return false;
787
788 uint32 excludeAura = 0;
789 if (excludeCasterChannel)
790 if (Spell const* currentChanneledSpell = excludeCasterChannel->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
791 excludeAura = currentChanneledSpell->GetSpellInfo()->Id; //Avoid self interrupt of channeled Crowd Control spells like Seduction
792
793 // This function is named after spell attribute it is meant for - SPELL_ATTR6_DO_NOT_CHAIN_TO_CROWD_CONTROLLED_TARGETS
794 // Not checking aura type is not a mistake here
795 for (AuraApplication const* aurApp : m_interruptableAuras)
796 if (!aurApp->IsPositive()
797 && (!excludeAura || excludeAura != aurApp->GetBase()->GetId())
798 && aurApp->GetBase()->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::AnyDamageMask))
799 return true;
800
801 return false;
802}
803
804/*static*/ void Unit::DealDamageMods(Unit const* attacker, Unit const* victim, uint32& damage, uint32* absorb)
805{
806 if (!victim || !victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
807 {
808 if (absorb)
809 *absorb += damage;
810 damage = 0;
811 return;
812 }
813
814 if (attacker)
815 damage *= attacker->GetDamageMultiplierForTarget(victim);
816}
817
819{
820 AuraEffectVector effects;
821 std::copy(list.begin(), list.end(), std::back_inserter(effects));
822 return effects;
823}
824
825/*static*/ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
826{
827 uint32 damageDone = damage;
828 uint32 damageTaken = damage;
829 if (attacker)
830 damageTaken = damage / victim->GetHealthMultiplierForTarget(attacker);
831
832 // call script hooks
833 {
834 uint32 tmpDamage = damageTaken;
835
836 // sparring
837 if (Creature* victimCreature = victim->ToCreature())
838 tmpDamage = victimCreature->CalculateDamageForSparring(attacker, tmpDamage);
839
840 if (UnitAI* victimAI = victim->GetAI())
841 victimAI->DamageTaken(attacker, tmpDamage, damagetype, spellProto);
842
843 if (UnitAI* attackerAI = attacker ? attacker->GetAI() : nullptr)
844 attackerAI->DamageDealt(victim, tmpDamage, damagetype);
845
846 // Hook for OnDamage Event
847 sScriptMgr->OnDamage(attacker, victim, tmpDamage);
848
849 // if any script modified damage, we need to also apply the same modification to unscaled damage value
850 if (tmpDamage != damageTaken)
851 {
852 if (attacker)
853 damageDone = tmpDamage * victim->GetHealthMultiplierForTarget(attacker);
854 else
855 damageDone = tmpDamage;
856
857 damageTaken = tmpDamage;
858 }
859 }
860
861 // Signal to pets that their owner was attacked - except when DOT.
862 if (attacker != victim && damagetype != DOT)
863 {
864 for (Unit* controlled : victim->m_Controlled)
865 if (Creature* cControlled = controlled->ToCreature())
866 if (CreatureAI* controlledAI = cControlled->AI())
867 controlledAI->OwnerAttackedBy(attacker);
868 }
869
870 if (Player* player = victim->ToPlayer())
871 if (player->GetCommandStatus(CHEAT_GOD))
872 return 0;
873
874 if (damagetype != NODAMAGE)
875 {
876 // interrupting auras with SpellAuraInterruptFlags::Damage before checking !damage (absorbed damage breaks that type of auras)
877 if (spellProto)
878 {
881 }
882 else
884
885 if (!damageTaken && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage)
886 if (victim != attacker && victim->GetTypeId() == TYPEID_PLAYER)
887 if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
888 if (spell->getState() == SPELL_STATE_PREPARING && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageAbsorb))
889 victim->InterruptNonMeleeSpells(false);
890
891 // We're going to call functions which can modify content of the list during iteration over it's elements
892 // Let's copy the list so we can prevent iterator invalidation
894 // copy damage to casters of this aura
895 for (auto i = vCopyDamageCopy.begin(); i != vCopyDamageCopy.end(); ++i)
896 {
897 // Check if aura was removed during iteration - we don't need to work on such auras
898 if (!((*i)->GetBase()->IsAppliedOnTarget(victim->GetGUID())))
899 continue;
900 // check damage school mask
901 if (((*i)->GetMiscValue() & damageSchoolMask) == 0)
902 continue;
903
904 Unit* shareDamageTarget = (*i)->GetCaster();
905 if (!shareDamageTarget)
906 continue;
907 SpellInfo const* spell = (*i)->GetSpellInfo();
908
909 uint32 share = CalculatePct(damageDone, (*i)->GetAmount());
910
912 Unit::DealDamageMods(attacker, shareDamageTarget, share, nullptr);
913 Unit::DealDamage(attacker, shareDamageTarget, share, nullptr, NODAMAGE, spell->GetSchoolMask(), spell, false);
914 }
915 }
916
917 if (!damageDone)
918 return 0;
919
920 uint32 health = victim->GetHealth();
921
922 // duel ends when player has 1 or less hp
923 bool duel_hasEnded = false;
924 bool duel_wasMounted = false;
925 if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damageTaken >= (health-1))
926 {
927 if (!attacker)
928 return 0;
929
930 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
931 if (victim->ToPlayer()->duel->Opponent == attacker->GetControllingPlayer())
932 damageTaken = health - 1;
933
934 duel_hasEnded = true;
935 }
936 else if (victim->IsCreature() && victim != attacker && damageTaken >= health && victim->ToCreature()->HasFlag(CREATURE_STATIC_FLAG_UNKILLABLE))
937 {
938 damageTaken = health - 1;
939
940 // If we had damage (aka health was not 1 already) trigger OnHealthDepleted
941 if (damageTaken > 0)
942 {
943 if (CreatureAI* victimAI = victim->ToCreature()->AI())
944 victimAI->OnHealthDepleted(attacker, false);
945 }
946 }
947 else if (victim->IsVehicle() && damageTaken >= (health-1) && victim->GetCharmer() && victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER)
948 {
949 Player* victimRider = victim->GetCharmer()->ToPlayer();
950
951 if (victimRider && victimRider->duel && victimRider->duel->IsMounted)
952 {
953 if (!attacker)
954 return 0;
955
956 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
957 if (victimRider->duel->Opponent == attacker->GetControllingPlayer())
958 damageTaken = health - 1;
959
960 duel_wasMounted = true;
961 duel_hasEnded = true;
962 }
963 }
964
965 if (spellProto && spellProto->HasAttribute(SPELL_ATTR9_CANNOT_KILL_TARGET) && damageTaken >= health)
966 damageTaken = health - 1;
967
968 if (attacker && attacker != victim)
969 {
970 if (Player* killer = attacker->ToPlayer())
971 {
972 // in bg, count dmg if victim is also a player
973 if (victim->GetTypeId() == TYPEID_PLAYER && !(spellProto && spellProto->HasAttribute(SPELL_ATTR7_DO_NOT_COUNT_FOR_PVP_SCOREBOARD)))
974 if (Battleground* bg = killer->GetBattleground())
975 bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damageDone);
976
977 killer->UpdateCriteria(CriteriaType::DamageDealt, health > damageDone ? damageDone : health, 0, 0, victim);
978 killer->UpdateCriteria(CriteriaType::HighestDamageDone, damageDone);
979 }
980 }
981
982 if (victim->GetTypeId() == TYPEID_PLAYER)
984
985 if (victim->GetTypeId() != TYPEID_PLAYER && (!victim->IsControlledByPlayer() || victim->IsVehicle()))
986 {
987 victim->ToCreature()->SetTappedBy(attacker);
988
989 if (!attacker || attacker->IsControlledByPlayer())
990 victim->ToCreature()->LowerPlayerDamageReq(health < damageTaken ? health : damageTaken);
991 }
992
993 bool killed = false;
994 bool skipSettingDeathState = false;
995
996 if (health <= damageTaken)
997 {
998 killed = true;
999
1000 if (victim->GetTypeId() == TYPEID_PLAYER && victim != attacker)
1002
1003 if (damagetype != NODAMAGE && damagetype != SELF_DAMAGE && victim->HasAuraType(SPELL_AURA_SCHOOL_ABSORB_OVERKILL))
1004 {
1006 std::ranges::stable_sort(vAbsorbOverkill, Trinity::AbsorbAuraOrderPred());
1007 DamageInfo damageInfo = DamageInfo(attacker, victim, damageTaken, spellProto, damageSchoolMask, damagetype,
1008 cleanDamage ? cleanDamage->attackType : BASE_ATTACK);
1009 for (AuraEffect* absorbAurEff : vAbsorbOverkill)
1010 {
1011 Aura* base = absorbAurEff->GetBase();
1012 AuraApplication const* aurApp = base->GetApplicationOfTarget(victim->GetGUID());
1013 if (!aurApp)
1014 continue;
1015
1016 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1017 continue;
1018
1019 // cannot absorb over limit
1020 if (absorbAurEff->GetAmount() > 0)
1021 {
1022 if (damageTaken > absorbAurEff->GetAmount())
1023 continue;
1024 }
1025 else if (damageTaken >= victim->GetMaxHealth() * 2)
1026 continue;
1027
1028 // absorb all damage by default
1029 uint32 currentAbsorb = damageInfo.GetDamage();
1030
1031 // This aura type is used both by Spirit of Redemption (death not really prevented, must grant all credit immediately) and Cheat Death (death prevented)
1032 // repurpose PreventDefaultAction for this
1033 bool deathFullyPrevented = false;
1034
1035 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, currentAbsorb, deathFullyPrevented);
1036
1037 // absorb must be smaller than the damage itself
1038 currentAbsorb = std::min(currentAbsorb, damageInfo.GetDamage());
1039
1040 // if nothing is absorbed (for example because of a scripted cooldown) then skip this aura and proceed with dying
1041 if (!currentAbsorb)
1042 continue;
1043
1044 damageInfo.AbsorbDamage(currentAbsorb);
1045
1046 if (deathFullyPrevented)
1047 killed = false;
1048
1049 skipSettingDeathState = true;
1050
1051 if (currentAbsorb)
1052 {
1054 absorbLog.Attacker = attacker ? attacker->GetGUID() : ObjectGuid::Empty;
1055 absorbLog.Victim = victim->GetGUID();
1056 absorbLog.Caster = base->GetCasterGUID();
1057 absorbLog.AbsorbedSpellID = spellProto ? spellProto->Id : 0;
1058 absorbLog.AbsorbSpellID = base->GetId();
1059 absorbLog.Absorbed = currentAbsorb;
1060 absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
1061 absorbLog.LogData.Initialize(victim);
1062 victim->SendCombatLogMessage(&absorbLog);
1063 }
1065
1066 damageTaken = damageInfo.GetDamage();
1067 }
1068 }
1069
1070 if (spellProto && spellProto->HasAttribute(SPELL_ATTR3_NO_DURABILITY_LOSS))
1071 durabilityLoss = false;
1072
1073 if (killed)
1074 Unit::Kill(attacker, victim, durabilityLoss, skipSettingDeathState);
1075 else
1076 {
1077 if (victim->GetTypeId() == TYPEID_PLAYER)
1079
1080 victim->ModifyHealth(-(int32)damageTaken);
1081
1082 if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
1084
1085 if (victim->GetTypeId() != TYPEID_PLAYER)
1086 {
1087 // Part of Evade mechanics. DoT's and Thorns / Retribution Aura do not contribute to this
1088 if (damagetype != DOT && damageTaken > 0 && !victim->GetOwnerGUID().IsPlayer() && (!spellProto || !spellProto->HasAura(SPELL_AURA_DAMAGE_SHIELD)))
1090
1091 if (attacker && (!spellProto || !spellProto->HasAttribute(SPELL_ATTR4_NO_HARMFUL_THREAT)))
1092 victim->GetThreatManager().AddThreat(attacker, float(damageTaken), spellProto);
1093 }
1094 else // victim is a player
1095 {
1096 // random durability for items (HIT TAKEN)
1097 if (durabilityLoss && roll_chance(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE)))
1098 {
1101 }
1102 }
1103
1104 if (attacker && attacker->GetTypeId() == TYPEID_PLAYER)
1105 {
1106 // random durability for items (HIT DONE)
1107 if (durabilityLoss && roll_chance(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE)))
1108 {
1110 attacker->ToPlayer()->DurabilityPointLossForEquipSlot(slot);
1111 }
1112 }
1113
1114 if (damagetype != NODAMAGE && damagetype != DOT)
1115 {
1116 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))))
1117 {
1118 if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
1119 {
1120 if (spell->getState() == SPELL_STATE_PREPARING)
1121 {
1122 auto isCastInterrupted = [&]()
1123 {
1124 if (!damageTaken)
1125 return spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::ZeroDamageCancels);
1126
1127 if (victim->IsPlayer() && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancelsPlayerOnly))
1128 return true;
1129
1130 if (spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancels))
1131 return true;
1132
1133 return false;
1134 };
1135
1136 auto isCastDelayed = [&]()
1137 {
1138 if (!damageTaken)
1139 return false;
1140
1141 if (victim->IsPlayer() && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamagePushbackPlayerOnly))
1142 return true;
1143
1144 if (spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamagePushback))
1145 return true;
1146
1147 return false;
1148 };
1149
1150 if (isCastInterrupted())
1151 victim->InterruptSpell(CURRENT_GENERIC_SPELL, false, false);
1152 else if (isCastDelayed())
1153 spell->Delayed();
1154 }
1155 }
1156
1157 if (damageTaken && victim->IsPlayer())
1158 if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL])
1159 if (spell->getState() == SPELL_STATE_CHANNELING && spell->m_spellInfo->HasChannelInterruptFlag(SpellAuraInterruptFlags::DamageChannelDuration))
1160 spell->DelayedChannel();
1161 }
1162 }
1163
1164 // last damage from duel opponent
1165 if (duel_hasEnded)
1166 {
1167 Player* he = duel_wasMounted ? victim->GetCharmer()->ToPlayer() : victim->ToPlayer();
1168
1169 ASSERT_NODEBUGINFO(he && he->duel);
1170
1171 if (duel_wasMounted) // In this case victim == mount
1172 victim->SetHealth(1);
1173 else
1174 he->SetHealth(1);
1175
1176 he->duel->Opponent->CombatStopWithPets(true);
1177 he->CombatStopWithPets(true);
1178
1179 he->CastSpell(he, 7267, true); // beg
1181 }
1182 }
1183
1184 // make player victims stand up automatically
1185 if (victim->GetStandState() && victim->IsPlayer() && damagetype != NODAMAGE && damagetype != DOT)
1187
1188 return damageTaken;
1189}
1190
1191void Unit::CastStop(uint32 except_spellid)
1192{
1194 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id != except_spellid)
1196}
1197
1198void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit /*= false*/, bool blocked /*= false*/, Spell* spell /*= nullptr*/)
1199{
1200 if (damage < 0)
1201 return;
1202
1203 Unit* victim = damageInfo->target;
1204 if (!victim || !victim->IsAlive())
1205 return;
1206
1207 SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
1208
1209 // Spells with SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS ignore resilience because their damage is based off another spell's damage.
1211 {
1212 if (Unit::IsDamageReducedByArmor(damageSchoolMask, spellInfo))
1213 damage = Unit::CalcArmorReducedDamage(damageInfo->attacker, victim, damage, spellInfo, attackType);
1214
1215 // Per-school calc
1216 switch (spellInfo->DmgClass)
1217 {
1218 // Melee and Ranged Spells
1221 {
1222 if (crit)
1223 {
1224 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1225
1226 // Calculate crit bonus
1227 uint32 crit_bonus = damage;
1228 // Apply crit_damage bonus for melee spells
1229 if (Player* modOwner = GetSpellModOwner())
1230 modOwner->ApplySpellMod(spellInfo, SpellModOp::CritDamageAndHealing, crit_bonus);
1231 damage += crit_bonus;
1232
1233 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
1234 float critPctDamageMod = (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellInfo->GetSchoolMask()) - 1.0f) * 100;
1235
1236 if (critPctDamageMod != 0)
1237 AddPct(damage, critPctDamageMod);
1238 }
1239
1240 // Spell weapon based damage CAN BE crit & blocked at same time
1241 if (blocked)
1242 {
1243 // double blocked amount if block is critical
1244 uint32 value = victim->GetBlockPercent(GetLevel());
1245 if (victim->IsBlockCritical())
1246 {
1247 value *= 2; // double blocked percent
1249 }
1250
1251 damageInfo->blocked = CalculatePct(damage, value);
1252 if (damage <= int32(damageInfo->blocked))
1253 {
1254 damageInfo->blocked = uint32(damage);
1255 damageInfo->fullBlock = true;
1256 }
1257 damage -= damageInfo->blocked;
1258 }
1259
1260 if (CanApplyResilience())
1261 Unit::ApplyResilience(victim, &damage);
1262 break;
1263 }
1264 // Magical Attacks
1267 {
1268 // If crit add critical bonus
1269 if (crit)
1270 {
1271 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1272 damage = Unit::SpellCriticalDamageBonus(this, spellInfo, damage, victim);
1273 }
1274
1275 if (CanApplyResilience())
1276 Unit::ApplyResilience(victim, &damage);
1277 break;
1278
1279 }
1280 default:
1281 break;
1282 }
1283 }
1284
1285 // Script Hook For CalculateSpellDamageTaken -- Allow scripts to change the Damage post class mitigation calculations
1286 sScriptMgr->ModifySpellDamageTaken(damageInfo->target, damageInfo->attacker, damage, spellInfo);
1287
1288 // Calculate absorb resist
1289 if (damage < 0)
1290 damage = 0;
1291
1292 damageInfo->damage = damage;
1293 damageInfo->originalDamage = damage;
1295 Unit::CalcAbsorbResist(dmgInfo, spell);
1296 damageInfo->absorb = dmgInfo.GetAbsorb();
1297 damageInfo->resist = dmgInfo.GetResist();
1298
1299 if (damageInfo->absorb)
1300 damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
1301
1302 if (damageInfo->resist)
1303 damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
1304
1305 damageInfo->damage = dmgInfo.GetDamage();
1306}
1307
1308void Unit::DealSpellDamage(SpellNonMeleeDamage const* damageInfo, bool durabilityLoss)
1309{
1310 if (!damageInfo)
1311 return;
1312
1313 Unit* victim = damageInfo->target;
1314 if (!victim)
1315 return;
1316
1317 if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
1318 return;
1319
1320 if (!damageInfo->Spell)
1321 {
1322 TC_LOG_DEBUG("entities.unit", "Unit::DealSpellDamage has no spell");
1323 return;
1324 }
1325
1326 // Call default DealDamage
1327 CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
1328 Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), damageInfo->Spell, durabilityLoss);
1329}
1330
1332void Unit::CalculateMeleeDamage(Unit* victim, CalcDamageInfo* damageInfo, WeaponAttackType attackType /*= BASE_ATTACK*/)
1333{
1334 damageInfo->Attacker = this;
1335 damageInfo->Target = victim;
1336
1337 damageInfo->DamageSchoolMask = GetMeleeDamageSchoolMask(attackType);
1338 damageInfo->Damage = 0;
1339 damageInfo->OriginalDamage = 0;
1340 damageInfo->Absorb = 0;
1341 damageInfo->Resist = 0;
1342
1343 damageInfo->Blocked = 0;
1344 damageInfo->HitInfo = 0;
1345 damageInfo->TargetState = 0;
1346 damageInfo->RageGained = 0;
1347
1348 damageInfo->AttackType = attackType;
1349 damageInfo->ProcAttacker = PROC_FLAG_NONE;
1350 damageInfo->ProcVictim = PROC_FLAG_NONE;
1351 damageInfo->CleanDamage = 0;
1352 damageInfo->HitOutCome = MELEE_HIT_EVADE;
1353
1354 if (!victim)
1355 return;
1356
1357 if (!IsAlive() || !victim->IsAlive())
1358 return;
1359
1360 // Select HitInfo/procAttacker/procVictim flag based on attack type
1361 switch (attackType)
1362 {
1363 case BASE_ATTACK:
1366 break;
1367 case OFF_ATTACK:
1370 damageInfo->HitInfo = HITINFO_OFFHAND;
1371 break;
1372 default:
1373 return;
1374 }
1375
1376 // Physical Immune check
1377 if (damageInfo->Target->IsImmunedToDamage(SpellSchoolMask(damageInfo->DamageSchoolMask)))
1378 {
1379 damageInfo->HitInfo |= HITINFO_NORMALSWING;
1380 damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
1381
1382 damageInfo->Damage = 0;
1383 damageInfo->CleanDamage = 0;
1384 return;
1385 }
1386
1387 uint32 damage = 0;
1388 damage += CalculateDamage(damageInfo->AttackType, false, true);
1389 // Add melee damage bonus
1390 damage = MeleeDamageBonusDone(damageInfo->Target, damage, damageInfo->AttackType, DIRECT_DAMAGE, nullptr, nullptr, MECHANIC_NONE, SpellSchoolMask(damageInfo->DamageSchoolMask));
1391 damage = damageInfo->Target->MeleeDamageBonusTaken(this, damage, damageInfo->AttackType, DIRECT_DAMAGE, nullptr, SpellSchoolMask(damageInfo->DamageSchoolMask));
1392
1393 // Script Hook For CalculateMeleeDamage -- Allow scripts to change the Damage pre class mitigation calculations
1394 sScriptMgr->ModifyMeleeDamage(damageInfo->Target, damageInfo->Attacker, damage);
1395
1396 // Calculate armor reduction
1398 {
1399 damageInfo->Damage = Unit::CalcArmorReducedDamage(damageInfo->Attacker, damageInfo->Target, damage, nullptr, damageInfo->AttackType);
1400 damageInfo->CleanDamage += damage - damageInfo->Damage;
1401 }
1402 else
1403 damageInfo->Damage = damage;
1404
1405 damageInfo->HitOutCome = RollMeleeOutcomeAgainst(damageInfo->Target, damageInfo->AttackType);
1406
1407 switch (damageInfo->HitOutCome)
1408 {
1409 case MELEE_HIT_EVADE:
1411 damageInfo->TargetState = VICTIMSTATE_EVADES;
1412 damageInfo->OriginalDamage = damageInfo->Damage;
1413
1414 damageInfo->Damage = 0;
1415 damageInfo->CleanDamage = 0;
1416 return;
1417 case MELEE_HIT_MISS:
1418 damageInfo->HitInfo |= HITINFO_MISS;
1419 damageInfo->TargetState = VICTIMSTATE_INTACT;
1420 damageInfo->OriginalDamage = damageInfo->Damage;
1421
1422 damageInfo->Damage = 0;
1423 damageInfo->CleanDamage = 0;
1424 break;
1425 case MELEE_HIT_NORMAL:
1426 damageInfo->TargetState = VICTIMSTATE_HIT;
1427 damageInfo->OriginalDamage = damageInfo->Damage;
1428 break;
1429 case MELEE_HIT_CRIT:
1430 {
1431 damageInfo->HitInfo |= HITINFO_CRITICALHIT;
1432 damageInfo->TargetState = VICTIMSTATE_HIT;
1433
1434 // Crit bonus calc
1435 damageInfo->Damage *= 2;
1436
1437 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
1439
1440 if (mod != 0)
1441 AddPct(damageInfo->Damage, mod);
1442
1443 damageInfo->OriginalDamage = damageInfo->Damage;
1444 break;
1445 }
1446 case MELEE_HIT_PARRY:
1447 damageInfo->TargetState = VICTIMSTATE_PARRY;
1448 damageInfo->CleanDamage += damageInfo->Damage;
1449
1450 damageInfo->OriginalDamage = damageInfo->Damage;
1451 damageInfo->Damage = 0;
1452 break;
1453 case MELEE_HIT_DODGE:
1454 damageInfo->TargetState = VICTIMSTATE_DODGE;
1455 damageInfo->CleanDamage += damageInfo->Damage;
1456
1457 damageInfo->OriginalDamage = damageInfo->Damage;
1458 damageInfo->Damage = 0;
1459 break;
1460 case MELEE_HIT_BLOCK:
1461 damageInfo->TargetState = VICTIMSTATE_HIT;
1462 damageInfo->HitInfo |= HITINFO_BLOCK;
1463 // 30% damage blocked, double blocked amount if block is critical
1464 damageInfo->Blocked = CalculatePct(damageInfo->Damage, damageInfo->Target->GetBlockPercent(GetLevel()));
1465 if (damageInfo->Target->IsBlockCritical())
1466 {
1467 damageInfo->Blocked *= 2;
1469 }
1470
1471 damageInfo->OriginalDamage = damageInfo->Damage;
1472 damageInfo->Damage -= damageInfo->Blocked;
1473 damageInfo->CleanDamage += damageInfo->Blocked;
1474 break;
1475 case MELEE_HIT_GLANCING:
1476 {
1477 damageInfo->HitInfo |= HITINFO_GLANCING;
1478 damageInfo->TargetState = VICTIMSTATE_HIT;
1479 int32 leveldif = int32(victim->GetLevel()) - int32(GetLevel());
1480 if (leveldif > 3)
1481 leveldif = 3;
1482
1483 damageInfo->OriginalDamage = damageInfo->Damage;
1484 float reducePercent = 1.f - leveldif * 0.1f;
1485 damageInfo->CleanDamage += damageInfo->Damage - uint32(reducePercent * damageInfo->Damage);
1486 damageInfo->Damage = uint32(reducePercent * damageInfo->Damage);
1487 break;
1488 }
1489 case MELEE_HIT_CRUSHING:
1490 damageInfo->HitInfo |= HITINFO_CRUSHING;
1491 damageInfo->TargetState = VICTIMSTATE_HIT;
1492 // 150% normal damage
1493 damageInfo->Damage += (damageInfo->Damage / 2);
1494 damageInfo->OriginalDamage = damageInfo->Damage;
1495 break;
1496 default:
1497 break;
1498 }
1499
1500 // Always apply HITINFO_AFFECTS_VICTIM in case its not a miss
1501 if (!(damageInfo->HitInfo & HITINFO_MISS))
1502 damageInfo->HitInfo |= HITINFO_AFFECTS_VICTIM;
1503
1504 int32 resilienceReduction = damageInfo->Damage;
1505 if (CanApplyResilience())
1506 Unit::ApplyResilience(victim, &resilienceReduction);
1507 resilienceReduction = damageInfo->Damage - resilienceReduction;
1508 damageInfo->Damage -= resilienceReduction;
1509 damageInfo->CleanDamage += resilienceReduction;
1510 damageInfo->OriginalDamage -= resilienceReduction;
1511
1512 // Calculate absorb resist
1513 if (int32(damageInfo->Damage) > 0)
1514 {
1516 // Calculate absorb & resists
1517 DamageInfo dmgInfo(*damageInfo);
1518 Unit::CalcAbsorbResist(dmgInfo);
1519 damageInfo->Absorb = dmgInfo.GetAbsorb();
1520 damageInfo->Resist = dmgInfo.GetResist();
1521
1522 if (damageInfo->Absorb)
1523 damageInfo->HitInfo |= (damageInfo->Damage - damageInfo->Absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
1524
1525 if (damageInfo->Resist)
1526 damageInfo->HitInfo |= (damageInfo->Damage - damageInfo->Resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
1527
1528 damageInfo->Damage = dmgInfo.GetDamage();
1529 }
1530 else // Impossible get negative result but....
1531 damageInfo->Damage = 0;
1532}
1533
1534void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
1535{
1536 Unit* victim = damageInfo->Target;
1537
1538 if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
1539 return;
1540
1541 if (damageInfo->TargetState == VICTIMSTATE_PARRY &&
1543 {
1544 // Get attack timers
1545 float offtime = float(victim->getAttackTimer(OFF_ATTACK));
1546 float basetime = float(victim->getAttackTimer(BASE_ATTACK));
1547 // Reduce attack time
1548 if (victim->haveOffhandWeapon() && offtime < basetime)
1549 {
1550 float percent20 = victim->GetBaseAttackTime(OFF_ATTACK) * 0.20f;
1551 float percent60 = 3.0f * percent20;
1552 if (offtime > percent20 && offtime <= percent60)
1553 victim->setAttackTimer(OFF_ATTACK, uint32(percent20));
1554 else if (offtime > percent60)
1555 {
1556 offtime -= 2.0f * percent20;
1557 victim->setAttackTimer(OFF_ATTACK, uint32(offtime));
1558 }
1559 }
1560 else
1561 {
1562 float percent20 = victim->GetBaseAttackTime(BASE_ATTACK) * 0.20f;
1563 float percent60 = 3.0f * percent20;
1564 if (basetime > percent20 && basetime <= percent60)
1565 victim->setAttackTimer(BASE_ATTACK, uint32(percent20));
1566 else if (basetime > percent60)
1567 {
1568 basetime -= 2.0f * percent20;
1569 victim->setAttackTimer(BASE_ATTACK, uint32(basetime));
1570 }
1571 }
1572 }
1573
1574 // Call default DealDamage
1575 CleanDamage cleanDamage(damageInfo->CleanDamage, damageInfo->Absorb, damageInfo->AttackType, damageInfo->HitOutCome);
1576 Unit::DealDamage(this, victim, damageInfo->Damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->DamageSchoolMask), nullptr, durabilityLoss);
1577
1578 // If this is a creature and it attacks from behind it has a probability to daze it's victim
1579 if ((damageInfo->HitOutCome == MELEE_HIT_CRIT || damageInfo->HitOutCome == MELEE_HIT_CRUSHING || damageInfo->HitOutCome == MELEE_HIT_NORMAL || damageInfo->HitOutCome == MELEE_HIT_GLANCING) &&
1580 GetTypeId() != TYPEID_PLAYER && !ToCreature()->IsControlledByPlayer() && !victim->HasInArc(float(M_PI), this)
1581 && (victim->GetTypeId() == TYPEID_PLAYER || !victim->ToCreature()->isWorldBoss())&& !victim->IsVehicle())
1582 {
1583 // 20% base chance
1584 float chance = 20.0f;
1585
1586 // there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1587 if (victim->GetLevel() < 30)
1588 chance = 0.65f * victim->GetLevelForTarget(this) + 0.5f;
1589
1590 uint32 const victimDefense = victim->GetMaxSkillValueForLevel(this);
1591 uint32 const attackerMeleeSkill = GetMaxSkillValueForLevel();
1592
1593 chance *= attackerMeleeSkill / float(victimDefense) * 0.16f;
1594
1595 // -probability is between 0% and 40%
1596 RoundToInterval(chance, 0.0f, 40.0f);
1597 if (roll_chance(chance))
1598 CastSpell(victim, SPELL_DAZED, true);
1599 }
1600
1601 if (GetTypeId() == TYPEID_PLAYER)
1602 {
1603 DamageInfo dmgInfo(*damageInfo);
1604 ToPlayer()->CastItemCombatSpell(dmgInfo);
1605 }
1606
1607 // Do effect if any damage done to target
1608 if (damageInfo->Damage)
1609 {
1610 // We're going to call functions which can modify content of the list during iteration over it's elements
1611 // Let's copy the list so we can prevent iterator invalidation
1613 for (AuraEffect const* aurEff : vDamageShieldsCopy)
1614 {
1615 SpellInfo const* spellInfo = aurEff->GetSpellInfo();
1616
1617 // Damage shield can be resisted...
1618 SpellMissInfo missInfo = victim->SpellHitResult(this, spellInfo, false, true);
1619 if (missInfo != SPELL_MISS_NONE)
1620 {
1621 victim->SendSpellMiss(this, spellInfo->Id, missInfo);
1622 continue;
1623 }
1624
1625 // ...or immuned
1626 if (IsImmunedToDamage(this, spellInfo))
1627 {
1628 victim->SendSpellDamageImmune(this, spellInfo->Id, false);
1629 continue;
1630 }
1631
1632 uint32 damage = aurEff->GetAmountAsInt();
1633 if (Unit* caster = aurEff->GetCaster())
1634 {
1635 damage = caster->SpellDamageBonusDone(this, spellInfo, damage, SPELL_DIRECT_DAMAGE, aurEff->GetSpellEffectInfo());
1636 damage = SpellDamageBonusTaken(caster, spellInfo, damage, SPELL_DIRECT_DAMAGE);
1637 }
1638
1639 DamageInfo damageInfo(this, victim, damage, spellInfo, spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK);
1640 victim->CalcAbsorbResist(damageInfo);
1641 damage = damageInfo.GetDamage();
1642 Unit::DealDamageMods(victim, this, damage, nullptr);
1643
1645 damageShield.Attacker = victim->GetGUID();
1646 damageShield.Defender = GetGUID();
1647 damageShield.SpellID = spellInfo->Id;
1648 damageShield.TotalDamage = damage;
1649 damageShield.OriginalDamage = damageInfo.GetOriginalDamage();
1650 damageShield.OverKill = std::max(int32(damage) - int32(GetHealth()), 0);
1651 damageShield.SchoolMask = spellInfo->SchoolMask;
1652 damageShield.LogAbsorbed = damageInfo.GetAbsorb();
1653
1654 Unit::DealDamage(victim, this, damage, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true);
1655
1656 damageShield.LogData.Initialize(this);
1657 victim->SendCombatLogMessage(&damageShield);
1658 }
1659 }
1660}
1661
1662void Unit::HandleEmoteCommand(Emote emoteId, Player* target /*=nullptr*/, Trinity::IteratorPair<int32 const*> spellVisualKitIds /*= {}*/, int32 sequenceVariation /*= 0*/)
1663{
1665 packet.Guid = GetGUID();
1666 packet.EmoteID = emoteId;
1667
1668 if (EmotesEntry const* emotesEntry = sEmotesStore.LookupEntry(emoteId))
1669 if (emotesEntry->AnimID == ANIM_MOUNT_SPECIAL || emotesEntry->AnimID == ANIM_MOUNT_SELF_SPECIAL)
1670 std::copy(spellVisualKitIds.begin(), spellVisualKitIds.end(), std::back_inserter(packet.SpellVisualKitIDs));
1671
1672 packet.SequenceVariation = sequenceVariation;
1673
1674 if (target)
1675 target->SendDirectMessage(packet.Write());
1676 else
1677 SendMessageToSet(packet.Write(), true);
1678}
1679
1680/*static*/ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* spellInfo /*= nullptr*/)
1681{
1682 // only physical spells damage gets reduced by armor
1683 if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
1684 return false;
1685
1686 return !spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_ARMOR);
1687}
1688
1689/*static*/ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType /*= MAX_ATTACK*/, uint8 attackerLevel /*= 0*/)
1690{
1691 float armor = float(victim->GetArmor());
1692
1693 if (attacker)
1694 {
1695 armor *= victim->GetArmorMultiplierForTarget(attacker);
1696
1697 // bypass enemy armor by SPELL_AURA_BYPASS_ARMOR_FOR_CASTER
1698 SpellEffectValue armorBypassPct = 0;
1700 for (AuraEffectList::const_iterator i = reductionAuras.begin(); i != reductionAuras.end(); ++i)
1701 if ((*i)->GetCasterGUID() == attacker->GetGUID())
1702 armorBypassPct += (*i)->GetAmount();
1703 armor = CalculatePct(armor, 100 - std::min(armorBypassPct, 100.0));
1704
1705 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1707
1708 if (spellInfo)
1709 if (Player* modOwner = attacker->GetSpellModOwner())
1710 modOwner->ApplySpellMod(spellInfo, SpellModOp::TargetResistance, armor);
1711
1713 for (AuraEffect const* aurEff : resIgnoreAuras)
1714 {
1715 if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL && aurEff->IsAffectingSpell(spellInfo))
1716 armor = std::floor(AddPct(armor, -aurEff->GetAmount()));
1717 }
1718
1719 // Apply Player CR_ARMOR_PENETRATION rating and buffs from stances\specializations etc.
1720 if (attacker->GetTypeId() == TYPEID_PLAYER)
1721 {
1722 float arpPct = attacker->ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION);
1723
1724 Item const* weapon = attacker->ToPlayer()->GetWeaponForAttack(attackType, true);
1725 arpPct += attacker->GetTotalAuraModifier(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT, [weapon](AuraEffect const* aurEff) -> bool
1726 {
1727 return aurEff->GetSpellInfo()->IsItemFitToSpellRequirements(weapon);
1728 });
1729
1730 // no more than 100%
1731 RoundToInterval(arpPct, 0.f, 100.f);
1732
1733 float maxArmorPen = 0.f;
1734 if (victim->GetLevelForTarget(attacker) < 60)
1735 maxArmorPen = float(400 + 85 * victim->GetLevelForTarget(attacker));
1736 else
1737 maxArmorPen = 400 + 85 * victim->GetLevelForTarget(attacker) + 4.5f * 85 * (victim->GetLevelForTarget(attacker) - 59);
1738
1739 // Cap armor penetration to this number
1740 maxArmorPen = std::min((armor + maxArmorPen) / 3.f, armor);
1741 // Figure out how much armor do we ignore
1742 armor -= CalculatePct(maxArmorPen, arpPct);
1743 }
1744 }
1745
1746 if (G3D::fuzzyLe(armor, 0.0f))
1747 return damage;
1748
1749 Classes attackerClass = CLASS_NONE;
1750 Optional<float> attackerItemLevel;
1751 if (attacker)
1752 {
1753 attackerLevel = attacker->GetLevelForTarget(victim);
1754 if (Player const* ownerPlayer = attacker->GetCharmerOrOwnerPlayerOrPlayerItself())
1755 attackerItemLevel = ownerPlayer->m_playerData->AvgItemLevel[AsUnderlyingType(AvgItemLevelCategory::EquippedBase)];
1756 else
1757 attackerClass = Classes(attacker->GetClass());
1758 }
1759
1760 // Expansion and ContentTuningID necessary? Does Player get a ContentTuningID too ?
1761 float armorConstant = sDB2Manager.EvaluateExpectedStat(ExpectedStatType::ArmorConstant, attackerLevel, -2, 0, attackerClass, 0);
1762 if (attackerItemLevel)
1763 {
1764 uint32 maxLevelForExpansion = GetMaxLevelForExpansion(sWorld->getIntConfig(CONFIG_EXPANSION));
1765 if (attackerLevel == maxLevelForExpansion)
1766 {
1767 float itemLevelDelta = *attackerItemLevel - ASSERT_NOTNULL(sItemLevelByLevelTable.GetRow(maxLevelForExpansion))->ItemLevel;
1768 if (uint32 curveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::ArmorItemLevelDiminishing))
1769 armorConstant *= sDB2Manager.GetCurveValueAt(curveId, itemLevelDelta);
1770 }
1771 }
1772
1773 if (!(armor + armorConstant))
1774 return damage;
1775
1776 float mitigation = std::min(armor / (armor + armorConstant), 0.85f);
1777 return uint32(std::max(damage * (1.0f - mitigation), 0.0f));
1778}
1779
1780/*static*/ uint32 Unit::CalcSpellResistedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo)
1781{
1782 // Magic damage, check for resists
1783 if (!(schoolMask & SPELL_SCHOOL_MASK_MAGIC))
1784 return 0;
1785
1786 // Npcs can have holy resistance
1787 if ((schoolMask & SPELL_SCHOOL_MASK_HOLY) && victim->GetTypeId() != TYPEID_UNIT)
1788 return 0;
1789
1790 float const averageResist = Unit::CalculateAverageResistReduction(attacker, schoolMask, victim, spellInfo);
1791 float discreteResistProbability[11] = { };
1792 if (averageResist <= 0.1f)
1793 {
1794 discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
1795 discreteResistProbability[1] = 5.0f * averageResist;
1796 discreteResistProbability[2] = 2.5f * averageResist;
1797 }
1798 else
1799 {
1800 for (uint32 i = 0; i < 11; ++i)
1801 discreteResistProbability[i] = std::max(0.5f - 2.5f * std::fabs(0.1f * i - averageResist), 0.0f);
1802 }
1803
1804 float roll = rand_norm();
1805 float probabilitySum = 0.0f;
1806
1807 uint32 resistance = 0;
1808 for (; resistance < 11; ++resistance)
1809 if (roll < (probabilitySum += discreteResistProbability[resistance]))
1810 break;
1811
1812 float damageResisted = damage * resistance / 10.f;
1813 if (damageResisted > 0.0f) // if any damage was resisted
1814 {
1815 float ignoredResistance = 0.0f;
1816
1817 if (attacker)
1818 ignoredResistance += attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask);
1819
1820 ignoredResistance = std::min(ignoredResistance, 100.0f);
1821 ApplyPct(damageResisted, 100.0f - ignoredResistance);
1822
1823 // Spells with melee and magic school mask, decide whether resistance or armor absorb is higher
1824 if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC))
1825 {
1826 uint32 damageAfterArmor = Unit::CalcArmorReducedDamage(attacker, victim, damage, spellInfo, spellInfo->GetAttackType());
1827 float armorReduction = damage - damageAfterArmor;
1828
1829 // pick the lower one, the weakest resistance counts
1830 damageResisted = std::min(damageResisted, armorReduction);
1831 }
1832 }
1833
1834 damageResisted = std::max(damageResisted, 0.f);
1835 return uint32(damageResisted);
1836}
1837
1838/*static*/ float Unit::CalculateAverageResistReduction(WorldObject const* caster, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo /*= nullptr*/)
1839{
1840 float victimResistance = float(victim->GetResistance(schoolMask));
1841 if (caster)
1842 {
1843 // pets inherit 100% of masters penetration
1844 if (Player const* player = caster->GetSpellModOwner())
1845 {
1846 victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
1847 victimResistance -= float(player->GetSpellPenetrationItemMod());
1848 }
1849 else if (Unit const* unitCaster = caster->ToUnit())
1850 victimResistance += float(unitCaster->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
1851 }
1852
1853 // holy resistance exists in pve and comes from level difference, ignore template values
1854 if (schoolMask & SPELL_SCHOOL_MASK_HOLY)
1855 victimResistance = 0.0f;
1856
1857 // Chaos Bolt exception, ignore all target resistances (unknown attribute?)
1858 if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && spellInfo->Id == 116858)
1859 victimResistance = 0.0f;
1860
1861 victimResistance = std::max(victimResistance, 0.0f);
1862
1863 return victimResistance;
1864}
1865
1866/*static*/ void Unit::CalcAbsorbResist(DamageInfo& damageInfo, Spell* spell /*= nullptr*/)
1867{
1868 if (!damageInfo.GetVictim() || !damageInfo.GetVictim()->IsAlive() || !damageInfo.GetDamage())
1869 return;
1870
1871 uint32 resistedDamage = Unit::CalcSpellResistedDamage(damageInfo.GetAttacker(), damageInfo.GetVictim(), damageInfo.GetDamage(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo());
1872
1873 // Ignore Absorption Auras
1874 float auraAbsorbMod = 0.f;
1875 if (Unit* attacker = damageInfo.GetAttacker())
1877
1878 RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
1879
1880 int32 absorbIgnoringDamage = CalculatePct(damageInfo.GetDamage(), auraAbsorbMod);
1881
1882 if (spell)
1883 spell->CallScriptOnResistAbsorbCalculateHandlers(damageInfo, resistedDamage, absorbIgnoringDamage);
1884
1885 damageInfo.ResistDamage(resistedDamage);
1886
1887 // We're going to call functions which can modify content of the list during iteration over it's elements
1888 // Let's copy the list so we can prevent iterator invalidation
1890 std::ranges::stable_sort(vSchoolAbsorbCopy, Trinity::AbsorbAuraOrderPred());
1891
1892 // absorb without mana cost
1893 for (auto itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1894 {
1895 AuraEffect* absorbAurEff = *itr;
1896 // Check if aura was removed during iteration - we don't need to work on such auras
1897 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1898 if (!aurApp)
1899 continue;
1900 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1901 continue;
1902
1903 // get amount which can be still absorbed by the aura
1904 int32 currentAbsorb = absorbAurEff->GetAmountAsInt();
1905 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1906 if (currentAbsorb < 0)
1907 currentAbsorb = 0;
1908
1910 damageInfo.ModifyDamage(-absorbIgnoringDamage);
1911
1912 uint32 tempAbsorb = uint32(currentAbsorb);
1913
1914 bool defaultPrevented = false;
1915
1916 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
1917 currentAbsorb = tempAbsorb;
1918
1919 if (!defaultPrevented)
1920 {
1921 // absorb must be smaller than the damage itself
1922 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
1923
1924 damageInfo.AbsorbDamage(currentAbsorb);
1925
1926 tempAbsorb = currentAbsorb;
1927 absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
1928
1929 // Check if our aura is using amount to count damage
1930 if (absorbAurEff->GetAmount() >= 0)
1931 {
1932 // Reduce shield amount
1933 absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
1934 // Aura cannot absorb anything more - remove it
1935 if (absorbAurEff->GetAmount() <= 0)
1936 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
1937 }
1938 }
1939
1941 damageInfo.ModifyDamage(absorbIgnoringDamage);
1942
1943 if (currentAbsorb)
1944 {
1946 absorbLog.Attacker = damageInfo.GetAttacker() ? damageInfo.GetAttacker()->GetGUID() : ObjectGuid::Empty;
1947 absorbLog.Victim = damageInfo.GetVictim()->GetGUID();
1948 absorbLog.Caster = absorbAurEff->GetBase()->GetCasterGUID();
1949 absorbLog.AbsorbedSpellID = damageInfo.GetSpellInfo() ? damageInfo.GetSpellInfo()->Id : 0;
1950 absorbLog.AbsorbSpellID = absorbAurEff->GetId();
1951 absorbLog.Absorbed = currentAbsorb;
1952 absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
1953 absorbLog.LogData.Initialize(damageInfo.GetVictim());
1954 damageInfo.GetVictim()->SendCombatLogMessage(&absorbLog);
1955 }
1956 }
1957
1958 // absorb by mana cost
1960 for (auto itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1961 {
1962 AuraEffect* absorbAurEff = *itr;
1963 // Check if aura was removed during iteration - we don't need to work on such auras
1964 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1965 if (!aurApp)
1966 continue;
1967 // check damage school mask
1968 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1969 continue;
1970
1971 // get amount which can be still absorbed by the aura
1972 int32 currentAbsorb = absorbAurEff->GetAmountAsInt();
1973 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1974 if (currentAbsorb < 0)
1975 currentAbsorb = 0;
1976
1978 damageInfo.ModifyDamage(-absorbIgnoringDamage);
1979
1980 uint32 tempAbsorb = currentAbsorb;
1981
1982 bool defaultPrevented = false;
1983
1984 absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
1985 currentAbsorb = tempAbsorb;
1986
1987 if (!defaultPrevented)
1988 {
1989 // absorb must be smaller than the damage itself
1990 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
1991
1992 int32 manaReduction = currentAbsorb;
1993
1994 // lower absorb amount by talents
1995 if (float manaMultiplier = absorbAurEff->GetSpellEffectInfo().CalcValueMultiplier(absorbAurEff->GetCaster()))
1996 manaReduction = int32(float(manaReduction) * manaMultiplier);
1997
1998 int32 manaTaken = -damageInfo.GetVictim()->ModifyPower(POWER_MANA, -manaReduction);
1999
2000 // take case when mana has ended up into account
2001 currentAbsorb = currentAbsorb ? int32(float(currentAbsorb) * (float(manaTaken) / float(manaReduction))) : 0;
2002
2003 damageInfo.AbsorbDamage(currentAbsorb);
2004
2005 tempAbsorb = currentAbsorb;
2006 absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
2007
2008 // Check if our aura is using amount to count damage
2009 if (absorbAurEff->GetAmount() >= 0)
2010 {
2011 absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
2012 if ((absorbAurEff->GetAmount() <= 0))
2013 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
2014 }
2015 }
2016
2018 damageInfo.ModifyDamage(absorbIgnoringDamage);
2019
2020 if (currentAbsorb)
2021 {
2023 absorbLog.Attacker = damageInfo.GetAttacker() ? damageInfo.GetAttacker()->GetGUID() : ObjectGuid::Empty;
2024 absorbLog.Victim = damageInfo.GetVictim()->GetGUID();
2025 absorbLog.Caster = absorbAurEff->GetBase()->GetCasterGUID();
2026 absorbLog.AbsorbedSpellID = damageInfo.GetSpellInfo() ? damageInfo.GetSpellInfo()->Id : 0;
2027 absorbLog.AbsorbSpellID = absorbAurEff->GetId();
2028 absorbLog.Absorbed = currentAbsorb;
2029 absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
2030 absorbLog.LogData.Initialize(damageInfo.GetVictim());
2031 damageInfo.GetVictim()->SendCombatLogMessage(&absorbLog);
2032 }
2033 }
2034
2035 // split damage auras - only when not damaging self
2036 if (damageInfo.GetVictim() != damageInfo.GetAttacker())
2037 {
2038 // We're going to call functions which can modify content of the list during iteration over it's elements
2039 // Let's copy the list so we can prevent iterator invalidation
2041 for (auto itr = vSplitDamagePctCopy.begin(); itr != vSplitDamagePctCopy.end() && damageInfo.GetDamage() > 0; ++itr)
2042 {
2043 // Check if aura was removed during iteration - we don't need to work on such auras
2044 AuraApplication const* aurApp = (*itr)->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
2045 if (!aurApp)
2046 continue;
2047
2048 // check damage school mask
2049 if (!((*itr)->GetMiscValue() & damageInfo.GetSchoolMask()))
2050 continue;
2051
2052 // Damage can be splitted only if aura has an alive caster
2053 Unit* caster = (*itr)->GetCaster();
2054 if (!caster || (caster == damageInfo.GetVictim()) || !caster->IsInWorld() || !caster->IsAlive())
2055 continue;
2056
2057 uint32 splitDamage = CalculatePct(damageInfo.GetDamage(), (*itr)->GetAmount());
2058
2059 (*itr)->GetBase()->CallScriptEffectSplitHandlers((*itr), aurApp, damageInfo, splitDamage);
2060
2061 // absorb must be smaller than the damage itself
2062 splitDamage = RoundToInterval(splitDamage, uint32(0), uint32(damageInfo.GetDamage()));
2063
2064 damageInfo.AbsorbDamage(splitDamage);
2065
2066 // check if caster is immune to damage
2067 if (caster->IsImmunedToDamage(damageInfo.GetSchoolMask()))
2068 {
2069 damageInfo.GetVictim()->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
2070 continue;
2071 }
2072
2073 uint32 split_absorb = 0;
2074 Unit::DealDamageMods(damageInfo.GetAttacker(), caster, splitDamage, &split_absorb);
2075
2076 // sparring
2077 if (Creature* victimCreature = damageInfo.GetVictim()->ToCreature())
2078 {
2079 if (victimCreature->ShouldFakeDamageFrom(damageInfo.GetAttacker()))
2080 damageInfo.ModifyDamage(damageInfo.GetDamage() * -1);
2081 }
2082
2083 SpellNonMeleeDamage log(damageInfo.GetAttacker(), caster, (*itr)->GetSpellInfo(), (*itr)->GetBase()->GetSpellVisual(), damageInfo.GetSchoolMask(), (*itr)->GetBase()->GetCastId());
2084 CleanDamage cleanDamage = CleanDamage(splitDamage, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
2085 Unit::DealDamage(damageInfo.GetAttacker(), caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
2086 log.damage = splitDamage;
2087 log.originalDamage = splitDamage;
2088 log.absorb = split_absorb;
2089 log.periodicLog = damageInfo.GetDamageType() == DOT;
2091 caster->SendSpellNonMeleeDamageLog(&log);
2092
2093 // break 'Fear' and similar auras
2095 }
2096 }
2097}
2098
2099/*static*/ void Unit::CalcHealAbsorb(HealInfo& healInfo)
2100{
2101 if (!healInfo.GetHeal())
2102 return;
2103
2105 std::ranges::stable_sort(vHealAbsorb, Trinity::AbsorbAuraOrderPred());
2106 for (auto i = vHealAbsorb.begin(); i != vHealAbsorb.end() && healInfo.GetHeal() > 0; ++i)
2107 {
2108 AuraEffect* absorbAurEff = *i;
2109 // Check if aura was removed during iteration - we don't need to work on such auras
2110 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(healInfo.GetTarget()->GetGUID());
2111 if (!aurApp)
2112 continue;
2113 if (!(absorbAurEff->GetMiscValue() & healInfo.GetSchoolMask()))
2114 continue;
2115
2116 // get amount which can be still absorbed by the aura
2117 int32 currentAbsorb = absorbAurEff->GetAmountAsInt();
2118 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
2119 if (currentAbsorb < 0)
2120 currentAbsorb = 0;
2121
2122 uint32 tempAbsorb = uint32(currentAbsorb);
2123
2124 bool defaultPrevented = false;
2125
2126 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, healInfo, tempAbsorb, defaultPrevented);
2127 currentAbsorb = tempAbsorb;
2128
2129 if (!defaultPrevented)
2130 {
2131 // absorb must be smaller than the heal itself
2132 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(healInfo.GetHeal()));
2133
2134 healInfo.AbsorbHeal(currentAbsorb);
2135
2136 tempAbsorb = currentAbsorb;
2137 absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, healInfo, tempAbsorb);
2138
2139 // Check if our aura is using amount to count heal
2140 if (absorbAurEff->GetAmount() >= 0)
2141 {
2142 // Reduce shield amount
2143 absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
2144 // Aura cannot absorb anything more - remove it
2145 if (absorbAurEff->GetAmount() <= 0)
2146 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
2147 }
2148 }
2149
2150 if (currentAbsorb)
2151 {
2153 absorbLog.Healer = healInfo.GetHealer() ? healInfo.GetHealer()->GetGUID() : ObjectGuid::Empty;
2154 absorbLog.Target = healInfo.GetTarget()->GetGUID();
2155 absorbLog.AbsorbCaster = absorbAurEff->GetBase()->GetCasterGUID();
2156 absorbLog.AbsorbedSpellID = healInfo.GetSpellInfo() ? healInfo.GetSpellInfo()->Id : 0;
2157 absorbLog.AbsorbSpellID = absorbAurEff->GetId();
2158 absorbLog.Absorbed = currentAbsorb;
2159 absorbLog.OriginalHeal = healInfo.GetOriginalHeal();
2160 absorbLog.LogData.Initialize(healInfo.GetTarget());
2161 healInfo.GetTarget()->SendCombatLogMessage(&absorbLog);
2162 }
2163 }
2164}
2165
2167{
2169 return;
2170
2172 return;
2173
2174 if (IsCreature() && !ToCreature()->CanMelee())
2175 return;
2176
2178 return;
2179
2180 Unit* victim = GetVictim();
2181 if (!victim)
2182 return;
2183
2184 auto getAutoAttackError = [&]() -> Optional<AttackSwingErr>
2185 {
2186 if (!IsValidAttackTarget(victim))
2188
2189 if (!IsWithinMeleeRange(victim))
2191
2192 //120 degrees of radiant range, if player is not in boundary radius
2193 if (!IsWithinBoundaryRadius(victim) && !HasInArc(2 * float(M_PI) / 3, victim))
2195
2196 return {};
2197 };
2198
2200 {
2201 Optional<AttackSwingErr> autoAttackError = getAutoAttackError();
2202 if (!autoAttackError)
2203 {
2204 // prevent base and off attack in same time, delay attack at 0.2 sec
2205 if (haveOffhandWeapon())
2208
2209 // do attack
2212 }
2213 else
2215
2216 if (Player* attackerPlayer = ToPlayer())
2217 attackerPlayer->SetAttackSwingError(autoAttackError);
2218 }
2219
2221 {
2222 Optional<AttackSwingErr> autoAttackError = getAutoAttackError();
2223 if (!autoAttackError)
2224 {
2225 // prevent base and off attack in same time, delay attack at 0.2 sec
2228
2229 // do attack
2232 }
2233 else
2235 }
2236}
2237
2238// Calculates the normalized rage amount per weapon swing
2239static uint32 CalcMeleeAttackRageGain(Unit const* attacker, WeaponAttackType attType)
2240{
2241 if (!attacker || (attType != BASE_ATTACK && attType != OFF_ATTACK))
2242 return 0;
2243
2244 uint32 rage = uint32(attacker->GetBaseAttackTime(attType) / 1000.f * 1.75f);
2245 if (attType == OFF_ATTACK)
2246 rage /= 2;
2247
2248 return rage;
2249}
2250
2251void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra)
2252{
2254 return;
2255
2257 return;
2258
2260 return;
2261
2263 return;
2264
2265 if (!victim->IsAlive())
2266 return;
2267
2268 if ((attType == BASE_ATTACK || attType == OFF_ATTACK) && !IsWithinLOSInMap(victim))
2269 return;
2270
2271 AtTargetAttacked(victim, true);
2273
2274 if (attType != BASE_ATTACK && attType != OFF_ATTACK)
2275 return; // ignore ranged case
2276
2277 if (!extra && _lastExtraAttackSpell)
2279
2280 // melee attack spell cast at main hand attack only - no normal melee dmg dealt
2281 if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL] && !extra)
2283 else
2284 {
2285 // attack can be redirected to another target
2286 victim = GetMeleeHitRedirectTarget(victim);
2287
2289 uint32 meleeAttackSpellId = 0;
2290 if (attType == BASE_ATTACK)
2291 {
2292 if (!meleeAttackOverrides.empty())
2293 meleeAttackSpellId = meleeAttackOverrides.front()->GetSpellEffectInfo().TriggerSpell;
2294 }
2295 else
2296 {
2297 auto itr = std::find_if(meleeAttackOverrides.begin(), meleeAttackOverrides.end(), [&](AuraEffect const* aurEff)
2298 {
2299 return aurEff->GetSpellEffectInfo().MiscValue != 0;
2300 });
2301 if (itr != meleeAttackOverrides.end())
2302 meleeAttackSpellId = (*itr)->GetSpellEffectInfo().MiscValue;
2303 }
2304
2305 if (!meleeAttackSpellId)
2306 {
2307 CalcDamageInfo damageInfo;
2308 CalculateMeleeDamage(victim, &damageInfo, attType);
2309 // Send log damage message to client
2310 Unit::DealDamageMods(damageInfo.Attacker, victim, damageInfo.Damage, &damageInfo.Absorb);
2311
2312 // sparring
2313 if (Creature* victimCreature = victim->ToCreature())
2314 {
2315 if (victimCreature->ShouldFakeDamageFrom(damageInfo.Attacker))
2316 damageInfo.HitInfo |= HITINFO_FAKE_DAMAGE;
2317 }
2318
2319 // Rage reward
2320 if (this != victim && damageInfo.HitOutCome != MELEE_HIT_MISS && GetPowerType() == POWER_RAGE)
2321 {
2322 if (uint32 rageReward = CalcMeleeAttackRageGain(this, attType))
2323 {
2324 damageInfo.HitInfo |= HITINFO_RAGE_GAIN;
2325 damageInfo.RageGained = RewardRage(rageReward);
2326 }
2327 }
2328
2329 SendAttackStateUpdate(&damageInfo);
2330
2331 _lastDamagedTargetGuid = victim->GetGUID();
2332
2333 DealMeleeDamage(&damageInfo, true);
2334
2335 DamageInfo dmgInfo(damageInfo);
2336 Unit::ProcSkillsAndAuras(damageInfo.Attacker, damageInfo.Target, damageInfo.ProcAttacker, damageInfo.ProcVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr);
2337
2338 TC_LOG_DEBUG("entities.unit", "AttackerStateUpdate: {} attacked {} for {} dmg, absorbed {}, blocked {}, resisted {}.",
2339 GetGUID().ToString(), victim->GetGUID().ToString(), damageInfo.Damage, damageInfo.Absorb, damageInfo.Blocked, damageInfo.Resist);
2340 }
2341 else
2342 {
2343 CastSpell(victim, meleeAttackSpellId, true);
2344
2346 if (attType == OFF_ATTACK)
2347 hitInfo |= HITINFO_OFFHAND;
2348
2349 SendAttackStateUpdate(hitInfo, victim, 0, GetMeleeDamageSchoolMask(), 0, 0, 0, VICTIMSTATE_HIT, 0, 0);
2350 }
2351 }
2352}
2353
2355{
2356 while (count)
2357 {
2358 --count;
2359 AttackerStateUpdate(victim, BASE_ATTACK, true);
2360 }
2361}
2362
2364{
2366 if (!targetGUID)
2367 {
2368 ObjectGuid selection = GetTarget();
2369 if (!selection.IsEmpty())
2370 targetGUID = selection; // Spell was cast directly (not triggered by aura)
2371 else
2372 return;
2373 }
2374
2375 extraAttacksTargets[targetGUID] += count;
2376}
2377
2379{
2380 if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks())
2381 return MELEE_HIT_EVADE;
2382
2383 // Miss chance based on melee
2384 int32 miss_chance = int32(MeleeSpellMissChance(victim, attType, nullptr) * 100.0f);
2385
2386 // Critical hit chance
2388
2389 int32 dodge_chance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
2390 int32 block_chance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
2391 int32 parry_chance = int32(GetUnitParryChance(attType, victim) * 100.0f);
2392
2393 // melee attack table implementation
2394 // outcome priority:
2395 // 1. > 2. > 3. > 4. > 5. > 6. > 7. > 8.
2396 // MISS > DODGE > PARRY > GLANCING > BLOCK > CRIT > CRUSHING > HIT
2397
2398 int32 sum = 0, tmp = 0;
2399 int32 roll = urand(0, 9999);
2400
2401 int32 attackerLevel = GetLevelForTarget(victim);
2402 int32 victimLevel = victim->GetLevelForTarget(this);
2403
2404 // check if attack comes from behind, nobody can parry or block if attacker is behind
2405 bool canParryOrBlock = victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION);
2406
2407 // only creatures can dodge if attacker is behind
2408 bool canDodge = victim->GetTypeId() != TYPEID_PLAYER || canParryOrBlock;
2409
2410 // if victim is casting or cc'd it can't avoid attacks
2411 if (victim->IsNonMeleeSpellCast(false, false, true) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
2412 {
2413 canDodge = false;
2414 canParryOrBlock = false;
2415 }
2416
2417 // 1. MISS
2418 tmp = miss_chance;
2419 if (tmp > 0 && roll < (sum += tmp))
2420 return MELEE_HIT_MISS;
2421
2422 // always crit against a sitting target (except 0 crit chance)
2423 if (victim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !victim->IsStandState())
2424 return MELEE_HIT_CRIT;
2425
2426 // 2. DODGE
2427 if (canDodge)
2428 {
2429 tmp = dodge_chance;
2430 if (tmp > 0 // check if unit _can_ dodge
2431 && roll < (sum += tmp))
2432 return MELEE_HIT_DODGE;
2433 }
2434
2435 // 3. PARRY
2436 if (canParryOrBlock)
2437 {
2438 tmp = parry_chance;
2439 if (tmp > 0 // check if unit _can_ parry
2440 && roll < (sum += tmp))
2441 return MELEE_HIT_PARRY;
2442 }
2443
2444 // 4. GLANCING
2445 // 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)
2446 if ((GetTypeId() == TYPEID_PLAYER || IsPet()) &&
2447 victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet() &&
2448 attackerLevel + 3 < victimLevel)
2449 {
2450 // cap possible value (with bonuses > max skill)
2451 tmp = (10 + 10 * (victimLevel - attackerLevel)) * 100;
2452 if (tmp > 0 && roll < (sum += tmp))
2453 return MELEE_HIT_GLANCING;
2454 }
2455
2456 // 5. BLOCK
2457 if (canParryOrBlock)
2458 {
2459 tmp = block_chance;
2460 if (tmp > 0 // check if unit _can_ block
2461 && roll < (sum += tmp))
2462 return MELEE_HIT_BLOCK;
2463 }
2464
2465 // 6.CRIT
2466 tmp = crit_chance;
2467 if (tmp > 0 && roll < (sum += tmp))
2468 return MELEE_HIT_CRIT;
2469
2470 // 7. CRUSHING
2471 // mobs can score crushing blows if they're 4 or more levels above victim
2472 if (attackerLevel >= victimLevel + 4 &&
2473 // can be from by creature (if can) or from controlled player that considered as creature
2476 {
2477 // add 2% chance per level, min. is 15%
2478 tmp = attackerLevel - victimLevel * 1000 - 1500;
2479 if (roll < (sum += tmp))
2480 {
2481 TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRUSHING <{}, {})", sum-tmp, sum);
2482 return MELEE_HIT_CRUSHING;
2483 }
2484 }
2485
2486 // 8. HIT
2487 return MELEE_HIT_NORMAL;
2488}
2489
2490uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const
2491{
2492 float minDamage = 0.0f;
2493 float maxDamage = 0.0f;
2494
2495 if (normalized || !addTotalPct)
2496 {
2497 CalculateMinMaxDamage(attType, normalized, addTotalPct, minDamage, maxDamage);
2498 if (IsInFeralForm() && attType == BASE_ATTACK)
2499 {
2500 float minOffhandDamage = 0.0f;
2501 float maxOffhandDamage = 0.0f;
2502 CalculateMinMaxDamage(OFF_ATTACK, normalized, addTotalPct, minOffhandDamage, maxOffhandDamage);
2503 minDamage += minOffhandDamage;
2504 maxDamage += maxOffhandDamage;
2505 }
2506 }
2507 else
2508 {
2509 switch (attType)
2510 {
2511 case RANGED_ATTACK:
2512 minDamage = m_unitData->MinRangedDamage;
2513 maxDamage = m_unitData->MaxRangedDamage;
2514 break;
2515 case BASE_ATTACK:
2516 minDamage = m_unitData->MinDamage;
2517 maxDamage = m_unitData->MaxDamage;
2518 if (IsInFeralForm())
2519 {
2520 minDamage += m_unitData->MinOffHandDamage;
2521 maxDamage += m_unitData->MaxOffHandDamage;
2522 }
2523 break;
2524 case OFF_ATTACK:
2525 minDamage = m_unitData->MinOffHandDamage;
2526 maxDamage = m_unitData->MaxOffHandDamage;
2527 break;
2528 default:
2529 break;
2530 }
2531 }
2532
2533 minDamage = std::max(0.f, minDamage);
2534 maxDamage = std::max(0.f, maxDamage);
2535
2536 if (minDamage > maxDamage)
2537 std::swap(minDamage, maxDamage);
2538
2539 return urand(uint32(minDamage), uint32(maxDamage));
2540}
2541
2543{
2545 packet.Attacker = GetGUID();
2546 packet.Victim = victim->GetGUID();
2547 SendMessageToSet(packet.Write(), true);
2548}
2549
2550void Unit::SendMeleeAttackStop(Unit const* victim) const
2551{
2553 attackStop.Attacker = GetGUID();
2554 attackStop.Victim = Object::GetGUID(victim);
2555 attackStop.NowDead = !IsAlive();
2556 SendMessageToSet(attackStop.Write(), true);
2557
2558 if (victim)
2559 TC_LOG_DEBUG("entities.unit", "{} stopped attacking {}", GetGUID().ToString(), victim->GetGUID().ToString());
2560 else
2561 TC_LOG_DEBUG("entities.unit", "{} stopped attacking", GetGUID().ToString());
2562}
2563
2565{
2567 return true;
2568 return false;
2569}
2570
2571float Unit::GetMechanicResistChance(SpellInfo const* spellInfo) const
2572{
2573 if (!spellInfo)
2574 return 0;
2575
2576 float resistMech = 0;
2577 for (SpellEffectInfo const& effect : spellInfo->GetEffects())
2578 {
2579 if (!effect.IsEffect())
2580 break;
2581
2582 int32 effectMech = spellInfo->GetEffectMechanic(effect.EffectIndex);
2583 if (effectMech)
2584 {
2586 if (resistMech < temp)
2587 resistMech = temp;
2588 }
2589 }
2590
2591 return std::max(resistMech, 0.0f);
2592}
2593
2594bool Unit::CanUseAttackType(uint8 attacktype) const
2595{
2596 switch (attacktype)
2597 {
2598 case BASE_ATTACK:
2600 case OFF_ATTACK:
2602 case RANGED_ATTACK:
2604 default:
2605 return true;
2606 }
2607}
2608
2609// Melee based spells hit result calculations
2611{
2612 if (spellInfo->HasAttribute(SPELL_ATTR3_NO_AVOIDANCE))
2613 return SPELL_MISS_NONE;
2614
2615 WeaponAttackType attType = BASE_ATTACK;
2616
2617 // Check damage class instead of attack type to correctly handle judgements
2618 // - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
2619 if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2620 attType = RANGED_ATTACK;
2621
2622 uint32 roll = urand(0, 9999);
2623
2624 uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, spellInfo) * 100.0f);
2625
2626 // Roll miss
2627 uint32 tmp = missChance;
2628 if (roll < tmp)
2629 return SPELL_MISS_MISS;
2630
2631 // Chance resist mechanic
2632 int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100.0f;
2633 tmp += resist_chance;
2634 if (roll < tmp)
2635 return SPELL_MISS_RESIST;
2636
2637 // Same spells cannot be parried/dodged
2639 return SPELL_MISS_NONE;
2640
2641 bool canDodge = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_DODGE);
2642 bool canParry = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_PARRY);
2643 bool canBlock = !spellInfo->HasAttribute(SPELL_ATTR8_NO_ATTACK_BLOCK);
2644
2645 // if victim is casting or cc'd it can't avoid attacks
2646 if (victim->IsNonMeleeSpellCast(false, false, true) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
2647 {
2648 canDodge = false;
2649 canParry = false;
2650 canBlock = false;
2651 }
2652
2653 // Ranged attacks can only miss, resist and deflect and get blocked
2654 if (attType == RANGED_ATTACK)
2655 {
2656 canParry = false;
2657 canDodge = false;
2658
2659 // only if in front
2660 if (!victim->HasUnitState(UNIT_STATE_CONTROLLED) && (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)))
2661 {
2662 int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100.0f;
2663 tmp += deflect_chance;
2664 if (roll < tmp)
2665 return SPELL_MISS_DEFLECT;
2666 }
2667 }
2668
2669 // Check for attack from behind
2670 if (!victim->HasInArc(float(M_PI), this))
2671 {
2673 {
2674 // Can't dodge from behind in PvP (but its possible in PvE)
2675 if (victim->GetTypeId() == TYPEID_PLAYER)
2676 canDodge = false;
2677 // Can't parry or block
2678 canParry = false;
2679 canBlock = false;
2680 }
2681 else // Only deterrence as of 3.3.5
2682 {
2684 canParry = false;
2685 }
2686 }
2687
2688 // Ignore combat result aura
2690 for (AuraEffect const* aurEff : ignore)
2691 {
2692 if (!aurEff->IsAffectingSpell(spellInfo))
2693 continue;
2694
2695 switch (aurEff->GetMiscValue())
2696 {
2697 case MELEE_HIT_DODGE:
2698 canDodge = false;
2699 break;
2700 case MELEE_HIT_BLOCK:
2701 canBlock = false;
2702 break;
2703 case MELEE_HIT_PARRY:
2704 canParry = false;
2705 break;
2706 default:
2707 TC_LOG_DEBUG("entities.unit", "Spell {} SPELL_AURA_IGNORE_COMBAT_RESULT has unhandled state {}", aurEff->GetId(), aurEff->GetMiscValue());
2708 break;
2709 }
2710 }
2711
2712 if (canDodge)
2713 {
2714 // Roll dodge
2715 int32 dodgeChance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
2716 if (dodgeChance < 0)
2717 dodgeChance = 0;
2718
2719 if (roll < (tmp += dodgeChance))
2720 return SPELL_MISS_DODGE;
2721 }
2722
2723 if (canParry)
2724 {
2725 // Roll parry
2726 int32 parryChance = int32(GetUnitParryChance(attType, victim) * 100.0f);
2727 if (parryChance < 0)
2728 parryChance = 0;
2729
2730 tmp += parryChance;
2731 if (roll < tmp)
2732 return SPELL_MISS_PARRY;
2733 }
2734
2735 if (canBlock)
2736 {
2737 int32 blockChance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
2738 if (blockChance < 0)
2739 blockChance = 0;
2740 tmp += blockChance;
2741
2742 if (roll < tmp)
2743 return SPELL_MISS_BLOCK;
2744 }
2745
2746 return SPELL_MISS_NONE;
2747}
2748
2749float Unit::GetUnitDodgeChance(WeaponAttackType attType, Unit const* victim) const
2750{
2751 int32 const levelDiff = victim->GetLevelForTarget(this) - GetLevelForTarget(victim);
2752
2753 float chance = 0.0f;
2754 float levelBonus = 0.0f;
2755 if (Player const* playerVictim = victim->ToPlayer())
2756 chance = playerVictim->m_activePlayerData->DodgePercentage;
2757 else
2758 {
2759 if (!victim->IsTotem())
2760 {
2761 chance = 3.0f;
2763
2764 if (levelDiff > 0)
2765 levelBonus = 1.5f * levelDiff;
2766 }
2767 }
2768
2769 chance += levelBonus;
2770
2771 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2773
2774 // reduce dodge by SPELL_AURA_MOD_ENEMY_DODGE
2776
2777 // Reduce dodge chance by attacker expertise rating
2778 if (GetTypeId() == TYPEID_PLAYER)
2779 chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
2780 else
2782 return std::max(chance, 0.0f);
2783}
2784
2785float Unit::GetUnitParryChance(WeaponAttackType attType, Unit const* victim) const
2786{
2787 int32 const levelDiff = victim->GetLevelForTarget(this) - GetLevelForTarget(victim);
2788
2789 float chance = 0.0f;
2790 float levelBonus = 0.0f;
2791 if (Player const* playerVictim = victim->ToPlayer())
2792 {
2793 if (playerVictim->CanParry())
2794 {
2795 Item* tmpitem = playerVictim->GetWeaponForAttack(BASE_ATTACK, true);
2796 if (!tmpitem)
2797 tmpitem = playerVictim->GetWeaponForAttack(OFF_ATTACK, true);
2798
2799 if (tmpitem)
2800 chance = playerVictim->m_activePlayerData->ParryPercentage;
2801 }
2802 }
2803 else
2804 {
2806 {
2807 chance = 6.0f;
2809
2810 if (levelDiff > 0)
2811 levelBonus = 1.5f * levelDiff;
2812 }
2813 }
2814
2815 chance += levelBonus;
2816
2817 // Reduce parry chance by attacker expertise rating
2818 if (GetTypeId() == TYPEID_PLAYER)
2819 chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
2820 else
2822 return std::max(chance, 0.0f);
2823}
2824
2826{
2827 float miss_chance = 5.0f;
2828
2829 return miss_chance;
2830}
2831
2832float Unit::GetUnitBlockChance(WeaponAttackType /*attType*/, Unit const* victim) const
2833{
2834 int32 const levelDiff = victim->GetLevelForTarget(this) - GetLevelForTarget(victim);
2835
2836 float chance = 0.0f;
2837 float levelBonus = 0.0f;
2838 if (Player const* playerVictim = victim->ToPlayer())
2839 {
2840 if (playerVictim->CanBlock())
2841 {
2842 Item* tmpitem = playerVictim->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2843 if (tmpitem && !tmpitem->IsBroken() && tmpitem->GetTemplate()->GetInventoryType() == INVTYPE_SHIELD)
2844 chance = playerVictim->m_activePlayerData->BlockPercentage;
2845 }
2846 }
2847 else
2848 {
2850 {
2851 chance = 3.0f;
2853
2854 if (levelDiff > 0)
2855 levelBonus = 1.5f * levelDiff;
2856 }
2857 }
2858
2859 chance += levelBonus;
2860 return std::max(chance, 0.0f);
2861}
2862
2864{
2865 float chance = 0.0f;
2866 if (Player const* thisPlayer = ToPlayer())
2867 {
2868 switch (attackType)
2869 {
2870 case BASE_ATTACK:
2871 chance = thisPlayer->m_activePlayerData->CritPercentage;
2872 break;
2873 case OFF_ATTACK:
2874 chance = thisPlayer->m_activePlayerData->OffhandCritPercentage;
2875 break;
2876 case RANGED_ATTACK:
2877 chance = thisPlayer->m_activePlayerData->RangedCritPercentage;
2878 break;
2879 // Just for good manner
2880 default:
2881 chance = 0.0f;
2882 break;
2883 }
2884 }
2885 else
2886 {
2887 if (!(ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT))
2888 {
2889 chance = 5.0f;
2892 }
2893 }
2894
2895 return chance;
2896}
2897
2898float Unit::GetUnitCriticalChanceTaken(Unit const* attacker, WeaponAttackType attackType, float critDone) const
2899{
2900 float chance = critDone;
2901
2902 // flat aura mods
2903 if (attackType != RANGED_ATTACK)
2905
2907 {
2908 return !HealthBelowPct(aurEff->GetMiscValueB());
2909 });
2910
2911 chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [attacker](AuraEffect const* aurEff) -> bool
2912 {
2913 return aurEff->GetCasterGUID() == attacker->GetGUID();
2914 });
2915
2916 if (TempSummon const* tempSummon = attacker->ToTempSummon())
2917 {
2918 chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_PET, [tempSummon](AuraEffect const* aurEff) -> bool
2919 {
2920 return aurEff->GetCasterGUID() == tempSummon->GetSummonerGUID();
2921 });
2922 }
2923
2925
2926 return std::max(chance, 0.0f);
2927}
2928
2929float Unit::GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const* victim) const
2930{
2931 float chance = GetUnitCriticalChanceDone(attackType);
2932 return victim->GetUnitCriticalChanceTaken(this, attackType, chance);
2933}
2934
2936{
2937 while (!m_removedAuras.empty())
2938 {
2939 delete m_removedAuras.front();
2940 m_removedAuras.pop_front();
2941 }
2942
2944}
2945
2947{
2948 if (!_spellHistory->IsPaused())
2949 _spellHistory->Update();
2950
2953
2954 // remove finished spells from current pointers
2955 for (Spell*& spell : m_currentSpells)
2956 {
2957 if (spell && spell->getState() == SPELL_STATE_FINISHED)
2958 {
2959 spell->SetReferencedFromCurrent(false);
2960 spell = nullptr; // remove pointer
2961 }
2962 }
2963
2964 // m_auraUpdateIterator can be updated in indirect called code at aura remove to skip next planned to update but removed auras
2966 {
2967 Aura* i_aura = m_auraUpdateIterator->second;
2968 ++m_auraUpdateIterator; // need shift to next for allow update if need into aura update
2969 i_aura->UpdateOwner(time, this);
2970 }
2971
2972 // remove expired auras - do that after updates(used in scripts?)
2973 for (AuraMap::iterator i = m_ownedAuras.begin(); i != m_ownedAuras.end();)
2974 {
2975 if (i->second->IsExpired())
2977 else if (i->second->GetSpellInfo()->IsChanneled() && i->second->GetCasterGUID() != GetGUID() && !ObjectAccessor::GetWorldObject(*this, i->second->GetCasterGUID()))
2978 RemoveOwnedAura(i, AURA_REMOVE_BY_CANCEL); // remove channeled auras when caster is not on the same map
2979 else
2980 ++i;
2981 }
2982
2983 for (AuraApplication* visibleAura : m_visibleAurasToUpdate)
2984 visibleAura->ClientUpdate();
2985
2986 m_visibleAurasToUpdate.clear();
2987
2989
2990 if (!m_gameObj.empty())
2991 {
2992 GameObjectList::iterator itr;
2993 for (itr = m_gameObj.begin(); itr != m_gameObj.end();)
2994 {
2995 if (!(*itr)->isSpawned())
2996 {
2997 (*itr)->SetOwnerGUID(ObjectGuid::Empty);
2998 (*itr)->SetRespawnTime(0);
2999 (*itr)->Delete();
3000 m_gameObj.erase(itr++);
3001 }
3002 else
3003 ++itr;
3004 }
3005 }
3006}
3007
3009{
3010 SpellInfo const* autoRepeatSpellInfo = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo;
3011
3013 return;
3014
3015 // check "realtime" interrupts
3016 // don't cancel spells which are affected by a SPELL_AURA_CAST_WHILE_WALKING effect
3017 if ((isMoving() && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckMovement() != SPELL_CAST_OK) || IsNonMeleeSpellCast(false, false, true, autoRepeatSpellInfo->IsAutoShot()))
3018 {
3019 // cancel wand shoot
3020 if (!autoRepeatSpellInfo->IsAutoShot())
3022 return;
3023 }
3024
3025 // castroutine
3027 {
3028 // Check if able to cast
3029 SpellCastResult result = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true);
3030 if (result != SPELL_CAST_OK)
3031 {
3032 if (!autoRepeatSpellInfo->IsAutoShot())
3034 else if (GetTypeId() == TYPEID_PLAYER)
3035 Spell::SendCastResult(ToPlayer(), autoRepeatSpellInfo, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_SpellVisual, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_castId, result);
3036
3037 return;
3038 }
3039
3040 // we want to shoot
3041 Spell* spell = new Spell(this, autoRepeatSpellInfo, TRIGGERED_IGNORE_GCD);
3043 }
3044}
3045
3050
3055
3057{
3058 int32 index = m_unitData->ChannelObjects.FindIndex(guid);
3059 if (index >= 0)
3061}
3062
3067
3069{
3070 ASSERT(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
3071
3072 CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer();
3073
3074 if (pSpell == m_currentSpells[CSpellType]) // avoid breaking self
3075 return;
3076
3077 // special breakage effects:
3078 switch (CSpellType)
3079 {
3081 {
3083
3084 // generic spells always break channeled not delayed spells
3089
3090 // autorepeat breaking
3092 {
3093 // break autorepeat if not Auto Shot
3094 if (!m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->IsAutoShot())
3096 }
3097 if (pSpell->GetCastTime() > 0)
3099
3100 break;
3101 }
3103 {
3104 // channel spells always break other channeled spells
3106
3108 {
3109 // channel spells break generic non-delayed
3113
3114 // it also does break autorepeat if not Auto Shot
3116 !m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->IsAutoShot())
3118
3120 }
3121
3122 break;
3123 }
3125 {
3126 if (m_currentSpells[CSpellType] && m_currentSpells[CSpellType]->getState() == SPELL_STATE_IDLE)
3127 m_currentSpells[CSpellType]->setState(SPELL_STATE_FINISHED);
3128
3129 // only Auto Shoot does not break anything
3130 if (!pSpell->GetSpellInfo()->IsAutoShot())
3131 {
3132 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3134
3139 }
3140
3141 break;
3142 }
3143 default:
3144 break; // other spell types don't break anything now
3145 }
3146
3147 // current spell (if it is still here) may be safely deleted now
3148 if (m_currentSpells[CSpellType])
3149 m_currentSpells[CSpellType]->SetReferencedFromCurrent(false);
3150
3151 // set new current spell
3152 m_currentSpells[CSpellType] = pSpell;
3153 pSpell->SetReferencedFromCurrent(true);
3154
3155 pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]);
3156}
3157
3158void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool withInstant,
3159 SpellCastResult result, Optional<SpellCastResult> resultOther /*= {}*/, ObjectGuid const& interrupter /*= ObjectGuid::Empty*/)
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(result, resultOther, interrupter);
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
3202{
3204 {
3205 if (!spell->IsInterruptable() || spell->getState() == SPELL_STATE_LAUNCHED || spell->getState() == SPELL_STATE_IDLE)
3206 {
3208 spell->SetReferencedFromCurrent(false);
3209 }
3210 else
3211 spell->cancel(SPELL_FAILED_INTERRUPTED);
3212
3213 // send autorepeat cancel message for autorepeat spells
3214 if (Player* player = ToPlayer())
3215 player->SendAutoRepeatCancel(this);
3216 }
3217}
3218
3219bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled /*= false*/, bool skipAutorepeat /*= false*/, bool isAutoshoot /*= false*/,
3220 bool skipInstant /*= true*/, bool skipChanneledAllowingActions /*= false*/) const
3221{
3222 // We don't do loop here to explicitly show that melee spell is excluded.
3223 // Maybe later some special spells will be excluded too.
3224
3225 // generic spells are cast when they are not finished and not delayed
3228 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_LAUNCHED))
3229 {
3230 if (!skipInstant || m_currentSpells[CURRENT_GENERIC_SPELL]->GetCastTime())
3231 {
3232 if (!isAutoshoot || !m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS))
3233 return true;
3234 }
3235 }
3236 // channeled spells may be delayed, but they are still considered cast
3237 if (!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
3239 {
3240 SpellInfo const* channeledSpellInfo = m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo;
3241
3243 (!skipChanneledAllowingActions || !channeledSpellInfo->HasAttribute(SPELL_ATTR5_ALLOW_ACTIONS_DURING_CHANNEL)))
3244 return true;
3245 }
3246 // autorepeat spells may be finished or delayed, but they are still considered cast
3247 if (!skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
3248 return true;
3249
3250 return false;
3251}
3252
3253void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id, bool withInstant)
3254{
3255 // generic spells are interrupted if they are not finished or delayed
3256 if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == spell_id))
3257 InterruptSpell(CURRENT_GENERIC_SPELL, withDelayed, withInstant);
3258
3259 // autorepeat spells are interrupted if they are not finished or delayed
3260 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == spell_id))
3261 InterruptSpell(CURRENT_AUTOREPEAT_SPELL, withDelayed, withInstant);
3262
3263 // channeled spells are interrupted if they are not finished, even if they are delayed
3264 if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id == spell_id))
3266}
3267
3269{
3270 for (Spell* spell : m_currentSpells)
3271 if (spell && spell->m_spellInfo->Id == spell_id)
3272 return spell;
3273 return nullptr;
3274}
3275
3277{
3278 if (Spell const* spell = FindCurrentSpellBySpellId(spell_id))
3279 return spell->GetCastTime();
3280 return 0;
3281}
3282
3284{
3286 if (!CanCastSpellWhileMoving(spell->GetSpellInfo())
3287 && spell->getState() == SPELL_STATE_PREPARING && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement))
3288 return true;
3289
3290 // channeled spells during channel stage (after the initial cast timer) allow movement without Moving channel interrupt flag
3292 if (!CanCastSpellWhileMoving(spell->GetSpellInfo())
3293 && ((spell->getState() == SPELL_STATE_PREPARING && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement))
3294 || (spell->getState() == SPELL_STATE_CHANNELING && !spell->GetSpellInfo()->IsMoveAllowedChannel())))
3295 return true;
3296
3297 return false;
3298}
3299
3300bool Unit::CanCastSpellWhileMoving(SpellInfo const* spellInfo) const
3301{
3303 return false;
3304
3306 return true;
3307
3309 return true;
3310
3311 for (uint32 label : spellInfo->Labels)
3313 return true;
3314
3315 return false;
3316}
3317
3318bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
3319{
3320 return IsWithinDistInMap(target, distance) && HasInArc(arc, target);
3321}
3322
3323bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
3324{
3325 return IsWithinDistInMap(target, distance) && !HasInArc(2 * float(M_PI) - arc, target);
3326}
3327
3329{
3330 // Aquatic creatures are not allowed to leave liquids
3331 if (!IsInWater() && c->IsAquatic())
3332 return false;
3333
3334 // Underwater special case. Some creatures may not go below liquid surfaces
3335 if (IsUnderWater() && c->CannotPenetrateWater())
3336 return false;
3337
3338 // Water checks
3339 if (IsInWater() && !c->CanEnterWater())
3340 return false;
3341
3342 // Some creatures are tied to the ocean floor and cannot chase swimming targets.
3344 return false;
3345
3346 return true;
3347}
3348
3353
3355{
3357}
3358
3360{
3362}
3363
3370
3372{
3373 if (!IsControlledByPlayer())
3374 return;
3375
3376 // remove appropriate auras if we are swimming/not swimming respectively
3377 if (IsInWater())
3379 else
3381
3382 // liquid aura handling
3383 LiquidTypeEntry const* curLiquid = nullptr;
3384 if (IsInWater() && newLiquidData)
3385 curLiquid = sLiquidTypeStore.LookupEntry(newLiquidData->entry);
3386 if (curLiquid != _lastLiquid)
3387 {
3390
3391 // Set _lastLiquid before casting liquid spell to avoid infinite loops
3392 _lastLiquid = curLiquid;
3393
3395 if (curLiquid && curLiquid->SpellID && (!player || !player->IsGameMaster()))
3396 CastSpell(this, curLiquid->SpellID, true);
3397 }
3398}
3399
3404
3406{
3407 ASSERT(!createInfo.CasterGUID.IsEmpty() || createInfo.Caster);
3408
3409 // Check if these can stack anyway
3410 if (!createInfo.CasterGUID && !createInfo.GetSpellInfo()->IsStackableOnOneSlotWithDifferentCasters())
3411 createInfo.CasterGUID = createInfo.Caster->GetGUID();
3412
3413 // passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
3414 if (!createInfo.GetSpellInfo()->IsMultiSlotAura())
3415 {
3416 // check if cast item changed
3417 ObjectGuid castItemGUID = createInfo.CastItemGUID;
3418
3419 // find current aura from spell and change it's stackamount, or refresh it's duration
3420 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))
3421 {
3422 // effect masks do not match
3423 // extremely rare case
3424 // let's just recreate aura
3425 if (createInfo.GetAuraEffectMask() != foundAura->GetEffectMask())
3426 return nullptr;
3427
3428 // update basepoints with new values - effect amount will be recalculated in ModStackAmount
3429 for (SpellEffectInfo const& spellEffectInfo : createInfo.GetSpellInfo()->GetEffects())
3430 {
3431 AuraEffect const* auraEff = foundAura->GetEffect(spellEffectInfo.EffectIndex);
3432 if (!auraEff)
3433 continue;
3434
3436 if (createInfo.BaseAmount)
3437 bp = *(createInfo.BaseAmount + spellEffectInfo.EffectIndex);
3438 else
3439 bp = spellEffectInfo.BasePoints;
3440
3441 SpellEffectValue* oldBP = const_cast<SpellEffectValue*>(&(auraEff->m_baseAmount));
3442 if (spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::AuraPointsStack))
3443 *oldBP += bp;
3444 else
3445 *oldBP = bp;
3446 }
3447
3448 // correct cast item guid if needed
3449 if (castItemGUID != foundAura->GetCastItemGUID())
3450 {
3451 ObjectGuid* oldGUID = const_cast<ObjectGuid*>(&foundAura->m_castItemGuid);
3452 *oldGUID = castItemGUID;
3453 uint32* oldItemId = const_cast<uint32*>(&foundAura->m_castItemId);
3454 *oldItemId = createInfo.CastItemId;
3455 int32* oldItemLevel = const_cast<int32*>(&foundAura->m_castItemLevel);
3456 *oldItemLevel = createInfo.CastItemLevel;
3457 }
3458
3459 // try to increase stack amount
3460 foundAura->ModStackAmount(createInfo.StackAmount, AURA_REMOVE_BY_DEFAULT, createInfo.ResetPeriodicTimer);
3461 return foundAura;
3462 }
3463 }
3464
3465 return nullptr;
3466}
3467
3468void Unit::_AddAura(UnitAura* aura, Unit* caster)
3469{
3471 m_ownedAuras.emplace(aura->GetId(), aura);
3472
3473 _RemoveNoStackAurasDueToAura(aura, true);
3474
3475 if (aura->IsRemoved())
3476 return;
3477
3478 aura->SetIsSingleTarget(caster && aura->GetSpellInfo()->IsSingleTarget());
3479 if (aura->IsSingleTarget())
3480 {
3482 /* @HACK: Player is not in world during loading auras.
3483 * Single target auras are not saved or loaded from database
3484 * but may be created as a result of aura links.
3485 */
3486
3487 std::vector<Aura*> aurasSharingLimit;
3488 // remove other single target auras
3489 for (Aura* scAura : caster->GetSingleCastAuras())
3490 if (scAura->IsSingleTargetWith(aura))
3491 aurasSharingLimit.push_back(scAura);
3492
3493 // register single target aura
3494 caster->GetSingleCastAuras().push_front(aura);
3495
3496 uint32 maxOtherAuras = aura->GetSpellInfo()->MaxAffectedTargets - 1;
3497 while (aurasSharingLimit.size() > maxOtherAuras)
3498 {
3499 aurasSharingLimit.back()->Remove();
3500 aurasSharingLimit.pop_back();
3501 }
3502 }
3503}
3504
3505// creates aura application instance and registers it in lists
3506// aura application effects are handled separately to prevent aura list corruption
3508{
3509 // can't apply aura on unit which is going to be deleted - to not create a memory leak
3511
3512 // just return if the aura has been already removed
3513 // this can happen if OnEffectHitTarget() script hook killed the unit or the aura owner (which can be different)
3514 if (aura->IsRemoved())
3515 {
3516 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());
3517 return nullptr;
3518 }
3519
3520 // aura mustn't be already applied on target
3521 ASSERT (!aura->IsAppliedOnTarget(GetGUID()) && "Unit::_CreateAuraApplication: aura musn't be applied on target");
3522
3523 SpellInfo const* aurSpellInfo = aura->GetSpellInfo();
3524 uint32 aurId = aurSpellInfo->Id;
3525
3526 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3527 if (!IsAlive() && !aurSpellInfo->IsDeathPersistent() &&
3528 (GetTypeId() != TYPEID_PLAYER || !ToPlayer()->GetSession()->PlayerLoading()))
3529 return nullptr;
3530
3531 Unit* caster = aura->GetCaster();
3532
3533 AuraApplication * aurApp = new AuraApplication(this, caster, aura, effMask);
3534 m_appliedAuras.insert(AuraApplicationMap::value_type(aurId, aurApp));
3535
3536 if (aurSpellInfo->HasAnyAuraInterruptFlag())
3537 {
3538 m_interruptableAuras.push_front(aurApp);
3539 AddInterruptMask(aurSpellInfo->AuraInterruptFlags, aurSpellInfo->AuraInterruptFlags2);
3540 }
3541
3542 if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState())
3543 m_auraStateAuras.insert(AuraStateAurasMap::value_type(aState, aurApp));
3544
3545 aura->_ApplyForTarget(this, caster, aurApp);
3546 return aurApp;
3547}
3548
3549void Unit::_ApplyAuraEffect(Aura* aura, uint8 effIndex)
3550{
3551 ASSERT(aura);
3552 ASSERT(aura->HasEffect(effIndex));
3554 ASSERT(aurApp);
3555 if (!aurApp->GetEffectMask())
3556 _ApplyAura(aurApp, 1 << effIndex);
3557 else
3558 aurApp->_HandleEffect(effIndex, true);
3559}
3560
3561// handles effects of aura application
3562// should be done after registering aura in lists
3564{
3565 Aura* aura = aurApp->GetBase();
3566
3567 _RemoveNoStackAurasDueToAura(aura, false);
3568
3569 if (aurApp->GetRemoveMode())
3570 return;
3571
3572 // Update target aura state flag
3573 if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState())
3574 {
3575 uint32 aStateMask = (1 << (aState - 1));
3576 // force update so the new caster registers it
3577 if ((aStateMask & PER_CASTER_AURA_STATE_MASK) && *m_unitData->AuraState & aStateMask)
3579 else
3580 ModifyAuraState(aState, true);
3581 }
3582
3583 if (aurApp->GetRemoveMode())
3584 return;
3585
3586 // Sitdown on apply aura req seated
3589
3590 Unit* caster = aura->GetCaster();
3591
3592 if (aurApp->GetRemoveMode())
3593 return;
3594
3595 aura->HandleAuraSpecificMods(aurApp, caster, true, false);
3596
3597 // apply effects of the aura
3598 for (AuraEffect const* aurEff : aura->GetAuraEffects())
3599 {
3600 if (effMask & 1 << aurEff->GetEffIndex())
3601 {
3602 aurApp->_HandleEffect(aurEff->GetEffIndex(), true);
3603 if (aurApp->GetRemoveMode())
3604 break;
3605 }
3606 }
3607
3608 if (Player* player = ToPlayer())
3609 {
3610 if (sConditionMgr->IsSpellUsedInSpellClickConditions(aura->GetId()))
3611 player->UpdateVisibleObjectInteractions(false, true, false, false);
3612
3613 player->FailCriteria(CriteriaFailEvent::GainAura, aura->GetId());
3614 player->StartCriteria(CriteriaStartEvent::GainAura, aura->GetId());
3615 player->UpdateCriteria(CriteriaType::GainAura, aura->GetId(), 0, 0, caster);
3616 }
3617}
3618
3619// removes aura application from lists and unapplies effects
3620void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMode)
3621{
3622 AuraApplication * aurApp = i->second;
3623 ASSERT(aurApp);
3624 ASSERT(!aurApp->GetRemoveMode());
3625 ASSERT(aurApp->GetTarget() == this);
3626
3627 aurApp->SetRemoveMode(removeMode);
3628 Aura* aura = aurApp->GetBase();
3629 TC_LOG_DEBUG("spells", "Aura {} now is remove mode {}", aura->GetId(), removeMode);
3630
3631 // dead loop is killing the server probably
3632 ASSERT(m_removedAurasCount < 0xFFFFFFFF);
3633
3635
3636 Unit* caster = aura->GetCaster();
3637
3638 // Remove all pointers from lists here to prevent possible pointer invalidation on spellcast/auraapply/auraremove
3639 m_appliedAuras.erase(i);
3640
3642 {
3645 }
3646
3647 bool auraStateFound = false;
3648 AuraStateType auraState = aura->GetSpellInfo()->GetAuraState();
3649 if (auraState)
3650 {
3651 bool canBreak = false;
3652 // Get mask of all aurastates from remaining auras
3653 for (AuraStateAurasMap::iterator itr = m_auraStateAuras.lower_bound(auraState); itr != m_auraStateAuras.upper_bound(auraState) && !(auraStateFound && canBreak);)
3654 {
3655 if (itr->second == aurApp)
3656 {
3657 m_auraStateAuras.erase(itr);
3658 itr = m_auraStateAuras.lower_bound(auraState);
3659 canBreak = true;
3660 continue;
3661 }
3662 auraStateFound = true;
3663 ++itr;
3664 }
3665 }
3666
3667 aurApp->_Remove();
3668 aura->_UnapplyForTarget(this, caster, aurApp);
3669
3670 // remove effects of the spell - needs to be done after removing aura from lists
3671 for (AuraEffect const* aurEff : aura->GetAuraEffects())
3672 if (aurApp->HasEffect(aurEff->GetEffIndex()))
3673 aurApp->_HandleEffect(aurEff->GetEffIndex(), false);
3674
3675 // all effect mustn't be applied
3676 ASSERT(!aurApp->GetEffectMask());
3677
3678 // Remove totem at next update if totem loses its aura
3679 if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE && GetTypeId() == TYPEID_UNIT && IsTotem())
3680 {
3681 if (ToTotem()->GetSpell() == aura->GetId() && ToTotem()->GetTotemType() == TOTEM_PASSIVE)
3683 }
3684
3685 // Remove aurastates only if needed and were not found
3686 if (auraState)
3687 {
3688 if (!auraStateFound)
3689 ModifyAuraState(auraState, false);
3690 else
3691 {
3692 // update for casters, some shouldn't 'see' the aura state
3693 uint32 aStateMask = (1 << (auraState - 1));
3694 if ((aStateMask & PER_CASTER_AURA_STATE_MASK) != 0)
3696 }
3697 }
3698
3699 aura->HandleAuraSpecificMods(aurApp, caster, false, false);
3700
3701 if (Player* player = ToPlayer())
3702 {
3703 if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId()))
3704 player->UpdateVisibleObjectInteractions(false, true, false, false);
3705
3706 player->FailCriteria(CriteriaFailEvent::LoseAura, aurApp->GetBase()->GetId());
3707 }
3708
3709 i = m_appliedAuras.begin();
3710}
3711
3713{
3714 // aura can be removed from unit only if it's applied on it, shouldn't happen
3715 ASSERT(aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) == aurApp);
3716
3717 uint32 spellId = aurApp->GetBase()->GetId();
3718 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3719
3720 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3721 {
3722 if (iter->second == aurApp)
3723 {
3724 _UnapplyAura(iter, removeMode);
3725 return;
3726 }
3727 else
3728 ++iter;
3729 }
3730 ABORT();
3731}
3732
3734{
3735 SpellInfo const* spellProto = aura->GetSpellInfo();
3736
3737 // passive spell special case (only non stackable with ranks)
3738 if (spellProto->IsPassiveStackableWithRanks())
3739 return;
3740
3741 if (!IsHighestExclusiveAura(aura))
3742 {
3743 aura->Remove();
3744 return;
3745 }
3746
3747 if (owned)
3748 RemoveOwnedAuras([aura](Aura const* ownedAura) { return !aura->CanStackWith(ownedAura); }, AURA_REMOVE_BY_DEFAULT);
3749 else
3750 RemoveAppliedAuras([aura](AuraApplication const* appliedAura) { return !aura->CanStackWith(appliedAura->GetBase()); }, AURA_REMOVE_BY_DEFAULT);
3751}
3752
3753void Unit::_RegisterAuraEffect(AuraEffect* aurEff, bool apply)
3754{
3755 if (apply)
3756 {
3757 m_modAuras[aurEff->GetAuraType()].push_front(aurEff);
3758 if (Player* player = ToPlayer())
3759 {
3760 player->FailCriteria(CriteriaFailEvent::GainAuraEffect, aurEff->GetAuraType());
3761 player->StartCriteria(CriteriaStartEvent::GainAuraEffect, aurEff->GetAuraType());
3762 }
3763 }
3764 else
3766}
3767
3768// All aura base removes should go through this function!
3769void Unit::RemoveOwnedAura(AuraMap::iterator& i, AuraRemoveMode removeMode)
3770{
3771 Aura* aura = i->second;
3772 ASSERT(!aura->IsRemoved());
3773
3774 // if unit currently update aura list then make safe update iterator shift to next
3775 if (m_auraUpdateIterator == i)
3777
3778 m_ownedAuras.erase(i);
3779 m_removedAuras.push_front(aura);
3780
3781 // Unregister single target aura
3782 if (aura->IsSingleTarget())
3783 aura->UnregisterSingleTarget();
3784
3785 aura->_Remove(removeMode);
3786
3787 i = m_ownedAuras.begin();
3788}
3789
3790void Unit::RemoveOwnedAura(uint32 spellId, ObjectGuid casterGUID, uint32 reqEffMask, AuraRemoveMode removeMode)
3791{
3792 for (AuraMap::iterator itr = m_ownedAuras.lower_bound(spellId); itr != m_ownedAuras.upper_bound(spellId);)
3793 if (((itr->second->GetEffectMask() & reqEffMask) == reqEffMask) && (!casterGUID || itr->second->GetCasterGUID() == casterGUID))
3794 {
3795 RemoveOwnedAura(itr, removeMode);
3796 itr = m_ownedAuras.lower_bound(spellId);
3797 }
3798 else
3799 ++itr;
3800}
3801
3803{
3804 if (aura->IsRemoved())
3805 return;
3806
3807 ASSERT(aura->GetOwner() == this);
3808
3809 if (removeMode == AURA_REMOVE_NONE)
3810 {
3811 TC_LOG_ERROR("spells", "Unit::RemoveOwnedAura() called with unallowed removeMode AURA_REMOVE_NONE, spellId {}", aura->GetId());
3812 return;
3813 }
3814
3815 uint32 spellId = aura->GetId();
3816 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3817
3818 for (AuraMap::iterator itr = range.first; itr != range.second; ++itr)
3819 {
3820 if (itr->second == aura)
3821 {
3822 RemoveOwnedAura(itr, removeMode);
3823 return;
3824 }
3825 }
3826
3827 ABORT();
3828}
3829
3830Aura* Unit::GetOwnedAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, Aura* except) const
3831{
3832 AuraMapBounds range = m_ownedAuras.equal_range(spellId);
3833 for (AuraMap::const_iterator itr = range.first; itr != range.second; ++itr)
3834 {
3835 if (((itr->second->GetEffectMask() & reqEffMask) == reqEffMask)
3836 && (!casterGUID || itr->second->GetCasterGUID() == casterGUID)
3837 && (!itemCasterGUID || itr->second->GetCastItemGUID() == itemCasterGUID)
3838 && (!except || except != itr->second))
3839 {
3840 return itr->second;
3841 }
3842 }
3843 return nullptr;
3844}
3845
3846void Unit::RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode)
3847{
3848 AuraApplication * aurApp = i->second;
3849 // Do not remove aura which is already being removed
3850 if (aurApp->GetRemoveMode())
3851 return;
3852 Aura* aura = aurApp->GetBase();
3853 _UnapplyAura(i, mode);
3854 // Remove aura - for Area and Target auras
3855 if (aura->GetOwner() == this)
3856 aura->Remove(mode);
3857}
3858
3859void Unit::RemoveAura(uint32 spellId, ObjectGuid caster, uint32 reqEffMask, AuraRemoveMode removeMode)
3860{
3861 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3862 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3863 {
3864 Aura const* aura = iter->second->GetBase();
3865 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
3866 && (!caster || aura->GetCasterGUID() == caster))
3867 {
3868 RemoveAura(iter, removeMode);
3869 return;
3870 }
3871 else
3872 ++iter;
3873 }
3874}
3875
3877{
3878 // we've special situation here, RemoveAura called while during aura removal
3879 // this kind of call is needed only when aura effect removal handler
3880 // or event triggered by it expects to remove
3881 // not yet removed effects of an aura
3882 if (aurApp->GetRemoveMode())
3883 {
3884 // remove remaining effects of an aura
3885 for (AuraEffect const* aurEff : aurApp->GetBase()->GetAuraEffects())
3886 {
3887 if (aurApp->HasEffect(aurEff->GetEffIndex()))
3888 aurApp->_HandleEffect(aurEff->GetEffIndex(), false);
3889 }
3890 return;
3891 }
3892 // no need to remove
3893 if (aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) != aurApp || aurApp->GetBase()->IsRemoved())
3894 return;
3895
3896 uint32 spellId = aurApp->GetBase()->GetId();
3897 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3898
3899 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3900 {
3901 if (aurApp == iter->second)
3902 {
3903 RemoveAura(iter, mode);
3904 return;
3905 }
3906 else
3907 ++iter;
3908 }
3909}
3910
3912{
3913 if (aura->IsRemoved())
3914 return;
3915 if (AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID()))
3916 RemoveAura(aurApp, mode);
3917}
3918
3919void Unit::RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3920{
3921 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
3922 {
3923 if (check(iter->second))
3924 {
3925 RemoveAura(iter, removeMode);
3926 continue;
3927 }
3928 ++iter;
3929 }
3930}
3931
3932void Unit::RemoveOwnedAuras(std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3933{
3934 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
3935 {
3936 if (check(iter->second))
3937 {
3938 RemoveOwnedAura(iter, removeMode);
3939 continue;
3940 }
3941 ++iter;
3942 }
3943}
3944
3945void Unit::RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3946{
3947 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3948 {
3949 if (check(iter->second))
3950 {
3951 RemoveAura(iter, removeMode);
3952 iter = m_appliedAuras.lower_bound(spellId);
3953 continue;
3954 }
3955 ++iter;
3956 }
3957}
3958
3959void Unit::RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3960{
3961 for (AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
3962 {
3963 if (check(iter->second))
3964 {
3965 RemoveOwnedAura(iter, removeMode);
3966 iter = m_ownedAuras.lower_bound(spellId);
3967 continue;
3968 }
3969 ++iter;
3970 }
3971}
3972
3973void Unit::RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3974{
3975 for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
3976 {
3977 Aura* aura = (*iter)->GetBase();
3979 ASSERT(aurApp);
3980
3981 ++iter;
3982 if (check(aurApp))
3983 {
3984 uint32 removedAuras = m_removedAurasCount;
3985 RemoveAura(aurApp, removeMode);
3986 if (m_removedAurasCount > removedAuras + 1)
3987 iter = m_modAuras[auraType].begin();
3988 }
3989 }
3990}
3991
3992void Unit::RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID, uint32 reqEffMask, AuraRemoveMode removeMode)
3993{
3994 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3995 {
3996 Aura const* aura = iter->second->GetBase();
3997 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
3998 && (!casterGUID || aura->GetCasterGUID() == casterGUID))
3999 {
4000 RemoveAura(iter, removeMode);
4001 iter = m_appliedAuras.lower_bound(spellId);
4002 }
4003 else
4004 ++iter;
4005 }
4006}
4007
4008void Unit::RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID, AuraRemoveMode removeMode, uint16 num)
4009{
4010 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
4011 for (AuraMap::iterator iter = range.first; iter != range.second;)
4012 {
4013 Aura* aura = iter->second;
4014 if ((aura->GetType() == UNIT_AURA_TYPE)
4015 && (!casterGUID || aura->GetCasterGUID() == casterGUID))
4016 {
4017 aura->ModStackAmount(-num, removeMode);
4018 return;
4019 }
4020 else
4021 ++iter;
4022 }
4023}
4024
4025void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject* dispeller, uint8 chargesRemoved /*= 1*/)
4026{
4027 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
4028 for (AuraMap::iterator iter = range.first; iter != range.second;)
4029 {
4030 Aura* aura = iter->second;
4031 if (aura->GetCasterGUID() == casterGUID)
4032 {
4033 DispelInfo dispelInfo(dispeller, dispellerSpellId, chargesRemoved);
4034
4035 // Call OnDispel hook on AuraScript
4036 aura->CallScriptDispel(&dispelInfo);
4037
4040 else
4042
4043 // Call AfterDispel hook on AuraScript
4044 aura->CallScriptAfterDispel(&dispelInfo);
4045
4046 return;
4047 }
4048 else
4049 ++iter;
4050 }
4051}
4052
4053void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject* stealer, int32 stolenCharges /*= 1*/)
4054{
4055 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
4056 for (AuraMap::iterator iter = range.first; iter != range.second;)
4057 {
4058 Aura* aura = iter->second;
4059 if (aura->GetCasterGUID() == casterGUID)
4060 {
4061 std::array<SpellEffectValue, MAX_SPELL_EFFECTS> damage = { };
4062 std::array<SpellEffectValue, MAX_SPELL_EFFECTS> baseDamage = { };
4063 std::bitset<MAX_SPELL_EFFECTS> effMask;
4064 std::bitset<MAX_SPELL_EFFECTS> recalculateMask;
4065 Unit* caster = aura->GetCaster();
4066 for (AuraEffect const* aurEff : aura->GetAuraEffects())
4067 {
4068 SpellEffIndex i = aurEff->GetEffIndex();
4069 baseDamage[i] = aurEff->GetBaseAmount();
4070 damage[i] = aurEff->GetAmount();
4071 effMask[i] = true;
4072 if (aurEff->CanBeRecalculated())
4073 recalculateMask[i] = true;
4074 }
4075
4077 // Cast duration to unsigned to prevent permanent aura's such as Righteous Fury being permanently added to caster
4078 uint32 dur = std::min(2u * MINUTE * IN_MILLISECONDS, uint32(aura->GetDuration()));
4079
4080 if (Unit* unitStealer = stealer->ToUnit())
4081 {
4082 if (Aura* oldAura = unitStealer->GetAura(aura->GetId(), aura->GetCasterGUID()))
4083 {
4084 if (stealCharge)
4085 oldAura->ModCharges(stolenCharges);
4086 else
4087 oldAura->ModStackAmount(stolenCharges);
4088 oldAura->SetDuration(int32(dur));
4089 }
4090 else
4091 {
4092 // single target state must be removed before aura creation to preserve existing single target aura
4093 if (aura->IsSingleTarget())
4094 aura->UnregisterSingleTarget();
4095
4096 AuraCreateInfo createInfo(aura->GetCastId(), aura->GetSpellInfo(), aura->GetCastDifficulty(), effMask.to_ulong(), unitStealer);
4097 createInfo
4099 .SetBaseAmount(baseDamage.data())
4100 .SetStackAmount(stolenCharges);
4101
4102 if (Aura* newAura = Aura::TryRefreshStackOrCreate(createInfo))
4103 {
4104 // created aura must not be single target aura,, so stealer won't loose it on recast
4105 if (newAura->IsSingleTarget())
4106 {
4107 newAura->UnregisterSingleTarget();
4108 // bring back single target aura status to the old aura
4109 aura->SetIsSingleTarget(true);
4110 caster->GetSingleCastAuras().push_front(aura);
4111 }
4112 // FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
4113 newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? stolenCharges : aura->GetCharges(), recalculateMask.to_ulong(), damage.data());
4114 newAura->ApplyForTargets();
4115 }
4116 }
4117 }
4118
4119 if (stealCharge)
4120 aura->ModCharges(-stolenCharges, AURA_REMOVE_BY_ENEMY_SPELL);
4121 else
4122 aura->ModStackAmount(-stolenCharges, AURA_REMOVE_BY_ENEMY_SPELL);
4123
4124 return;
4125 }
4126 else
4127 ++iter;
4128 }
4129}
4130
4132{
4133 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
4134 {
4135 if (iter->second->GetBase()->GetCastItemGUID() == castItemGuid)
4136 {
4137 RemoveAura(iter);
4138 iter = m_appliedAuras.lower_bound(spellId);
4139 }
4140 else
4141 ++iter;
4142 }
4143}
4144
4145void Unit::RemoveAurasByType(AuraType auraType, ObjectGuid casterGUID, Aura* except, bool negative, bool positive)
4146{
4147 for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
4148 {
4149 Aura* aura = (*iter)->GetBase();
4151 ASSERT(aurApp);
4152
4153 ++iter;
4154 if (aura != except && (!casterGUID || aura->GetCasterGUID() == casterGUID)
4155 && ((negative && !aurApp->IsPositive()) || (positive && aurApp->IsPositive())))
4156 {
4157 uint32 removedAuras = m_removedAurasCount;
4158 RemoveAura(aurApp);
4159 if (m_removedAurasCount > removedAuras + 1)
4160 iter = m_modAuras[auraType].begin();
4161 }
4162 }
4163}
4164
4166{
4167 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4168 {
4169 SpellInfo const* spell = iter->second->GetBase()->GetSpellInfo();
4170 if (spell->HasAttribute(flags))
4171 RemoveAura(iter);
4172 else
4173 ++iter;
4174 }
4175}
4176
4177void Unit::RemoveNotOwnSingleTargetAuras(bool onPhaseChange /*= false*/)
4178{
4179 // single target auras from other casters
4180 // Iterate m_ownedAuras - aura is marked as single target in Unit::AddAura (and pushed to m_ownedAuras).
4181 // m_appliedAuras will NOT contain the aura before first Unit::Update after adding it to m_ownedAuras.
4182 // Quickly removing such an aura will lead to it not being unregistered from caster's single cast auras container
4183 // leading to assertion failures if the aura was cast on a player that can
4184 // (and is changing map at the point where this function is called).
4185 // Such situation occurs when player is logging in inside an instance and fails the entry check for any reason.
4186 // The aura that was loaded from db (indirectly, via linked casts) gets removed before it has a chance
4187 // to register in m_appliedAuras
4188 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4189 {
4190 Aura const* aura = iter->second;
4191
4192 if (aura->GetCasterGUID() != GetGUID() && aura->IsSingleTarget())
4193 {
4194 if (!onPhaseChange)
4195 RemoveOwnedAura(iter);
4196 else
4197 {
4198 Unit* caster = aura->GetCaster();
4199 if (!caster || !caster->InSamePhase(this))
4200 RemoveOwnedAura(iter);
4201 else
4202 ++iter;
4203 }
4204 }
4205 else
4206 ++iter;
4207 }
4208
4209 // single target auras at other targets
4210 AuraList& scAuras = GetSingleCastAuras();
4211 for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
4212 {
4213 Aura* aura = *iter;
4214 if (aura->GetUnitOwner() != this && (!onPhaseChange || !aura->GetUnitOwner()->InSamePhase(this)))
4215 {
4216 aura->Remove();
4217 iter = scAuras.begin();
4218 }
4219 else
4220 ++iter;
4221 }
4222}
4223
4224template<typename InterruptFlag>
4225bool IsInterruptFlagIgnoredForSpell(InterruptFlag /*flag*/, Unit const* /*unit*/, SpellInfo const* /*auraSpellInfo*/, bool /*isChannel*/, SpellInfo const* /*interruptSource*/)
4226{
4227 return false;
4228}
4229
4230template<>
4231bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit const* unit, SpellInfo const* auraSpellInfo, bool isChannel, SpellInfo const* interruptSource)
4232{
4233 switch (flag)
4234 {
4236 return unit->CanCastSpellWhileMoving(auraSpellInfo);
4239 if (interruptSource)
4240 {
4241 if (interruptSource->HasAttribute(SPELL_ATTR1_ALLOW_WHILE_STEALTHED) && auraSpellInfo->Dispel == DISPEL_STEALTH)
4242 return true;
4243
4244 if (interruptSource->HasAttribute(SPELL_ATTR2_ALLOW_WHILE_INVISIBLE) && auraSpellInfo->Dispel == DISPEL_INVISIBILITY)
4245 return true;
4246
4247 if (interruptSource->HasAttribute(SPELL_ATTR9_ALLOW_CAST_WHILE_CHANNELING) && isChannel)
4248 return true;
4249 }
4250 break;
4251 default:
4252 break;
4253 }
4254
4255 return false;
4256}
4257
4258template <typename InterruptFlags>
4259void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const* source)
4260{
4261 if (!HasInterruptFlag(flag))
4262 return;
4263
4264 // interrupt auras
4265 for (AuraApplicationList::iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end();)
4266 {
4267 Aura* aura = (*iter)->GetBase();
4268 ++iter;
4269 if (aura->GetSpellInfo()->HasAuraInterruptFlag(flag)
4270 && (!source || aura->GetId() != source->Id)
4271 && !IsInterruptFlagIgnoredForSpell(flag, this, aura->GetSpellInfo(), false, source))
4272 {
4273 uint32 removedAuras = m_removedAurasCount;
4275 if (m_removedAurasCount > removedAuras + 1)
4276 iter = m_interruptableAuras.begin();
4277 }
4278 }
4279
4280 // interrupt channeled spell
4282 if (spell->getState() == SPELL_STATE_CHANNELING
4283 && spell->GetSpellInfo()->HasChannelInterruptFlag(flag)
4284 && (!source || spell->GetSpellInfo()->Id != source->Id)
4285 && !IsInterruptFlagIgnoredForSpell(flag, this, spell->GetSpellInfo(), true, source))
4287
4289}
4290
4293
4294void Unit::RemoveAurasWithFamily(SpellFamilyNames family, flag128 const& familyFlag, ObjectGuid casterGUID)
4295{
4296 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4297 {
4298 Aura const* aura = iter->second->GetBase();
4299 if (!casterGUID || aura->GetCasterGUID() == casterGUID)
4300 {
4301 SpellInfo const* spell = aura->GetSpellInfo();
4302 if (spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags & familyFlag)
4303 {
4304 RemoveAura(iter);
4305 continue;
4306 }
4307 }
4308 ++iter;
4309 }
4310}
4311
4313{
4314 if (withRoot)
4316
4318}
4319
4320void Unit::RemoveAurasWithMechanic(uint64 mechanicMaskToRemove, AuraRemoveMode removeMode, uint32 exceptSpellId, bool withEffectMechanics)
4321{
4322 std::vector<Aura*> aurasToUpdateTargets;
4323 RemoveAppliedAuras([=, &aurasToUpdateTargets](AuraApplication const* aurApp)
4324 {
4325 Aura* aura = aurApp->GetBase();
4326 if (exceptSpellId && aura->GetId() == exceptSpellId)
4327 return false;
4328
4329 uint64 appliedMechanicMask = aura->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask());
4330 if (!(appliedMechanicMask & mechanicMaskToRemove))
4331 return false;
4332
4333 // spell mechanic matches required mask for removal
4334 if ((UI64LIT(1) << aura->GetSpellInfo()->Mechanic) & mechanicMaskToRemove || withEffectMechanics)
4335 return true;
4336
4337 // effect mechanic matches required mask for removal - don't remove, only update targets
4338 aurasToUpdateTargets.push_back(aura);
4339 return false;
4340 }, removeMode);
4341
4342 for (Aura* aura : aurasToUpdateTargets)
4343 {
4344 aura->UpdateTargetMap(aura->GetCaster());
4345
4346 // Fully remove the aura if all effects were removed
4347 if (!aura->IsPassive() && aura->GetOwner() == this && !aura->GetApplicationOfTarget(GetGUID()))
4348 aura->Remove(removeMode);
4349 }
4350}
4351
4353{
4354 uint64 mechanic_mask = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT);
4355 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4356 {
4357 Aura const* aura = iter->second->GetBase();
4358 if ((aura->GetSpellInfo()->GetAllEffectsMechanicMask() & mechanic_mask) && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_CU_AURA_CC))
4359 {
4360 RemoveAura(iter);
4361 continue;
4362 }
4363 ++iter;
4364 }
4365}
4366
4368{
4369 // make sure that all area auras not applied on self are removed - prevent access to deleted pointer later
4370 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4371 {
4372 Aura* aura = iter->second;
4373 ++iter;
4374 Aura::ApplicationMap const& appMap = aura->GetApplicationMap();
4375 for (Aura::ApplicationMap::const_iterator itr = appMap.begin(); itr!= appMap.end();)
4376 {
4377 AuraApplication * aurApp = itr->second;
4378 ++itr;
4379 Unit* target = aurApp->GetTarget();
4380 if (target == this)
4381 continue;
4382 target->RemoveAura(aurApp);
4383 // things linked on aura remove may apply new area aura - so start from the beginning
4384 iter = m_ownedAuras.begin();
4385 }
4386 }
4387
4388 // remove area auras owned by others
4389 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4390 {
4391 if (iter->second->GetBase()->GetOwner() != this)
4392 {
4393 RemoveAura(iter);
4394 }
4395 else
4396 ++iter;
4397 }
4398}
4399
4401{
4402 // this may be a dead loop if some events on aura remove will continiously apply aura on remove
4403 // we want to have all auras removed, so use your brain when linking events
4404 for (int counter = 0; !m_appliedAuras.empty() || !m_ownedAuras.empty(); counter++)
4405 {
4406 AuraApplicationMap::iterator aurAppIter;
4407 for (aurAppIter = m_appliedAuras.begin(); aurAppIter != m_appliedAuras.end();)
4409
4410 AuraMap::iterator aurIter;
4411 for (aurIter = m_ownedAuras.begin(); aurIter != m_ownedAuras.end();)
4412 RemoveOwnedAura(aurIter);
4413
4414 const int maxIteration = 50;
4415 // give this loop a few tries, if there are still auras then log as much information as possible
4416 if (counter >= maxIteration)
4417 {
4418 std::stringstream sstr;
4419 sstr << "Unit::RemoveAllAuras() iterated " << maxIteration << " times already but there are still "
4420 << m_appliedAuras.size() << " m_appliedAuras and " << m_ownedAuras.size() << " m_ownedAuras. Details:" << "\n";
4421 sstr << GetDebugInfo() << "\n";
4422
4423 if (!m_appliedAuras.empty())
4424 {
4425 sstr << "m_appliedAuras:" << "\n";
4426
4427 for (std::pair<uint32 const, AuraApplication*>& auraAppPair : m_appliedAuras)
4428 sstr << auraAppPair.second->GetDebugInfo() << "\n";
4429 }
4430
4431 if (!m_ownedAuras.empty())
4432 {
4433 sstr << "m_ownedAuras:" << "\n";
4434
4435 for (auto const& [spellId, aura] : m_ownedAuras)
4436 sstr << aura->GetDebugInfo() << "\n";
4437 }
4438
4439 TC_LOG_ERROR("entities.unit", "{}", sstr.str());
4440 ABORT_MSG("%s", sstr.str().c_str());
4441
4442 break;
4443 }
4444 }
4445}
4446
4448{
4449 // in join, remove positive buffs, on end, remove negative
4450 // used to remove positive visible auras in arenas
4451 RemoveAppliedAuras([](AuraApplication const* aurApp)
4452 {
4453 Aura const* aura = aurApp->GetBase();
4454 return (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_ALLOW_ENTERING_ARENA) // don't remove stances, shadowform, pally/hunter auras
4455 && !aura->IsPassive() // don't remove passive auras
4456 && (aurApp->IsPositive() || !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD))) || // not negative death persistent auras
4457 aura->GetSpellInfo()->HasAttribute(SPELL_ATTR5_REMOVE_ENTERING_ARENA); // special marker, always remove
4458 });
4459}
4460
4462{
4463 if (IsCharmedOwnedByPlayerOrPlayer()) // if it is a player owned creature it should not remove the aura
4464 return;
4465
4466 // don't remove vehicle auras, passengers aren't supposed to drop off the vehicle
4467 // don't remove clone caster on evade (to be verified)
4468 auto evadeAuraCheck = [](Aura const* aura)
4469 {
4470 if (aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE))
4471 return false;
4472
4473 if (aura->HasEffectType(SPELL_AURA_CLONE_CASTER))
4474 return false;
4475
4476 if (aura->GetSpellInfo()->HasAttribute(SPELL_ATTR1_AURA_STAYS_AFTER_COMBAT))
4477 return false;
4478
4479 return true;
4480 };
4481
4482 auto evadeAuraApplicationCheck = [&evadeAuraCheck](AuraApplication const* aurApp)
4483 {
4484 return evadeAuraCheck(aurApp->GetBase());
4485 };
4486
4487 RemoveAppliedAuras(evadeAuraApplicationCheck);
4488 RemoveOwnedAuras(evadeAuraCheck);
4489}
4490
4492{
4493 // used just after dieing to remove all visible auras
4494 // and disable the mods for the passive ones
4495 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4496 {
4497 Aura const* aura = iter->second->GetBase();
4498 if (!aura->IsPassive() && !aura->IsDeathPersistent())
4500 else
4501 ++iter;
4502 }
4503
4504 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4505 {
4506 Aura* aura = iter->second;
4507 if (!aura->IsPassive() && !aura->IsDeathPersistent())
4509 else
4510 ++iter;
4511 }
4512}
4513
4515{
4516 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4517 {
4518 Aura const* aura = iter->second->GetBase();
4519 if (!aura->IsPassive() && aura->GetSpellInfo()->IsRequiringDeadTarget())
4521 else
4522 ++iter;
4523 }
4524
4525 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4526 {
4527 Aura* aura = iter->second;
4528 if (!aura->IsPassive() && aura->GetSpellInfo()->IsRequiringDeadTarget())
4530 else
4531 ++iter;
4532 }
4533}
4534
4536{
4537 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4538 {
4539 Aura const* aura = iter->second->GetBase();
4540 if (aura->GetSpellInfo()->HasAura(type))
4541 ++iter;
4542 else
4544 }
4545
4546 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4547 {
4548 Aura* aura = iter->second;
4549 if (aura->GetSpellInfo()->HasAura(type))
4550 ++iter;
4551 else
4553 }
4554}
4555
4557{
4558 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4559 {
4560 Aura const* aura = iter->second->GetBase();
4561 if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2))
4562 ++iter;
4563 else
4565 }
4566
4567 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4568 {
4569 Aura* aura = iter->second;
4570 if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2))
4571 ++iter;
4572 else
4574 }
4575}
4576
4578{
4579 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4580 {
4581 Aura* aura = iter->second;
4582 if (aura->GetCasterGUID() == casterGUID && aura->GetSpellInfo()->IsGroupBuff())
4583 {
4584 RemoveOwnedAura(iter);
4585 continue;
4586 }
4587 ++iter;
4588 }
4589}
4590
4591void Unit::DelayOwnedAuras(uint32 spellId, ObjectGuid caster, int32 delaytime)
4592{
4593 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
4594 for (; range.first != range.second; ++range.first)
4595 {
4596 Aura* aura = range.first->second;
4597 if (!caster || aura->GetCasterGUID() == caster)
4598 {
4599 if (aura->GetDuration() < delaytime)
4600 aura->SetDuration(0);
4601 else
4602 aura->SetDuration(aura->GetDuration() - delaytime);
4603
4604 // update for out of range group members (on 1 slot use)
4606 }
4607 }
4608}
4609
4611{
4612 for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
4613 (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, false);
4614}
4615
4617{
4618 for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
4619 (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, true);
4620}
4621
4622AuraEffect* Unit::GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster) const
4623{
4624 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4625 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4626 {
4627 if (itr->second->HasEffect(effIndex)
4628 && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
4629 {
4630 return itr->second->GetBase()->GetEffect(effIndex);
4631 }
4632 }
4633 return nullptr;
4634}
4635
4637{
4638 uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
4639 while (rankSpell)
4640 {
4641 if (AuraEffect* aurEff = GetAuraEffect(rankSpell, effIndex, caster))
4642 return aurEff;
4643 rankSpell = sSpellMgr->GetNextSpellInChain(rankSpell);
4644 }
4645 return nullptr;
4646}
4647
4648AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames family, flag128 const& familyFlag, ObjectGuid casterGUID) const
4649{
4650 AuraEffectList const& auras = GetAuraEffectsByType(type);
4651 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4652 {
4653 SpellInfo const* spell = (*i)->GetSpellInfo();
4654 if (spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags & familyFlag)
4655 {
4656 if (!casterGUID.IsEmpty() && (*i)->GetCasterGUID() != casterGUID)
4657 continue;
4658 return (*i);
4659 }
4660 }
4661 return nullptr;
4662}
4663
4664AuraApplication * Unit::GetAuraApplication(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, AuraApplication * except) const
4665{
4666 return GetAuraApplication(spellId, [&](AuraApplication const* app)
4667 {
4668 Aura const* aura = app->GetBase();
4669
4670 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
4671 && (!casterGUID || aura->GetCasterGUID() == casterGUID)
4672 && (!itemCasterGUID || aura->GetCastItemGUID() == itemCasterGUID)
4673 && (!except || except != app))
4674 {
4675 return true;
4676 }
4677
4678 return false;
4679 });
4680}
4681
4682AuraApplication* Unit::GetAuraApplication(uint32 spellId, std::function<bool(AuraApplication const*)> const& predicate) const
4683{
4684 for (AuraApplicationMap::value_type const& pair : Trinity::Containers::MapEqualRange(m_appliedAuras, spellId))
4685 if (predicate(pair.second))
4686 return pair.second;
4687
4688 return nullptr;
4689}
4690
4691AuraApplication* Unit::GetAuraApplication(uint32 spellId, std::function<bool(Aura const*)> const& predicate) const
4692{
4693 for (AuraApplicationMap::value_type const& pair : Trinity::Containers::MapEqualRange(m_appliedAuras, spellId))
4694 if (predicate(pair.second->GetBase()))
4695 return pair.second;
4696
4697 return nullptr;
4698}
4699
4700AuraApplication* Unit::GetAuraApplication(std::function<bool(AuraApplication const*)> const& predicate) const
4701{
4702 for (AuraApplicationMap::value_type const& pair : m_appliedAuras)
4703 if (predicate(pair.second))
4704 return pair.second;
4705
4706 return nullptr;
4707}
4708
4709AuraApplication* Unit::GetAuraApplication(std::function<bool(Aura const*)> const& predicate) const
4710{
4711 for (AuraApplicationMap::value_type const& pair : m_appliedAuras)
4712 if (predicate(pair.second->GetBase()))
4713 return pair.second;
4714
4715 return nullptr;
4716}
4717
4718Aura* Unit::GetAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const
4719{
4720 AuraApplication* aurApp = GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask);
4721 return aurApp ? aurApp->GetBase() : nullptr;
4722}
4723
4724Aura* Unit::GetAura(uint32 spellId, std::function<bool(Aura const*)> const& predicate) const
4725{
4726 AuraApplication* aurApp = GetAuraApplication(spellId, predicate);
4727 return aurApp ? aurApp->GetBase() : nullptr;
4728}
4729
4730Aura* Unit::GetAura(std::function<bool(Aura const*)> const& predicate) const
4731{
4732 AuraApplication* aurApp = GetAuraApplication(predicate);
4733 return aurApp ? aurApp->GetBase() : nullptr;
4734}
4735
4736AuraApplication * Unit::GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, AuraApplication* except) const
4737{
4738 uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
4739 while (rankSpell)
4740 {
4741 if (AuraApplication * aurApp = GetAuraApplication(rankSpell, casterGUID, itemCasterGUID, reqEffMask, except))
4742 return aurApp;
4743 rankSpell = sSpellMgr->GetNextSpellInChain(rankSpell);
4744 }
4745 return nullptr;
4746}
4747
4748Aura* Unit::GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const
4749{
4750 AuraApplication * aurApp = GetAuraApplicationOfRankedSpell(spellId, casterGUID, itemCasterGUID, reqEffMask);
4751 return aurApp ? aurApp->GetBase() : nullptr;
4752}
4753
4754void Unit::GetDispellableAuraList(WorldObject const* caster, uint32 dispelMask, DispelChargesList& dispelList, bool isReflect /*= false*/) const
4755{
4756 AuraMap const& auras = GetOwnedAuras();
4757 for (auto itr = auras.begin(); itr != auras.end(); ++itr)
4758 {
4759 Aura* aura = itr->second;
4760 AuraApplication const* aurApp = aura->GetApplicationOfTarget(GetGUID());
4761 if (!aurApp)
4762 continue;
4763
4764 // don't try to remove passive auras
4765 if (aura->IsPassive())
4766 continue;
4767
4768 if (aura->GetSpellInfo()->GetDispelMask() & dispelMask)
4769 {
4770 // do not remove positive auras if friendly target
4771 // negative auras if non-friendly
4772 // unless we're reflecting (dispeller eliminates one of it's benefitial buffs)
4773 if (isReflect != (aurApp->IsPositive() == IsFriendlyTo(caster)))
4774 continue;
4775
4776 // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
4777 int32 chance = aura->CalcDispelChance(this, !IsFriendlyTo(caster));
4778 if (!chance)
4779 continue;
4780
4781 // The charges / stack amounts don't count towards the total number of auras that can be dispelled.
4782 // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
4783 // Polymorph instead of 1 / (5 + 1) -> 16%.
4784 bool const dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_REMOVES_CHARGES);
4785 uint8 charges = dispelCharges ? aura->GetCharges() : aura->GetStackAmount();
4786 if (charges > 0)
4787 dispelList.emplace_back(aura, chance, charges);
4788 }
4789 }
4790}
4791
4792bool Unit::HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster) const
4793{
4794 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4795 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4796 {
4797 if (itr->second->HasEffect(effIndex)
4798 && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
4799 {
4800 return true;
4801 }
4802 }
4803 return false;
4804}
4805
4807{
4808 uint32 count = 0;
4809 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4810
4811 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4812 {
4813 if (itr->second->GetBase()->GetStackAmount() == 0)
4814 ++count;
4815 else
4816 count += (uint32)itr->second->GetBase()->GetStackAmount();
4817 }
4818
4819 return count;
4820}
4821
4822bool Unit::HasAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const
4823{
4824 return GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask) != nullptr;
4825}
4826
4827bool Unit::HasAura(std::function<bool(Aura const*)> const& predicate) const
4828{
4829 return GetAuraApplication(predicate) != nullptr;
4830}
4831
4832bool Unit::HasAuraType(AuraType auraType) const
4833{
4834 return (!m_modAuras[auraType].empty());
4835}
4836
4838{
4839 for (AuraEffect const* eff : GetAuraEffectsByType(auraType))
4840 if (caster == eff->GetCasterGUID())
4841 return true;
4842 return false;
4843}
4844
4845bool Unit::HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscvalue) const
4846{
4847 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4848 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4849 if (miscvalue == (*i)->GetMiscValue())
4850 return true;
4851 return false;
4852}
4853
4854bool Unit::HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
4855{
4856 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4857 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4858 if ((*i)->IsAffectingSpell(affectedSpell))
4859 return true;
4860 return false;
4861}
4862
4863bool Unit::HasAuraTypeWithValue(AuraType auraType, int32 value) const
4864{
4865 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4866 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4867 if (value == (*i)->GetAmountAsInt())
4868 return true;
4869 return false;
4870}
4871
4872bool Unit::HasAuraTypeWithTriggerSpell(AuraType auratype, uint32 triggerSpell) const
4873{
4874 for (AuraEffect const* aura : GetAuraEffectsByType(auratype))
4875 if (aura->GetSpellEffectInfo().TriggerSpell == triggerSpell)
4876 return true;
4877 return false;
4878}
4879
4880template <typename InterruptFlags>
4881bool Unit::HasNegativeAuraWithInterruptFlag(InterruptFlags flag, ObjectGuid guid) const
4882{
4883 if (!HasInterruptFlag(flag))
4884 return false;
4885
4886 for (AuraApplicationList::const_iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end(); ++iter)
4887 if (!(*iter)->IsPositive() && (*iter)->GetBase()->GetSpellInfo()->HasAuraInterruptFlag(flag) &&
4888 (!guid || (*iter)->GetBase()->GetCasterGUID() == guid))
4889 return true;
4890
4891 return false;
4892}
4893
4896
4897bool Unit::HasAuraWithMechanic(uint64 mechanicMask) const
4898{
4899 for (AuraApplicationMap::const_iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end(); ++iter)
4900 {
4901 SpellInfo const* spellInfo = iter->second->GetBase()->GetSpellInfo();
4902 if (spellInfo->Mechanic && (mechanicMask & (UI64LIT(1) << spellInfo->Mechanic)))
4903 return true;
4904
4905 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
4906 if (iter->second->HasEffect(spellEffectInfo.EffectIndex) && spellEffectInfo.IsEffect() && spellEffectInfo.Mechanic)
4907 if (mechanicMask & (UI64LIT(1) << spellEffectInfo.Mechanic))
4908 return true;
4909 }
4910
4911 return false;
4912}
4913
4914bool Unit::HasStrongerAuraWithDR(SpellInfo const* auraSpellInfo, Unit* caster) const
4915{
4916 DiminishingGroup diminishGroup = auraSpellInfo->GetDiminishingReturnsGroupForSpell();
4917 DiminishingLevels level = GetDiminishing(diminishGroup);
4918 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
4919 {
4920 SpellInfo const* spellInfo = itr->second->GetBase()->GetSpellInfo();
4921 if (spellInfo->GetDiminishingReturnsGroupForSpell() != diminishGroup)
4922 continue;
4923
4924 int32 existingDuration = itr->second->GetBase()->GetDuration();
4925 int32 newDuration = auraSpellInfo->GetMaxDuration();
4926 ApplyDiminishingToDuration(auraSpellInfo, newDuration, caster, level);
4927 if (newDuration > 0 && newDuration < existingDuration)
4928 return true;
4929 }
4930
4931 return false;
4932}
4933
4935{
4937 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4938 {
4939 if ((*i)->GetMiscValue() == script)
4940 if ((*i)->IsAffectingSpell(spell))
4941 return (*i);
4942 }
4943 return nullptr;
4944}
4945
4947{
4948 static const AuraType diseaseAuraTypes[] =
4949 {
4950 SPELL_AURA_PERIODIC_DAMAGE, // Frost Fever and Blood Plague
4951 SPELL_AURA_LINKED // Crypt Fever and Ebon Plague
4952 };
4953
4954 uint32 diseases = 0;
4955 for (AuraType aType : diseaseAuraTypes)
4956 {
4957 for (auto itr = m_modAuras[aType].begin(); itr != m_modAuras[aType].end();)
4958 {
4959 // Get auras with disease dispel type by caster
4960 if ((*itr)->GetSpellInfo()->Dispel == DISPEL_DISEASE
4961 && (*itr)->GetCasterGUID() == casterGUID)
4962 {
4963 ++diseases;
4964
4965 if (remove)
4966 {
4967 RemoveAura((*itr)->GetId(), (*itr)->GetCasterGUID());
4968 itr = m_modAuras[aType].begin();
4969 continue;
4970 }
4971 }
4972 ++itr;
4973 }
4974 }
4975 return diseases;
4976}
4977
4979{
4980 static const AuraType diseaseAuraTypes[] =
4981 {
4985 };
4986
4987 uint32 dots = 0;
4988 for (AuraType const* itr = &diseaseAuraTypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr)
4989 {
4990 Unit::AuraEffectList const& auras = GetAuraEffectsByType(*itr);
4991 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4992 {
4993 // Get auras by caster
4994 if ((*i)->GetCasterGUID() == casterGUID)
4995 ++dots;
4996 }
4997 }
4998 return dots;
4999}
5000
5001float Unit::GetTotalAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
5002{
5003 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
5004 if (mTotalAuraList.empty())
5005 return 0.0f;
5006
5007 std::map<SpellGroup, SpellEffectValue> sameEffectSpellGroup;
5008 SpellEffectValue modifier = 0;
5009
5010 for (AuraEffect const* aurEff : mTotalAuraList)
5011 {
5012 if (predicate(aurEff))
5013 {
5014 // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
5015 // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
5016 if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), auraType, aurEff->GetAmount(), sameEffectSpellGroup))
5017 modifier += aurEff->GetAmount();
5018 }
5019 }
5020
5021 // Add the highest of the Same Effect Stack Rule SpellGroups to the accumulator
5022 for (auto itr = sameEffectSpellGroup.begin(); itr != sameEffectSpellGroup.end(); ++itr)
5023 modifier += itr->second;
5024
5025 return static_cast<float>(modifier);
5026}
5027
5028float Unit::GetTotalAuraMultiplier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
5029{
5030 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
5031 if (mTotalAuraList.empty())
5032 return 1.0f;
5033
5034 std::map<SpellGroup, SpellEffectValue> sameEffectSpellGroup;
5035 SpellEffectValue multiplier = 1.0;
5036
5037 for (AuraEffect const* aurEff : mTotalAuraList)
5038 {
5039 if (predicate(aurEff))
5040 {
5041 // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
5042 // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
5043 if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), auraType, aurEff->GetAmount(), sameEffectSpellGroup))
5044 AddPct(multiplier, aurEff->GetAmount());
5045 }
5046 }
5047
5048 // Add the highest of the Same Effect Stack Rule SpellGroups to the multiplier
5049 for (auto itr = sameEffectSpellGroup.begin(); itr != sameEffectSpellGroup.end(); ++itr)
5050 AddPct(multiplier, itr->second);
5051
5052 return static_cast<float>(multiplier);
5053}
5054
5055float Unit::GetMaxPositiveAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
5056{
5057 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
5058 if (mTotalAuraList.empty())
5059 return 0.0f;
5060
5061 SpellEffectValue modifier = 0;
5062 for (AuraEffect const* aurEff : mTotalAuraList)
5063 {
5064 if (predicate(aurEff))
5065 modifier = std::max(modifier, aurEff->GetAmount());
5066 }
5067
5068 return static_cast<float>(modifier);
5069}
5070
5071float Unit::GetMaxNegativeAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
5072{
5073 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
5074 if (mTotalAuraList.empty())
5075 return 0.0f;
5076
5077 SpellEffectValue modifier = 0;
5078 for (AuraEffect const* aurEff : mTotalAuraList)
5079 {
5080 if (predicate(aurEff))
5081 modifier = std::min(modifier, aurEff->GetAmount());
5082 }
5083
5084 return static_cast<float>(modifier);
5085}
5086
5088{
5089 return GetTotalAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
5090}
5091
5093{
5094 return GetTotalAuraMultiplier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
5095}
5096
5098{
5099 return GetMaxPositiveAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
5100}
5101
5103{
5104 return GetMaxNegativeAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
5105}
5106
5108{
5109 return GetTotalAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
5110 {
5111 if ((aurEff->GetMiscValue() & miscMask) != 0)
5112 return true;
5113 return false;
5114 });
5115}
5116
5118{
5119 return GetTotalAuraMultiplier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
5120 {
5121 if ((aurEff->GetMiscValue() & miscMask) != 0)
5122 return true;
5123 return false;
5124 });
5125}
5126
5127float Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auraType, uint32 miscMask, AuraEffect const* except /*= nullptr*/) const
5128{
5129 return GetMaxPositiveAuraModifier(auraType, [miscMask, except](AuraEffect const* aurEff) -> bool
5130 {
5131 if (except != aurEff && (aurEff->GetMiscValue() & miscMask) != 0)
5132 return true;
5133 return false;
5134 });
5135}
5136
5138{
5139 return GetMaxNegativeAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
5140 {
5141 if ((aurEff->GetMiscValue() & miscMask) != 0)
5142 return true;
5143 return false;
5144 });
5145}
5146
5148{
5149 return GetTotalAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5150 {
5151 if (aurEff->GetMiscValue() == miscValue)
5152 return true;
5153 return false;
5154 });
5155}
5156
5158{
5159 return GetTotalAuraMultiplier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5160 {
5161 if (aurEff->GetMiscValue() == miscValue)
5162 return true;
5163 return false;
5164 });
5165}
5166
5168{
5169 return GetMaxPositiveAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5170 {
5171 if (aurEff->GetMiscValue() == miscValue)
5172 return true;
5173 return false;
5174 });
5175}
5176
5178{
5179 return GetMaxNegativeAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5180 {
5181 if (aurEff->GetMiscValue() == miscValue)
5182 return true;
5183 return false;
5184 });
5185}
5186
5187float Unit::GetTotalAuraModifierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
5188{
5189 return GetTotalAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5190 {
5191 if (aurEff->IsAffectingSpell(affectedSpell))
5192 return true;
5193 return false;
5194 });
5195}
5196
5197float Unit::GetTotalAuraMultiplierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
5198{
5199 return GetTotalAuraMultiplier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5200 {
5201 if (aurEff->IsAffectingSpell(affectedSpell))
5202 return true;
5203 return false;
5204 });
5205}
5206
5207float Unit::GetMaxPositiveAuraModifierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
5208{
5209 return GetMaxPositiveAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5210 {
5211 if (aurEff->IsAffectingSpell(affectedSpell))
5212 return true;
5213 return false;
5214 });
5215}
5216
5217float Unit::GetMaxNegativeAuraModifierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
5218{
5219 return GetMaxNegativeAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5220 {
5221 if (aurEff->IsAffectingSpell(affectedSpell))
5222 return true;
5223 return false;
5224 });
5225}
5226
5228{
5229 for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
5230 {
5231 m_floatStatPosBuff[i] = 0.0f;
5232 m_floatStatNegBuff[i] = 0.0f;
5234 }
5235}
5236
5238{
5239 float modPos = 0.0f;
5240 float modNeg = 0.0f;
5241
5242 UnitMods const unitMod = static_cast<UnitMods>(UNIT_MOD_STAT_START + AsUnderlyingType(stat));
5243
5244 if (IsGuardian())
5245 {
5246 float modValue = static_cast<Guardian*>(this)->GetBonusStatFromOwner(stat);
5247 if (modValue > 0.f)
5248 modPos += modValue;
5249 else
5250 modNeg += modValue;
5251 }
5252
5253 modPos += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
5254 {
5255 if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() > 0)
5256 return true;
5257 return false;
5258 });
5259
5260 modNeg += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
5261 {
5262 if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() < 0)
5263 return true;
5264 return false;
5265 });
5266
5267 float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE);
5268 baseValue *= GetPctModifierValue(unitMod, BASE_PCT);
5269 baseValue *= GetPctModifierValue(unitMod, TOTAL_PCT);
5270 float baseModFromPct = baseValue - GetFlatModifierValue(unitMod, BASE_VALUE);
5271
5272 float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE);
5274 float totalModFromPct = totalValue * GetPctModifierValue(unitMod, TOTAL_PCT) - totalValue;
5275 float modsFromPct = baseModFromPct + totalModFromPct;
5276
5277 // recalculate stat bonuses not applied by auras
5278 float nonAuraMod = totalValue;
5279 nonAuraMod -= modPos; // remove positive auras
5280 nonAuraMod -= modNeg; // remove negative auras
5281
5282 // add item stat bonuses to positive
5283 if (nonAuraMod > 0.f)
5284 modPos += nonAuraMod;
5285 else
5286 modNeg += nonAuraMod;
5287
5288 // add pct mods
5289 if (modsFromPct > 0.f)
5290 modPos += modsFromPct;
5291 else
5292 modNeg += modsFromPct;
5293
5294 m_floatStatPosBuff[stat] = std::round(modPos);
5295 m_floatStatNegBuff[stat] = std::round(modNeg);
5296
5298}
5299
5305
5306void Unit::SetCreateStat(Stats stat, float val)
5307{
5308 UnitMods const unitMod = static_cast<UnitMods>(UNIT_MOD_STAT_START + AsUnderlyingType(stat));
5309 SetStatFlatModifier(unitMod, BASE_VALUE, val);
5310}
5311
5313{
5314 UnitMods const unitMod = static_cast<UnitMods>(UNIT_MOD_STAT_START + AsUnderlyingType(stat));
5315 return GetFlatModifierValue(unitMod, BASE_VALUE);
5316}
5317
5319{
5320 m_dynObj.push_back(dynObj);
5321 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5323}
5324
5326{
5327 std::erase(m_dynObj, dynObj);
5328 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5330}
5331
5333{
5334 std::vector<DynamicObject*> dynamicobjects = GetDynObjects(spellId);
5335 return dynamicobjects.empty() ? nullptr : dynamicobjects.front();
5336}
5337
5338std::vector<DynamicObject*> Unit::GetDynObjects(uint32 spellId) const
5339{
5340 std::vector<DynamicObject*> dynamicobjects;
5341 for (DynObjectList::const_iterator i = m_dynObj.begin(); i != m_dynObj.end(); ++i)
5342 if ((*i)->GetSpellId() == spellId)
5343 dynamicobjects.push_back(*i);
5344
5345 return dynamicobjects;
5346}
5347
5349{
5350 for (DynObjectList::iterator i = m_dynObj.begin(); i != m_dynObj.end();)
5351 {
5352 DynamicObject* dynObj = *i;
5353 if (dynObj->GetSpellId() == spellId)
5354 {
5355 dynObj->Remove();
5356 i = m_dynObj.begin();
5357 }
5358 else
5359 ++i;
5360 }
5361}
5362
5364{
5365 while (!m_dynObj.empty())
5366 m_dynObj.back()->Remove();
5367}
5368
5370{
5371 std::vector<GameObject*> gameobjects = GetGameObjects(spellId);
5372 return gameobjects.empty() ? nullptr : gameobjects.front();
5373}
5374
5375std::vector<GameObject*> Unit::GetGameObjects(uint32 spellId) const
5376{
5377 std::vector<GameObject*> gameobjects;
5378 for (GameObjectList::const_iterator i = m_gameObj.begin(); i != m_gameObj.end(); ++i)
5379 if ((*i)->GetSpellId() == spellId)
5380 gameobjects.push_back(*i);
5381
5382 return gameobjects;
5383}
5384
5386{
5387 if (!gameObj || !gameObj->GetOwnerGUID().IsEmpty())
5388 return;
5389
5390 m_gameObj.push_back(gameObj);
5391 gameObj->SetOwnerGUID(GetGUID());
5392
5393 if (gameObj->GetSpellId())
5394 {
5395 SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(gameObj->GetSpellId(), GetMap()->GetDifficultyID());
5396 // Need disable spell use for owner
5397 if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
5398 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
5399 GetSpellHistory()->StartCooldown(createBySpell, 0, nullptr, true);
5400 }
5401
5403 ToCreature()->AI()->JustSummonedGameobject(gameObj);
5404}
5405
5407{
5409
5410 auto objectSlotItr = std::ranges::find(m_ObjectSlot, gameObj->GetGUID());
5411 if (objectSlotItr != std::ranges::end(m_ObjectSlot))
5412 objectSlotItr->Clear();
5413
5414 // GO created by some spell
5415 if (uint32 spellid = gameObj->GetSpellId())
5416 {
5417 RemoveAurasDueToSpell(spellid);
5418
5419 SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid, GetMap()->GetDifficultyID());
5420 // Need activate spell use for owner
5421 if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
5422 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
5423 GetSpellHistory()->SendCooldownEvent(createBySpell);
5424 }
5425
5428
5429 if (del)
5430 {
5431 gameObj->SetRespawnTime(0);
5432 gameObj->Delete();
5433 }
5434}
5435
5436void Unit::RemoveGameObject(GameObject* gameObj, bool del)
5437{
5438 if (!gameObj || gameObj->GetOwnerGUID() != GetGUID())
5439 return;
5440
5441 RemoveGameObjectImpl(gameObj, del);
5442
5443 m_gameObj.remove(gameObj);
5444}
5445
5446void Unit::RemoveGameObject(uint32 spellid, bool del)
5447{
5448 if (m_gameObj.empty())
5449 return;
5450
5451 for (auto i = m_gameObj.begin(); i != m_gameObj.end(); )
5452 {
5453 if (spellid == 0 || (*i)->GetSpellId() == spellid)
5454 {
5455 RemoveGameObjectImpl(*i, del);
5456 i = m_gameObj.erase(i);
5457 }
5458 else
5459 ++i;
5460 }
5461}
5462
5464{
5465 // remove references to unit
5466 while (!m_gameObj.empty())
5467 {
5468 GameObject* gameObj = m_gameObj.front();
5469 m_gameObj.pop_front();
5470 RemoveGameObjectImpl(gameObj, true);
5471 }
5472}
5473
5475{
5476 m_areaTrigger.push_back(areaTrigger);
5477 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5478 ToCreature()->AI()->JustRegisteredAreaTrigger(areaTrigger);
5479}
5480
5482{
5483 std::erase(m_areaTrigger, areaTrigger);
5484 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5485 ToCreature()->AI()->JustUnregisteredAreaTrigger(areaTrigger);
5486}
5487
5489{
5490 std::vector<AreaTrigger*> areaTriggers = GetAreaTriggers(spellId);
5491 return areaTriggers.empty() ? nullptr : areaTriggers.front();
5492}
5493
5494std::vector<AreaTrigger*> Unit::GetAreaTriggers(uint32 spellId) const
5495{
5496 std::vector<AreaTrigger*> areaTriggers;
5497 for (AreaTriggerList::const_iterator i = m_areaTrigger.begin(); i != m_areaTrigger.end(); ++i)
5498 if ((*i)->GetSpellId() == spellId)
5499 areaTriggers.push_back(*i);
5500
5501 return areaTriggers;
5502}
5503
5505{
5506 for (AreaTriggerList::iterator i = m_areaTrigger.begin(); i != m_areaTrigger.end();)
5507 {
5508 AreaTrigger* areaTrigger = *i;
5509 if (areaTrigger->GetSpellId() == spellId)
5510 {
5511 areaTrigger->Remove();
5512 i = m_areaTrigger.begin();
5513 }
5514 else
5515 ++i;
5516 }
5517}
5518
5520{
5521 for (AreaTrigger* areaTrigger : m_areaTrigger)
5522 {
5523 if (areaTrigger->GetAuraEffect() == aurEff)
5524 {
5525 areaTrigger->Remove();
5526 break; // There can only be one AreaTrigger per AuraEffect
5527 }
5528 }
5529}
5530
5531void Unit::RemoveAllAreaTriggers(AreaTriggerRemoveReason reason /*= AreaTriggerRemoveReason::Default*/)
5532{
5533 for (AreaTrigger* at : AreaTriggerList(std::move(m_areaTrigger)))
5534 {
5535 if (reason == AreaTriggerRemoveReason::UnitDespawn && at->GetTemplate()->ActionSetFlags.HasFlag(AreaTriggerActionSetFlag::DontDespawnWithCreator))
5536 continue;
5537
5538 at->Remove();
5539 }
5540}
5541
5543{
5544 m_insideAreaTriggers.push_back(areaTrigger);
5545}
5546
5548{
5549 std::erase(m_insideAreaTriggers, areaTrigger);
5550}
5551
5553{
5554 AreaTriggerList atList = std::move(m_insideAreaTriggers);
5555 for (AreaTrigger* at : atList)
5556 at->HandleUnitExit(this);
5557}
5558
5560{
5562 packet.Me = log->target->GetGUID();
5563 packet.CasterGUID = Object::GetGUID(log->attacker);
5564 packet.CastID = log->castId;
5565 packet.SpellID = log->Spell ? log->Spell->Id : 0;
5566 packet.Visual = log->SpellVisual;
5567 packet.Damage = log->damage;
5568 packet.OriginalDamage = log->originalDamage;
5569 if (log->damage > log->preHitHealth)
5570 packet.Overkill = log->damage - log->preHitHealth;
5571 else
5572 packet.Overkill = -1;
5573
5574 packet.SchoolMask = log->schoolMask;
5575 packet.Absorbed = log->absorb;
5576 packet.Resisted = log->resist;
5577 packet.ShieldBlock = log->blocked;
5579 packet.Periodic = log->periodicLog;
5580 packet.Flags = log->HitInfo;
5581
5583 if (contentTuningParams.GenerateDataForUnits(log->attacker, log->target))
5584 packet.ContentTuning = contentTuningParams;
5585
5586 SendCombatLogMessage(&packet);
5587}
5588
5589/*static*/ void Unit::ProcSkillsAndAuras(Unit* actor, Unit* actionTarget, ProcFlagsInit const& typeMaskActor, ProcFlagsInit const& typeMaskActionTarget,
5590 ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask,
5591 Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
5592{
5593 static constexpr int32 ProcChainHardLimit = 10;
5594 if (spell && spell->GetProcChainLength() >= ProcChainHardLimit)
5595 {
5596 TC_LOG_ERROR("spells.aura.effect", "Unit::ProcSkillsAndAuras: Possible infinite proc loop detected, current triggering spell {}", spell->GetDebugInfo().c_str());
5597 return;
5598 }
5599
5600 WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK;
5601 SpellInfo const* spellInfo = [&]() -> SpellInfo const*
5602 {
5603 if (spell)
5604 return spell->GetSpellInfo();
5605 if (damageInfo)
5606 return damageInfo->GetSpellInfo();
5607 if (healInfo)
5608 return healInfo->GetSpellInfo();
5609 return nullptr;
5610 }();
5611 if (typeMaskActor && actor && !(spellInfo && spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_CASTER_PROCS)))
5612 actor->ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
5613
5614 if (typeMaskActionTarget && actionTarget && !(spellInfo && spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS)))
5615 actionTarget->ProcSkillsAndReactives(true, actor, typeMaskActionTarget, hitMask, attType);
5616
5617 if (actor)
5618 actor->TriggerAurasProcOnEvent(nullptr, nullptr, actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
5619}
5620
5622{
5623 AuraEffect const* aura = info->auraEff;
5625 data.TargetGUID = GetGUID();
5626 data.CasterGUID = aura->GetCasterGUID();
5627 data.SpellID = aura->GetId();
5628 data.LogData.Initialize(this);
5629
5630 WorldPackets::CombatLog::PeriodicAuraLogEffect& spellLogEffect = data.Effects.emplace_back();
5631 spellLogEffect.Effect = aura->GetAuraType();
5632 spellLogEffect.Amount = info->damage;
5633 spellLogEffect.OriginalDamage = info->originalDamage;
5634 spellLogEffect.OverHealOrKill = info->overDamage;
5635 spellLogEffect.SchoolMaskOrPower = aura->GetSpellInfo()->GetSchoolMask();
5636 spellLogEffect.AbsorbedOrAmplitude = info->absorb;
5637 spellLogEffect.Resisted = info->resist;
5638 spellLogEffect.Crit = info->critical;
5640
5642 if (Unit* caster = ObjectAccessor::GetUnit(*this, aura->GetCasterGUID()))
5643 if (contentTuningParams.GenerateDataForUnits(caster, this))
5644 spellLogEffect.ContentTuning = contentTuningParams;
5645
5646 SendCombatLogMessage(&data);
5647}
5648
5650{
5652 procResist.Caster = GetGUID();
5653 procResist.SpellID = spellId;
5654 procResist.Target = target->GetGUID();
5655 SendMessageToSet(procResist.Write(), true);
5656}
5657
5658void Unit::SendSpellDamageImmune(Unit* target, uint32 spellId, bool isPeriodic)
5659{
5661 spellOrDamageImmune.CasterGUID = GetGUID();
5662 spellOrDamageImmune.VictimGUID = target->GetGUID();
5663 spellOrDamageImmune.SpellID = spellId;
5664 spellOrDamageImmune.IsPeriodic = isPeriodic;
5665 SendMessageToSet(spellOrDamageImmune.Write(), true);
5666}
5667
5669{
5671 packet.Flags = damageInfo->HitInfo;
5672 packet.AttackerGUID = damageInfo->Attacker->GetGUID();
5673 packet.VictimGUID = damageInfo->Target->GetGUID();
5674 packet.Damage = damageInfo->Damage;
5675 packet.OriginalDamage = damageInfo->OriginalDamage;
5676 int32 overkill = damageInfo->Damage - damageInfo->Target->GetHealth();
5677 packet.OverDamage = (overkill < 0 ? -1 : overkill);
5678
5679 packet.SubDmg.emplace();
5680 packet.SubDmg->SchoolMask = damageInfo->DamageSchoolMask; // School of sub damage
5681 packet.SubDmg->FDamage = damageInfo->Damage; // sub damage
5682 packet.SubDmg->Damage = damageInfo->Damage; // Sub Damage
5683 packet.SubDmg->Absorbed = damageInfo->Absorb;
5684 packet.SubDmg->Resisted = damageInfo->Resist;
5685
5686 packet.VictimState = damageInfo->TargetState;
5687 packet.BlockAmount = damageInfo->Blocked;
5688 packet.RageGained = damageInfo->RageGained;
5689
5690 packet.LogData.Initialize(damageInfo->Attacker);
5691
5693 if (contentTuningParams.GenerateDataForUnits(damageInfo->Attacker, damageInfo->Target))
5694 packet.ContentTuning = contentTuningParams;
5695
5696 SendCombatLogMessage(&packet);
5697}
5698
5699void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType*/, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount, uint32 RageGained)
5700{
5701 CalcDamageInfo dmgInfo;
5702 dmgInfo.HitInfo = HitInfo;
5703 dmgInfo.Attacker = this;
5704 dmgInfo.Target = target;
5705 dmgInfo.Damage = Damage - AbsorbDamage - Resist - BlockedAmount;
5706 dmgInfo.OriginalDamage = Damage;
5707 dmgInfo.DamageSchoolMask = damageSchoolMask;
5708 dmgInfo.Absorb = AbsorbDamage;
5709 dmgInfo.Resist = Resist;
5710 dmgInfo.TargetState = TargetState;
5711 dmgInfo.Blocked = BlockedAmount;
5712 dmgInfo.RageGained = RageGained;
5713 SendAttackStateUpdate(&dmgInfo);
5714}
5715
5716void Unit::SetPowerType(Powers power, bool sendUpdate/* = true*/, bool onInit /*= false*/)
5717{
5718 if (!onInit && GetPowerType() == power)
5719 return;
5720
5721 PowerTypeEntry const* powerTypeEntry = sDB2Manager.GetPowerTypeEntry(power);
5722 if (!powerTypeEntry)
5723 return;
5724
5725 if (IsCreature() && !powerTypeEntry->GetFlags().HasFlag(PowerTypeFlags::IsUsedByNPCs))
5726 return;
5727
5729
5730 // Update max power
5731 UpdateMaxPower(power);
5732
5733 // Update current power
5734 if (!onInit)
5735 {
5736 switch (power)
5737 {
5738 case POWER_MANA: // Keep the same (druid form switching...)
5739 case POWER_ENERGY:
5740 break;
5741 case POWER_RAGE: // Reset to zero
5742 SetPower(POWER_RAGE, 0);
5743 break;
5744 case POWER_FOCUS: // Make it full
5745 SetFullPower(power);
5746 break;
5747 default:
5748 break;
5749 }
5750 }
5751 else
5752 SetInitialPowerValue(power);
5753
5754 if (!sendUpdate)
5755 return;
5756
5757 if (Player* thisPlayer = ToPlayer())
5758 {
5759 if (thisPlayer->GetGroup())
5760 thisPlayer->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE);
5761 }
5762 /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x
5763 {
5764 if (pet->isControlled())
5765 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE);
5766 }*/
5767}
5768
5770{
5771 PowerTypeEntry const* powerTypeEntry = sDB2Manager.GetPowerTypeEntry(powerType);
5772 if (!powerTypeEntry)
5773 return;
5774
5775 if (powerTypeEntry->GetFlags().HasFlag(PowerTypeFlags::UnitsUseDefaultPowerOnInit))
5776 SetPower(powerType, powerTypeEntry->DefaultPower);
5777 else
5778 SetFullPower(powerType);
5779}
5780
5782{
5783 Powers displayPower = POWER_MANA;
5784 switch (GetShapeshiftForm())
5785 {
5786 case FORM_GHOUL:
5787 case FORM_CAT_FORM:
5788 displayPower = POWER_ENERGY;
5789 break;
5790 case FORM_BEAR_FORM:
5792 displayPower = POWER_RAGE;
5793 break;
5794 case FORM_TRAVEL_FORM:
5795 case FORM_GHOST_WOLF:
5796 displayPower = POWER_MANA;
5797 break;
5798 default:
5799 {
5801 if (!powerTypeAuras.empty())
5802 {
5803 AuraEffect const* powerTypeAura = powerTypeAuras.front();
5804 displayPower = Powers(powerTypeAura->GetMiscValue());
5805 }
5806 else
5807 {
5808 ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(GetClass());
5809 if (cEntry && cEntry->DisplayPower < MAX_POWERS)
5810 displayPower = Powers(cEntry->DisplayPower);
5811
5812 if (Vehicle* vehicle = GetVehicleKit())
5813 {
5814 if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(vehicle->GetVehicleInfo()->PowerDisplayID[0]))
5815 displayPower = Powers(powerDisplay->ActualType);
5816 }
5817 else if (IsHunterPet())
5818 displayPower = POWER_FOCUS;
5819 }
5820 break;
5821 }
5822 }
5823
5824 return displayPower;
5825}
5826
5831
5838
5839void Unit::_addAttacker(Unit* pAttacker)
5840{
5841 m_attackers.insert(pAttacker);
5842}
5843
5845{
5846 m_attackers.erase(pAttacker);
5847}
5848
5849Unit* Unit::getAttackerForHelper() const // If someone wants to help, who to give them
5850{
5851 if (!IsEngaged())
5852 return nullptr;
5853
5854 if (Unit* victim = GetVictim())
5855 if ((!IsPet() && !GetPlayerMovingMe()) || IsInCombatWith(victim))
5856 return victim;
5857
5858 CombatManager const& mgr = GetCombatManager();
5859 // pick arbitrary targets; our pvp combat > owner's pvp combat > our pve combat > owner's pve combat
5860 Unit* owner = GetCharmerOrOwner();
5861 if (mgr.HasPvPCombat())
5862 return mgr.GetPvPCombatRefs().begin()->second->GetOther(this);
5863 if (owner && (owner->GetCombatManager().HasPvPCombat()))
5864 return owner->GetCombatManager().GetPvPCombatRefs().begin()->second->GetOther(owner);
5865 if (mgr.HasPvECombat())
5866 return mgr.GetPvECombatRefs().begin()->second->GetOther(this);
5867 if (owner && (owner->GetCombatManager().HasPvECombat()))
5868 return owner->GetCombatManager().GetPvECombatRefs().begin()->second->GetOther(owner);
5869 return nullptr;
5870}
5871
5872bool Unit::Attack(Unit* victim, bool meleeAttack)
5873{
5874 if (!victim || victim == this)
5875 return false;
5876
5877 // dead units can neither attack nor be attacked
5878 if (!IsAlive() || !victim->IsInWorld() || !victim->IsAlive())
5879 return false;
5880
5881 // player cannot attack in mount state
5882 if (GetTypeId() == TYPEID_PLAYER && IsMounted())
5883 return false;
5884
5885 Creature* creature = ToCreature();
5886 // creatures cannot attack while evading
5887 if (creature && creature->IsInEvadeMode())
5888 return false;
5889
5890 // nobody can attack GM in GM-mode
5891 if (victim->GetTypeId() == TYPEID_PLAYER)
5892 {
5893 if (victim->ToPlayer()->IsGameMaster())
5894 return false;
5895 }
5896 else
5897 {
5898 if (victim->ToCreature()->IsEvadingAttacks())
5899 return false;
5900 }
5901
5902 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
5905
5906 if (m_attacking)
5907 {
5908 if (m_attacking == victim)
5909 {
5910 // switch to melee attack from ranged/magic
5911 if (meleeAttack)
5912 {
5914 {
5916 SendMeleeAttackStart(victim);
5917 return true;
5918 }
5919 }
5921 {
5923 SendMeleeAttackStop(victim);
5924 return true;
5925 }
5926 return false;
5927 }
5928
5929 // switch target
5931 if (!meleeAttack)
5933 }
5934
5935 if (m_attacking)
5937
5938 m_attacking = victim;
5941
5942 // Set our target
5943 SetTarget(victim->GetGUID());
5944
5945 if (meleeAttack)
5947
5948 // set position before any AI calls/assistance
5949 //if (GetTypeId() == TYPEID_UNIT)
5950 // ToCreature()->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
5951
5952 if (creature && !IsControlledByPlayer())
5953 {
5954 EngageWithTarget(victim); // ensure that anything we're attacking has threat
5955
5957 creature->CallAssistance();
5958
5959 // Remove emote and stand state - will be restored on creature reset
5962 }
5963
5964 // delay offhand weapon attack by 50% of the base attack time
5967
5968 if (meleeAttack)
5969 SendMeleeAttackStart(victim);
5970
5971 // Let the pet know we've started attacking someting. Handles melee attacks only
5972 // Spells such as auto-shot and others handled in WorldSession::HandleCastSpellOpcode
5973 if (GetTypeId() == TYPEID_PLAYER)
5974 {
5975 for (Unit* controlled : m_Controlled)
5976 if (Creature* cControlled = controlled->ToCreature())
5977 if (CreatureAI* controlledAI = cControlled->AI())
5978 controlledAI->OwnerAttacked(victim);
5979 }
5980
5981 return true;
5982}
5983
5985{
5986 if (!m_attacking)
5987 return false;
5988
5989 Unit* victim = m_attacking;
5990
5991 m_updateFlag.CombatVictim = false;
5993 m_attacking = nullptr;
5994
5995 // Clear our target
5997
5999
6001
6002 // reset only at real combat stop
6003 if (Creature* creature = ToCreature())
6004 {
6005 creature->SetNoCallAssistance(false);
6006 }
6007
6008 SendMeleeAttackStop(victim);
6009
6010 return true;
6011}
6012
6014{
6015 // iterate attackers
6016 UnitVector toRemove;
6017 AttackerSet const& attackers = getAttackers();
6018 for (Unit* attacker : attackers)
6019 if (!attacker->IsValidAttackTarget(this))
6020 toRemove.push_back(attacker);
6021
6022 for (Unit* attacker : toRemove)
6023 attacker->AttackStop();
6024
6025 // remove our own victim
6026 if (Unit* victim = GetVictim())
6027 if (!IsValidAttackTarget(victim))
6028 AttackStop();
6029}
6030
6031void Unit::CombatStop(bool includingCast, bool mutualPvP, bool (*unitFilter)(Unit const* otherUnit))
6032{
6033 if (includingCast && IsNonMeleeSpellCast(false))
6035
6036 AttackStop();
6037 if (!unitFilter)
6039 else
6040 {
6041 std::vector<Unit*> attackersToRemove;
6042 attackersToRemove.reserve(m_attackers.size());
6043 std::copy_if(m_attackers.begin(), m_attackers.end(), std::back_inserter(attackersToRemove), unitFilter);
6044
6045 for (Unit* attacker : attackersToRemove)
6046 attacker->AttackStop();
6047 }
6048
6049 if (GetTypeId() == TYPEID_PLAYER)
6050 ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
6051
6052 m_combatManager.EndAllPvECombat(unitFilter);
6053 if (mutualPvP)
6054 m_combatManager.EndAllPvPCombat(unitFilter);
6055 else // vanish and brethren are weird
6057}
6058
6059void Unit::CombatStopWithPets(bool includingCast)
6060{
6061 CombatStop(includingCast);
6062
6063 for (Unit* minion : m_Controlled)
6064 minion->CombatStop(includingCast);
6065}
6066
6068{
6070 return true;
6071
6072 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
6073 if ((*itr)->isAttackingPlayer())
6074 return true;
6075
6076 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
6077 if (!m_SummonSlot[i].IsEmpty())
6078 if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
6079 if (summon->isAttackingPlayer())
6080 return true;
6081
6082 return false;
6083}
6084
6086{
6087 while (!m_attackers.empty())
6088 {
6089 AttackerSet::iterator iter = m_attackers.begin();
6090 if (!(*iter)->AttackStop())
6091 {
6092 TC_LOG_ERROR("entities.unit", "WORLD: Unit has an attacker that isn't attacking it!");
6093 m_attackers.erase(iter);
6094 }
6095 }
6096}
6097
6099{
6100 uint32 mask = 1 << (flag - 1);
6101 if (apply)
6102 {
6103 if (!(*m_unitData->AuraState & mask))
6104 {
6106 if (GetTypeId() == TYPEID_PLAYER)
6107 {
6108 PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap();
6109 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
6110 {
6111 if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
6112 continue;
6113 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE);
6114 if (!spellInfo || !spellInfo->IsPassive())
6115 continue;
6116 if (spellInfo->CasterAuraState == uint32(flag))
6117 CastSpell(this, itr->first, true);
6118 }
6119 }
6120 else if (Pet* pet = ToCreature()->ToPet())
6121 {
6122 for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
6123 {
6124 if (itr->second.state == PETSPELL_REMOVED)
6125 continue;
6126 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE);
6127 if (!spellInfo || !spellInfo->IsPassive())
6128 continue;
6129 if (spellInfo->CasterAuraState == uint32(flag))
6130 CastSpell(this, itr->first, true);
6131 }
6132 }
6133 }
6134 }
6135 else
6136 {
6137 if (*m_unitData->AuraState & mask)
6138 {
6140
6142 for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
6143 {
6144 SpellInfo const* spellProto = itr->second->GetBase()->GetSpellInfo();
6145 if (itr->second->GetBase()->GetCasterGUID() == GetGUID() && spellProto->CasterAuraState == uint32(flag) && (spellProto->IsPassive() || flag != AURA_STATE_ENRAGED))
6146 RemoveAura(itr);
6147 else
6148 ++itr;
6149 }
6150 }
6151 }
6152}
6153
6155{
6156 uint32 auraStates = *m_unitData->AuraState & ~(PER_CASTER_AURA_STATE_MASK);
6157 for (AuraStateAurasMap::const_iterator itr = m_auraStateAuras.begin(); itr != m_auraStateAuras.end(); ++itr)
6158 if ((1 << (itr->first - 1)) & PER_CASTER_AURA_STATE_MASK)
6159 if (itr->second->GetBase()->GetCasterGUID() == target->GetGUID())
6160 auraStates |= (1 << (itr->first - 1));
6161
6162 return auraStates;
6163}
6164
6165bool Unit::HasAuraState(AuraStateType flag, SpellInfo const* spellProto, Unit const* Caster) const
6166{
6167 if (Caster)
6168 {
6169 if (spellProto)
6170 {
6171 if (Caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_IGNORE_AURASTATE, spellProto))
6172 return true;
6173 }
6174
6175 // Check per caster aura state
6176 // If aura with aurastate by caster not found return false
6177 if ((1 << (flag - 1)) & PER_CASTER_AURA_STATE_MASK)
6178 {
6179 AuraStateAurasMapBounds range = m_auraStateAuras.equal_range(flag);
6180 for (AuraStateAurasMap::const_iterator itr = range.first; itr != range.second; ++itr)
6181 if (itr->second->GetBase()->GetCasterGUID() == Caster->GetGUID())
6182 return true;
6183 return false;
6184 }
6185 }
6186
6187 return (*m_unitData->AuraState & (1 << (flag - 1))) != 0;
6188}
6189
6191{
6192 if (GetOwnerGUID() == owner)
6193 return;
6194
6196 if (!owner)
6197 return;
6198
6199 // Update owner dependent fields
6200 Player* player = ObjectAccessor::GetPlayer(*this, owner);
6201 if (!player || !player->HaveAtClient(this)) // if player cannot see this unit yet, he will receive needed data with create object
6202 return;
6203
6204 UpdateData udata(GetMapId());
6205 WorldPacket packet;
6207 udata.BuildPacket(&packet);
6208 player->SendDirectMessage(&packet);
6209}
6210
6212{
6214}
6215
6220
6222{
6224 if (!guid.IsEmpty())
6225 {
6226 if (Unit* master = ObjectAccessor::GetUnit(*this, guid))
6227 return master->GetControllingPlayer();
6228 return nullptr;
6229 }
6230 else
6231 return const_cast<Player*>(ToPlayer());
6232}
6233
6235{
6236 ObjectGuid pet_guid = GetMinionGUID();
6237 if (!pet_guid.IsEmpty())
6238 {
6239 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
6240 if (pet->HasUnitTypeMask(UNIT_MASK_MINION))
6241 return (Minion*)pet;
6242
6243 TC_LOG_ERROR("entities.unit", "Unit::GetFirstMinion: Minion {} not exist.", pet_guid.ToString());
6244 const_cast<Unit*>(this)->SetMinionGUID(ObjectGuid::Empty);
6245 }
6246
6247 return nullptr;
6248}
6249
6251{
6252 ObjectGuid pet_guid = GetPetGUID();
6253 if (!pet_guid.IsEmpty())
6254 {
6255 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
6256 if (pet->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
6257 return (Guardian*)pet;
6258
6259 TC_LOG_FATAL("entities.unit", "Unit::GetGuardianPet: Guardian {} not exist.", pet_guid.ToString());
6260 const_cast<Unit*>(this)->SetPetGUID(ObjectGuid::Empty);
6261 }
6262
6263 return nullptr;
6264}
6265
6266void Unit::SetMinion(Minion *minion, bool apply)
6267{
6268 TC_LOG_DEBUG("entities.unit", "SetMinion {} for {}, apply {}", minion->GetEntry(), GetEntry(), apply);
6269
6270 if (apply)
6271 {
6272 if (!minion->GetOwnerGUID().IsEmpty())
6273 {
6274 TC_LOG_FATAL("entities.unit", "SetMinion: Minion {} is not the minion of owner {}", minion->GetEntry(), GetEntry());
6275 return;
6276 }
6277
6278 if (!IsInWorld())
6279 {
6280 TC_LOG_FATAL("entities.unit", "SetMinion: Minion being added to owner not in world. Minion: {}, Owner: {}", minion->GetGUID().ToString(), GetDebugInfo());
6281 return;
6282 }
6283
6284 minion->SetOwnerGUID(GetGUID());
6285
6286 m_Controlled.insert(minion);
6287
6288 if (GetTypeId() == TYPEID_PLAYER)
6289 {
6290 minion->m_ControlledByPlayer = true;
6292 }
6293
6294 // Can only have one pet. If a new one is summoned, dismiss the old one.
6295 if (minion->IsGuardianPet())
6296 {
6297 if (Guardian* oldPet = GetGuardianPet())
6298 {
6299 if (oldPet != minion && (oldPet->IsPet() || minion->IsPet() || oldPet->GetEntry() != minion->GetEntry()))
6300 {
6301 // remove existing minion pet
6302 if (Pet* oldPetAsPet = oldPet->ToPet())
6303 oldPetAsPet->Remove(PET_SAVE_NOT_IN_SLOT);
6304 else
6305 oldPet->UnSummon();
6306 SetPetGUID(minion->GetGUID());
6308 }
6309 }
6310 else
6311 {
6312 SetPetGUID(minion->GetGUID());
6314 }
6315 }
6316
6318 {
6319 if (GetMinionGUID().IsEmpty())
6320 SetMinionGUID(minion->GetGUID());
6321 }
6322
6323 SummonPropertiesEntry const* properties = minion->m_Properties;
6324 if (properties && SummonTitle(properties->Title) == SummonTitle::Companion)
6325 {
6326 SetCritterGUID(minion->GetGUID());
6327 if (Player const* thisPlayer = ToPlayer())
6328 {
6330 {
6331 if (BattlePets::BattlePet const* pet = thisPlayer->GetSession()->GetBattlePetMgr()->GetPet(thisPlayer->GetSummonedBattlePetGUID()))
6332 {
6333 minion->SetBattlePetCompanionGUID(thisPlayer->GetSummonedBattlePetGUID());
6334 minion->SetBattlePetCompanionNameTimestamp(pet->NameTimestamp);
6335 minion->SetWildBattlePetLevel(pet->PacketInfo.Level);
6336
6337 if (uint32 display = pet->PacketInfo.DisplayID)
6338 minion->SetDisplayId(display, true);
6339 }
6340 }
6341 }
6342 }
6343
6344 // PvP, FFAPvP
6346
6347 // FIXME: hack, speed must be set only at follow
6348 if (GetTypeId() == TYPEID_PLAYER && minion->IsPet())
6349 for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
6350 minion->SetSpeedRate(UnitMoveType(i), m_speed_rate[i]);
6351
6352 // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
6353 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->m_unitData->CreatedBySpell, DIFFICULTY_NONE);
6354
6355 if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
6356 GetSpellHistory()->StartCooldown(spellInfo, 0, nullptr, true);
6357 }
6358 else
6359 {
6360 if (minion->GetOwnerGUID() != GetGUID())
6361 {
6362 TC_LOG_FATAL("entities.unit", "SetMinion: Minion {} is not the minion of owner {}", minion->GetEntry(), GetEntry());
6363 return;
6364 }
6365
6366 m_Controlled.erase(minion);
6367
6369 if (GetCritterGUID() == minion->GetGUID())
6371
6372 if (minion->IsGuardianPet())
6373 {
6374 if (GetPetGUID() == minion->GetGUID())
6376 }
6377 else if (minion->IsTotem())
6378 {
6379 // All summoned by totem minions must disappear when it is removed.
6380 if (SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(minion->ToTotem()->GetSpell(), DIFFICULTY_NONE))
6381 {
6382 for (SpellEffectInfo const& spellEffectInfo : spInfo->GetEffects())
6383 {
6384 if (!spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON))
6385 continue;
6386
6387 RemoveAllMinionsByEntry(spellEffectInfo.MiscValue);
6388 }
6389 }
6390 }
6391
6392 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->m_unitData->CreatedBySpell, DIFFICULTY_NONE);
6393 // Remove infinity cooldown
6394 if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
6395 GetSpellHistory()->SendCooldownEvent(spellInfo);
6396
6397 //if (minion->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
6398 {
6399 if (GetMinionGUID() == minion->GetGUID())
6400 {
6402 // Check if there is another minion
6403 for (ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
6404 {
6405 // do not use this check, creature do not have charm guid
6406 //if (GetCharmedGUID() == (*itr)->GetGUID())
6407 if (GetGUID() == (*itr)->GetCharmerGUID())
6408 continue;
6409
6410 //ASSERT((*itr)->GetOwnerGUID() == GetGUID());
6411 if ((*itr)->GetOwnerGUID() != GetGUID())
6412 {
6413 OutDebugInfo();
6414 (*itr)->OutDebugInfo();
6415 ABORT();
6416 }
6417 ASSERT((*itr)->GetTypeId() == TYPEID_UNIT);
6418
6419 if (!(*itr)->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
6420 continue;
6421
6422 SetMinionGUID((*itr)->GetGUID());
6423 // show another pet bar if there is no charm bar
6424 if (GetTypeId() == TYPEID_PLAYER && !GetCharmedGUID())
6425 {
6426 if ((*itr)->IsPet())
6428 else
6430 }
6431 break;
6432 }
6433 }
6434 }
6435 }
6437}
6438
6439void Unit::GetAllMinionsByEntry(std::list<TempSummon*>& Minions, uint32 entry)
6440{
6441 for (Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
6442 {
6443 Unit* unit = *itr;
6444 if (unit->GetEntry() == entry && unit->IsSummon()) // minion, actually
6445 Minions.push_back(unit->ToTempSummon());
6446 }
6447}
6448
6450{
6451 for (Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end();)
6452 {
6453 Unit* unit = *itr;
6454 ++itr;
6455 if (unit->GetEntry() == entry && unit->GetTypeId() == TYPEID_UNIT
6456 && unit->ToCreature()->IsSummon()) // minion, actually
6457 unit->ToTempSummon()->UnSummon();
6458 // i think this is safe because i have never heard that a despawned minion will trigger a same minion
6459 }
6460}
6461
6462void Unit::SetCharm(Unit* charm, bool apply)
6463{
6464 if (apply)
6465 {
6466 if (GetTypeId() == TYPEID_PLAYER)
6467 {
6468 ASSERT(GetCharmedGUID().IsEmpty(),
6469 "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());
6471 m_charmed = charm;
6472
6473 charm->m_ControlledByPlayer = true;
6476 }
6477 else
6478 charm->m_ControlledByPlayer = false;
6479
6480 // PvP, FFAPvP
6482
6483 ASSERT(charm->GetCharmerGUID().IsEmpty(),
6484 "Unit %u is being charmed, but it already has a charmer %s", charm->GetEntry(), charm->GetCharmerGUID().ToString().c_str());
6486 charm->m_charmer = this;
6487
6490 charm->SetWalk(false);
6491
6492 m_Controlled.insert(charm);
6493 }
6494 else
6495 {
6497
6498 if (GetTypeId() == TYPEID_PLAYER)
6499 {
6500 ASSERT(GetCharmedGUID() == charm->GetGUID(),
6501 "Player %s is trying to uncharm unit %u, but it has another charmed unit %s", GetName().c_str(), charm->GetEntry(), GetCharmedGUID().ToString().c_str());
6503 m_charmed = nullptr;
6504 }
6505
6506 ASSERT(charm->GetCharmerGUID() == GetGUID(),
6507 "Unit %u is being uncharmed, but it has another charmer %s", charm->GetEntry(), charm->GetCharmerGUID().ToString().c_str());
6509 charm->m_charmer = nullptr;
6510
6511 if (charm->GetTypeId() == TYPEID_PLAYER)
6512 {
6513 charm->m_ControlledByPlayer = true;
6515 charm->ToPlayer()->UpdatePvPState();
6516 }
6517 else if (Player* player = charm->GetCharmerOrOwnerPlayerOrPlayerItself())
6518 {
6519 charm->m_ControlledByPlayer = true;
6521 charm->ReplaceAllPvpFlags(player->GetPvpFlags());
6522 }
6523 else
6524 {
6525 charm->m_ControlledByPlayer = false;
6528 }
6529
6530 if (charm->IsWalking() != _isWalkingBeforeCharm)
6532
6533 if (charm->GetTypeId() == TYPEID_PLAYER
6535 || charm->GetOwnerGUID() != GetGUID())
6536 {
6537 m_Controlled.erase(charm);
6538 }
6539 }
6541}
6542
6543/*static*/ void Unit::DealHeal(HealInfo& healInfo)
6544{
6545 int32 gain = 0;
6546 Unit* healer = healInfo.GetHealer();
6547 Unit* victim = healInfo.GetTarget();
6548 uint32 addhealth = healInfo.GetHeal();
6549
6550 if (UnitAI* victimAI = victim->GetAI())
6551 victimAI->HealReceived(healer, addhealth);
6552
6553 if (UnitAI* healerAI = healer ? healer->GetAI() : nullptr)
6554 healerAI->HealDone(victim, addhealth);
6555
6556 if (addhealth)
6557 gain = victim->ModifyHealth(int32(addhealth));
6558
6559 // Hook for OnHeal Event
6560 sScriptMgr->OnHeal(healer, victim, (uint32&)gain);
6561
6562 Unit* unit = healer;
6563 if (healer && healer->GetTypeId() == TYPEID_UNIT && healer->IsTotem())
6564 unit = healer->GetOwner();
6565
6566 if (unit)
6567 {
6568 if (Player* player = unit->ToPlayer())
6569 {
6571 if (Battleground* bg = player->GetBattleground())
6572 bg->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain);
6573
6574 // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
6575 if (gain)
6576 player->UpdateCriteria(CriteriaType::HealingDone, gain, 0, 0, victim);
6577
6578 player->UpdateCriteria(CriteriaType::HighestHealCast, addhealth);
6579 }
6580 }
6581
6582 if (Player* player = victim->ToPlayer())
6583 {
6584 player->UpdateCriteria(CriteriaType::TotalHealReceived, gain);
6585 player->UpdateCriteria(CriteriaType::HighestHealReceived, addhealth);
6586 }
6587
6588 if (gain)
6589 healInfo.SetEffectiveHeal(gain > 0 ? static_cast<uint32>(gain) : 0UL);
6590}
6591
6592bool Unit::IsMagnet() const
6593{
6594 // Grounding Totem
6595 if (*m_unitData->CreatedBySpell == 8177)
6596 return true;
6597
6598 return false;
6599}
6600
6601Unit* Unit::GetMeleeHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo /*= nullptr*/)
6602{
6604 for (AuraEffectList::const_iterator i = interceptAuras.begin(); i != interceptAuras.end(); ++i)
6605 {
6606 if (Unit* magnet = (*i)->GetBase()->GetCaster())
6607 if (IsValidAttackTarget(magnet, spellInfo) && magnet->IsWithinLOSInMap(this)
6608 && (!spellInfo || (spellInfo->CheckExplicitTarget(this, magnet) == SPELL_CAST_OK
6609 && spellInfo->CheckTarget(this, magnet, false) == SPELL_CAST_OK)))
6610 {
6611 (*i)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE);
6612 return magnet;
6613 }
6614 }
6615 return victim;
6616}
6617
6619{
6620 // Sequence: charmed, pet, other guardians
6621 Unit* unit = GetCharmed();
6622 if (!unit)
6623 {
6624 ObjectGuid guid = GetMinionGUID();
6625 if (!guid.IsEmpty())
6626 unit = ObjectAccessor::GetUnit(*this, guid);
6627 }
6628
6629 return unit;
6630}
6631
6633{
6634 // possessed pet and vehicle
6635 if (GetTypeId() == TYPEID_PLAYER)
6637
6638 while (!m_Controlled.empty())
6639 {
6640 Unit* target = *m_Controlled.begin();
6641 m_Controlled.erase(m_Controlled.begin());
6642 if (target->GetCharmerGUID() == GetGUID())
6643 target->RemoveCharmAuras();
6644 else if (target->GetOwnerGUID() == GetGUID() && target->IsSummon())
6645 target->ToTempSummon()->UnSummon();
6646 else
6647 TC_LOG_ERROR("entities.unit", "Unit {} is trying to release unit {} which is neither charmed nor owned by it", GetEntry(), target->GetEntry());
6648 }
6649 if (!GetPetGUID().IsEmpty())
6650 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its pet {}", GetEntry(), GetPetGUID().ToString());
6651 if (!GetMinionGUID().IsEmpty())
6652 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its minion {}", GetEntry(), GetMinionGUID().ToString());
6653 if (!GetCharmedGUID().IsEmpty())
6654 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its charm {}", GetEntry(), GetCharmedGUID().ToString());
6655 if (!IsPet()) // pets don't use the flag for this
6656 RemoveUnitFlag(UNIT_FLAG_PET_IN_COMBAT); // m_controlled is now empty, so we know none of our minions are in combat
6657}
6658
6663
6665{
6666 return u->isPossessed() && GetCharmedGUID() == u->GetGUID();
6667}
6668
6670{
6671 if (Unit* u = GetCharmed())
6672 return u->isPossessed();
6673 else
6674 return false;
6675}
6676
6678{
6679 Player* player = nullptr;
6680 if (GetTypeId() == TYPEID_PLAYER)
6681 player = ToPlayer();
6682 // Should we enable this also for charmed units?
6683 else if (GetTypeId() == TYPEID_UNIT && IsPet())
6684 player = GetOwner()->ToPlayer();
6685
6686 if (!player)
6687 return nullptr;
6688 Group* group = player->GetGroup();
6689 // When there is no group check pet presence
6690 if (!group)
6691 {
6692 // We are pet now, return owner
6693 if (player != this)
6694 return IsWithinDistInMap(player, radius) ? player : nullptr;
6695 Unit* pet = GetGuardianPet();
6696 // No pet, no group, nothing to return
6697 if (!pet)
6698 return nullptr;
6699 // We are owner now, return pet
6700 return IsWithinDistInMap(pet, radius) ? pet : nullptr;
6701 }
6702
6703 std::vector<Unit*> nearMembers;
6704 // reserve place for players and pets because resizing vector every unit push is unefficient (vector is reallocated then)
6705 nearMembers.reserve(group->GetMembersCount() * 2);
6706
6707 for (GroupReference const& itr : group->GetMembers())
6708 {
6709 Player* Target = itr.GetSource();
6710 // IsHostileTo check duel and controlled by enemy
6711 if (Target != this && IsWithinDistInMap(Target, radius) && Target->IsAlive() && !IsHostileTo(Target))
6712 nearMembers.push_back(Target);
6713
6714 // Push player's pet to vector
6715 if (Unit* pet = Target->GetGuardianPet())
6716 if (pet != this && IsWithinDistInMap(pet, radius) && pet->IsAlive() && !IsHostileTo(pet))
6717 nearMembers.push_back(pet);
6718 }
6719
6720 if (nearMembers.empty())
6721 return nullptr;
6722
6723 uint32 randTarget = urand(0, nearMembers.size()-1);
6724 return nearMembers[randTarget];
6725}
6726
6727// only called in Player::SetSeer
6728// so move it to Player?
6730{
6731 if (m_sharedVision.empty())
6732 {
6733 setActive(true);
6735 }
6736 m_sharedVision.push_back(player);
6737}
6738
6739// only called in Player::SetSeer
6741{
6742 m_sharedVision.remove(player);
6743 if (m_sharedVision.empty())
6744 {
6745 setActive(false);
6747 }
6748}
6749
6754
6762
6764{
6765 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
6766 {
6767 if (!m_SummonSlot[i])
6768 continue;
6769
6770 if (Creature* OldTotem = GetMap()->GetCreature(m_SummonSlot[i]))
6771 if (OldTotem->IsSummon())
6772 OldTotem->ToTempSummon()->UnSummon();
6773 }
6774}
6775
6776void Unit::SendHealSpellLog(HealInfo& healInfo, bool critical /*= false*/)
6777{
6779
6780 TC_LOG_DEBUG("spells", "HealSpellLog -- SpellId: {} Caster: {} Target: {} (Health: {} OverHeal: {} Absorbed: {} Crit: {})", healInfo.GetSpellInfo()->Id, healInfo.GetHealer()->GetGUID().ToString(), healInfo.GetTarget()->GetGUID().ToString(),
6781 healInfo.GetHeal(), healInfo.GetHeal() - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), critical);
6782
6783 spellHealLog.TargetGUID = healInfo.GetTarget()->GetGUID();
6784 spellHealLog.CasterGUID = healInfo.GetHealer()->GetGUID();
6785 spellHealLog.SpellID = healInfo.GetSpellInfo()->Id;
6786 spellHealLog.Health = healInfo.GetHeal();
6787 spellHealLog.OriginalHeal = healInfo.GetOriginalHeal();
6788 spellHealLog.OverHeal = int32(healInfo.GetHeal()) - healInfo.GetEffectiveHeal();
6789 spellHealLog.Absorbed = healInfo.GetAbsorb();
6790 spellHealLog.Crit = critical;
6791 spellHealLog.LogData.Initialize(healInfo.GetTarget());
6792 SendCombatLogMessage(&spellHealLog);
6793}
6794
6795int32 Unit::HealBySpell(HealInfo& healInfo, bool critical /*= false*/)
6796{
6797 // calculate heal absorb and reduce healing
6798 Unit::CalcHealAbsorb(healInfo);
6799 Unit::DealHeal(healInfo);
6800 SendHealSpellLog(healInfo, critical);
6801 return healInfo.GetEffectiveHeal();
6802}
6803
6804void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, int32 overEnergize, Powers powertype)
6805{
6807 data.CasterGUID = GetGUID();
6808 data.TargetGUID = victim->GetGUID();
6809 data.SpellID = spellID;
6810 data.Type = powertype;
6811 data.Amount = damage;
6812 data.OverEnergize = overEnergize;
6813 data.LogData.Initialize(victim);
6814 SendCombatLogMessage(&data);
6815}
6816
6817void Unit::EnergizeBySpell(Unit* victim, SpellInfo const* spellInfo, int32 damage, Powers powerType)
6818{
6819 if (Player* player = victim->ToPlayer())
6820 if (PowerTypeEntry const* powerTypeEntry = sDB2Manager.GetPowerTypeEntry(powerType))
6821 if (powerTypeEntry->GetFlags().HasFlag(PowerTypeFlags::UseRegenInterrupt))
6822 player->InterruptPowerRegen(powerType);
6823
6824 int32 gain = victim->ModifyPower(powerType, damage, false);
6825 int32 overEnergize = damage - gain;
6826 victim->GetThreatManager().ForwardThreatForAssistingMe(this, float(damage) / 2, spellInfo, true);
6827 SendEnergizeSpellLog(victim, spellInfo->Id, gain, overEnergize, powerType);
6828}
6829
6830int32 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
6831{
6832 if (!spellProto || !victim)
6833 return pdamage;
6834
6835 int32 DoneTotal = 0;
6836 float DoneTotalMod = 1.0f;
6837
6838 auto callDamageScript = [&](int32& dmg, int32& flatMod, float& pctMod)
6839 {
6840 if (spell)
6841 spell->CallScriptCalcDamageHandlers(spellEffectInfo, victim, dmg, flatMod, pctMod);
6842 else if (aurEff)
6843 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID()), victim, dmg, flatMod, pctMod);
6844 };
6845
6846 // Some spells don't benefit from done mods
6847 if (damagetype == DIRECT_DAMAGE || spellProto->HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS))
6848 {
6849 callDamageScript(pdamage, DoneTotal, DoneTotalMod);
6850 return int32(std::max(float(pdamage + DoneTotal) * DoneTotalMod, 0.0f));
6851 }
6852
6853 // For totems get damage bonus from owner
6854 if (GetTypeId() == TYPEID_UNIT && IsTotem())
6855 if (Unit* owner = GetOwner())
6856 return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, spellEffectInfo, stack, spell, aurEff);
6857
6858 DoneTotalMod = SpellDamagePctDone(victim, spellProto, damagetype, spellEffectInfo);
6859
6860 // Done fixed damage bonus auras
6861 int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto->GetSchoolMask());
6862 // modify spell power by victim's SPELL_AURA_MOD_DAMAGE_TAKEN auras (eg Amplify/Dampen Magic)
6863 DoneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_TAKEN, spellProto->GetSchoolMask());
6864
6865 // Pets just add their bonus damage to their spell damage
6866 // note that their spell damage is just gain of their own auras
6868 DoneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
6869
6870 // Check for table values
6871 if (spellEffectInfo.BonusCoefficientFromAP > 0.0f)
6872 {
6873 float attackPowerCoeff = spellEffectInfo.BonusCoefficientFromAP;
6874 if (Player* modOwner = GetSpellModOwner())
6875 {
6876 attackPowerCoeff *= 100.0f;
6877 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, attackPowerCoeff);
6878 attackPowerCoeff /= 100.0f;
6879 }
6880
6881 WeaponAttackType const attType = [&]()
6882 {
6883 if ((spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE))
6884 return RANGED_ATTACK;
6885
6887 return OFF_ATTACK;
6888
6889 return BASE_ATTACK;
6890 }();
6892 attackPowerBonus += GetTotalAttackPowerValue(attType);
6893 DoneTotal += int32(stack * attackPowerCoeff * attackPowerBonus);
6894 }
6895
6896 // Default calculation
6897 if (DoneAdvertisedBenefit)
6898 {
6899 float coeff = spellEffectInfo.BonusCoefficient;
6900 if (Player* modOwner = GetSpellModOwner())
6901 {
6902 coeff *= 100.0f;
6903 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, coeff);
6904 coeff /= 100.0f;
6905 }
6906
6907 DoneTotal += int32(DoneAdvertisedBenefit * coeff * stack);
6908 }
6909
6910 callDamageScript(pdamage, DoneTotal, DoneTotalMod);
6911
6912 float tmpDamage = float(pdamage + DoneTotal) * DoneTotalMod;
6913
6914 // apply spellmod to Done damage (flat and pct)
6915 if (Player* modOwner = GetSpellModOwner())
6916 modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, tmpDamage);
6917
6918 return int32(std::max(tmpDamage, 0.0f));
6919}
6920
6921float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo) const
6922{
6923 if (!spellProto || !victim || damagetype == DIRECT_DAMAGE)
6924 return 1.0f;
6925
6926 // Some spells don't benefit from done mods
6928 return 1.0f;
6929
6930 // Some spells don't benefit from pct done mods
6932 return 1.0f;
6933
6934 // For totems get damage bonus from owner
6935 if (GetTypeId() == TYPEID_UNIT && IsTotem())
6936 if (Unit* owner = GetOwner())
6937 return owner->SpellDamagePctDone(victim, spellProto, damagetype, spellEffectInfo);
6938
6939 // Done total percent damage auras
6940 float DoneTotalMod = 1.0f;
6941
6942 // Pet damage?
6943 if (GetTypeId() == TYPEID_UNIT && !IsPet())
6944 DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureTemplate()->Classification);
6945
6946 // Versatility
6947 if (Player* modOwner = GetSpellModOwner())
6948 AddPct(DoneTotalMod, modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_DONE) + modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY));
6949
6950 float maxModDamagePercentSchool = 0.0f;
6951 if (Player const* thisPlayer = ToPlayer())
6952 {
6953 for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
6954 if (spellProto->GetSchoolMask() & (1 << i))
6955 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, thisPlayer->m_activePlayerData->ModDamageDonePercent[i]);
6956 }
6957 else
6958 maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, spellProto->GetSchoolMask());
6959
6960 DoneTotalMod *= maxModDamagePercentSchool;
6961
6962 uint32 creatureTypeMask = victim->GetCreatureTypeMask();
6963
6965
6966 // bonus against aurastate
6967 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim](AuraEffect const* aurEff) -> bool
6968 {
6969 if (victim->HasAuraState(static_cast<AuraStateType>(aurEff->GetMiscValue())))
6970 return true;
6971 return false;
6972 });
6973
6974 // bonus against target aura mechanic
6976 {
6977 if (victim->HasAuraWithMechanic(UI64LIT(1) << aurEff->GetMiscValue()))
6978 return true;
6979 return false;
6980 });
6981
6982 // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
6983 if (spellEffectInfo.Mechanic)
6985 else if (spellProto->Mechanic)
6987
6988 // Custom scripted damage
6989 switch (spellProto->SpellFamilyName)
6990 {
6991 case SPELLFAMILY_MAGE:
6992 // Ice Lance (no unique family flag)
6993 if (spellProto->Id == 228598)
6994 if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
6995 DoneTotalMod *= 3.0f;
6996 break;
6998 // Shadow Bite (30% increase from each dot)
6999 if (spellProto->SpellFamilyFlags[1] & 0x00400000 && IsPet())
7000 if (uint8 count = victim->GetDoTsByCaster(GetOwnerGUID()))
7001 AddPct(DoneTotalMod, 30 * count);
7002
7003 // Drain Soul - increased damage for targets under 20% HP
7004 if (spellProto->Id == 198590)
7006 DoneTotalMod *= 2;
7007 break;
7008 }
7009
7010 return DoneTotalMod;
7011}
7012
7013int32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, int32 pdamage, DamageEffectType damagetype) const
7014{
7015 if (!spellProto || damagetype == DIRECT_DAMAGE)
7016 return pdamage;
7017
7018 float TakenTotalMod = 1.0f;
7019
7020 // Mod damage from spell mechanic
7021 if (uint64 mechanicMask = spellProto->GetAllEffectsMechanicMask())
7022 {
7023 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
7024 {
7025 if (mechanicMask & uint64(UI64LIT(1) << aurEff->GetMiscValue()))
7026 return true;
7027 return false;
7028 });
7029 }
7030
7031 if (AuraEffect const* cheatDeath = GetAuraEffect(45182, EFFECT_0))
7032 if (cheatDeath->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
7033 AddPct(TakenTotalMod, cheatDeath->GetAmount());
7034
7035 // Spells with SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS should only benefit from mechanic damage mod auras.
7037 {
7038 // Versatility
7039 if (Player* modOwner = GetSpellModOwner())
7040 {
7041 // only 50% of SPELL_AURA_MOD_VERSATILITY for damage reduction
7042 float versaBonus = modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY) / 2.0f;
7043 AddPct(TakenTotalMod, -(modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_TAKEN) + versaBonus));
7044 }
7045
7046 // from positive and negative SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
7047 // multiplicative bonus, for example Dispersion + Shadowform (0.10*0.85=0.085)
7049
7050 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_TAKEN_BY_LABEL, [spellProto](AuraEffect const* aurEff) -> bool
7051 {
7052 return spellProto->HasLabel(aurEff->GetMiscValue());
7053 });
7054
7055 // From caster spells
7056 if (caster)
7057 {
7058 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SCHOOL_MASK_DAMAGE_FROM_CASTER, [caster, spellProto](AuraEffect const* aurEff) -> bool
7059 {
7060 return aurEff->GetCasterGUID() == caster->GetGUID() && (aurEff->GetMiscValue() & spellProto->GetSchoolMask());
7061 });
7062
7063 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER, [caster, spellProto](AuraEffect const* aurEff) -> bool
7064 {
7065 return aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectingSpell(spellProto);
7066 });
7067
7068 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER_BY_LABEL, [caster, spellProto](AuraEffect const* aurEff) -> bool
7069 {
7070 return aurEff->GetCasterGUID() == caster->GetGUID() && spellProto->HasLabel(aurEff->GetMiscValue());
7071 });
7072 }
7073
7074 if (damagetype == DOT)
7075 {
7076 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_PERIODIC_DAMAGE_TAKEN, [spellProto](AuraEffect const* aurEff) -> bool
7077 {
7078 return aurEff->GetMiscValue() & spellProto->GetSchoolMask();
7079 });
7080 }
7081 }
7082
7083 // Sanctified Wrath (bypass damage reduction)
7084 if (caster && TakenTotalMod < 1.0f)
7085 {
7086 float damageReduction = 1.0f - TakenTotalMod;
7088 for (AuraEffect const* aurEff : casterIgnoreResist)
7089 {
7090 if (!(aurEff->GetMiscValue() & spellProto->GetSchoolMask()))
7091 continue;
7092
7093 AddPct(damageReduction, -aurEff->GetAmount());
7094 }
7095
7096 TakenTotalMod = 1.0f - damageReduction;
7097 }
7098
7099 float tmpDamage = pdamage * TakenTotalMod;
7100 return int32(std::max(tmpDamage, 0.0f));
7101}
7102
7104{
7105 Player const* thisPlayer = ToPlayer();
7106 if (thisPlayer)
7107 {
7108 float overrideSP = thisPlayer->m_activePlayerData->OverrideSpellPowerByAPPercent;
7109 if (overrideSP > 0.0f)
7110 return int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), overrideSP) + 0.5f);
7111 }
7112
7113 int32 DoneAdvertisedBenefit = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE, schoolMask);
7114
7115 if (thisPlayer)
7116 {
7117 // Base value
7118 DoneAdvertisedBenefit += thisPlayer->GetBaseSpellPowerBonus();
7119
7120 if (thisPlayer->GetPrimaryStat() == STAT_INTELLECT)
7121 DoneAdvertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT))); // spellpower from intellect
7122
7123 // Damage bonus from stats
7125 for (AuraEffect const* aurEff : mDamageDoneOfStatPercent)
7126 {
7127 if ((aurEff->GetMiscValue() & schoolMask) != 0)
7128 {
7129 // stat used stored in miscValueB for this aura
7130 Stats const usedStat = static_cast<Stats>(aurEff->GetMiscValueB());
7131 DoneAdvertisedBenefit += static_cast<int32>(CalculatePct(GetStat(usedStat), aurEff->GetAmount()));
7132 }
7133 }
7134
7135 }
7136
7137 return DoneAdvertisedBenefit;
7138}
7139
7140float Unit::SpellCritChanceDone(Spell* spell, AuraEffect const* aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType /*= BASE_ATTACK*/) const
7141{
7142 SpellInfo const* spellInfo = spell ? spell->GetSpellInfo() : aurEff->GetSpellInfo();
7144 if (GetTypeId() == TYPEID_UNIT && !GetSpellModOwner())
7145 return 0.0f;
7146
7147 // not critting spell
7148 if (spell && !spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
7149 return 0.0f;
7150
7151 float crit_chance = 0.0f;
7152 switch (spellInfo->DmgClass)
7153 {
7156 {
7157 auto getPhysicalCritChance = [&]
7158 {
7159 return GetUnitCriticalChanceDone(attackType);
7160 };
7161
7162 auto getMagicCritChance = [&]
7163 {
7164 if (Player const* thisPlayer = ToPlayer())
7165 return *thisPlayer->m_activePlayerData->SpellCritPercentage;
7166
7167 return m_baseSpellCritChance;
7168 };
7169
7170 if (schoolMask & SPELL_SCHOOL_MASK_NORMAL)
7171 crit_chance = std::max(crit_chance, getPhysicalCritChance());
7172
7173 if (schoolMask & ~SPELL_SCHOOL_MASK_NORMAL)
7174 crit_chance = std::max(crit_chance, getMagicCritChance());
7175 break;
7176 }
7179 {
7180 crit_chance += GetUnitCriticalChanceDone(attackType);
7181 break;
7182 }
7183 default:
7184 return 0.0f;
7185 }
7186 // percent done
7187 // only players use intelligence for critical chance computations
7188 if (Player* modOwner = GetSpellModOwner())
7189 modOwner->ApplySpellMod(spellInfo, SpellModOp::CritChance, crit_chance);
7190
7191 return std::max(crit_chance, 0.0f);
7192}
7193
7194float Unit::SpellCritChanceTaken(Unit const* caster, Spell* spell, AuraEffect const* aurEff, SpellSchoolMask /*schoolMask*/, float doneChance, WeaponAttackType attackType /*= BASE_ATTACK*/) const
7195{
7196 SpellInfo const* spellInfo = spell ? spell->GetSpellInfo() : aurEff->GetSpellInfo();
7197 // not critting spell
7198 if (spell && !spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
7199 return 0.0f;
7200
7201 float crit_chance = doneChance;
7202 switch (spellInfo->DmgClass)
7203 {
7205 {
7206 // taken
7207 if (!spellInfo->IsPositive())
7208 {
7209 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7211 }
7212
7213 if (caster)
7214 {
7215 // scripted (increase crit chance ... against ... target by x%
7216 AuraEffectList const& mOverrideClassScript = caster->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7217 for (AuraEffect const* aurEff : mOverrideClassScript)
7218 {
7219 if (!aurEff->IsAffectingSpell(spellInfo))
7220 continue;
7221
7222 switch (aurEff->GetMiscValue())
7223 {
7224 case 911: // Shatter
7225 if (HasAuraState(AURA_STATE_FROZEN, spellInfo, caster))
7226 {
7227 crit_chance *= 1.5f;
7228 if (AuraEffect const* eff = aurEff->GetBase()->GetEffect(EFFECT_1))
7229 crit_chance += eff->GetAmount();
7230 }
7231 break;
7232 default:
7233 break;
7234 }
7235 }
7236 // Custom crit by class
7237 switch (spellInfo->SpellFamilyName)
7238 {
7239 case SPELLFAMILY_ROGUE:
7240 // Shiv-applied poisons can't crit
7241 if (caster->FindCurrentSpellBySpellId(5938))
7242 crit_chance = 0.0f;
7243 break;
7244 }
7245
7246 // Spell crit suppression
7247 if (GetTypeId() == TYPEID_UNIT)
7248 {
7249 int32 const levelDiff = static_cast<int32>(GetLevelForTarget(caster)) - caster->GetLevel();
7250 crit_chance -= levelDiff * 1.0f;
7251 }
7252 }
7253 break;
7254 }
7256
7258 if (caster)
7259 crit_chance = GetUnitCriticalChanceTaken(caster, attackType, crit_chance);
7260 break;
7262 default:
7263 return 0.f;
7264 }
7265
7266 // for this types the bonus was already added in GetUnitCriticalChance, do not add twice
7267 if (caster && spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && spellInfo->DmgClass != SPELL_DAMAGE_CLASS_RANGED)
7268 {
7269 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_WITH_ABILITIES, [caster, spellInfo](AuraEffect const* aurEff) -> bool
7270 {
7271 return aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectingSpell(spellInfo);
7272 });
7273 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [caster](AuraEffect const* aurEff) -> bool
7274 {
7275 return aurEff->GetCasterGUID() == caster->GetGUID();
7276 });
7277 crit_chance += caster->GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_VERSUS_TARGET_HEALTH, [this](AuraEffect const* aurEff)
7278 {
7279 return !HealthBelowPct(aurEff->GetMiscValueB());
7280 });
7281 if (TempSummon const* tempSummon = caster->ToTempSummon())
7282 {
7283 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_PET, [tempSummon](AuraEffect const* aurEff) -> bool
7284 {
7285 return aurEff->GetCasterGUID() == tempSummon->GetSummonerGUID();
7286 });
7287 }
7288 }
7289
7290 // call script handlers
7291 if (spell)
7292 spell->CallScriptCalcCritChanceHandlers(this, crit_chance);
7293 else
7294 aurEff->GetBase()->CallScriptEffectCalcCritChanceHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(GetGUID()), this, crit_chance);
7295
7296 return std::max(crit_chance, 0.0f);
7297}
7298
7299/*static*/ uint32 Unit::SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim)
7300{
7301 // Calculate critical bonus
7302 int32 crit_bonus = damage * 2;
7303 float crit_mod = 0.0f;
7304
7305 if (caster)
7306 {
7307 crit_mod += (caster->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellProto->GetSchoolMask()) - 1.0f) * 100;
7308
7309 if (crit_bonus != 0)
7310 AddPct(crit_bonus, crit_mod);
7311
7313 {
7314 return aurEff->GetCasterGUID() == caster->GetGUID();
7315 }));
7316
7317 crit_bonus -= damage;
7318
7319 // adds additional damage to critBonus (from talents)
7320 if (Player* modOwner = caster->GetSpellModOwner())
7321 modOwner->ApplySpellMod(spellProto, SpellModOp::CritDamageAndHealing, crit_bonus);
7322
7323 crit_bonus += damage;
7324 }
7325
7326 return crit_bonus;
7327}
7328
7329/*static*/ uint32 Unit::SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* /*victim*/)
7330{
7331 // Calculate critical bonus
7332 int32 crit_bonus = damage;
7333
7334 // adds additional damage to critBonus (from talents)
7335 if (caster)
7336 if (Player* modOwner = caster->GetSpellModOwner())
7337 modOwner->ApplySpellMod(spellProto, SpellModOp::CritDamageAndHealing, crit_bonus);
7338
7339 damage += crit_bonus;
7340
7341 if (caster)
7342 damage = int32(float(damage) * caster->GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT));
7343
7344 return damage;
7345}
7346
7347int32 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
7348{
7349 // For totems get healing bonus from owner (statue isn't totem in fact)
7350 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7351 if (Unit* owner = GetOwner())
7352 return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, spellEffectInfo, stack, spell, aurEff);
7353
7354 // No bonus healing for potion spells
7355 if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
7356 return healamount;
7357
7358 int32 DoneTotal = 0;
7359 float DoneTotalMod = SpellHealingPctDone(victim, spellProto);
7360
7361 // done scripted mod (take it from owner)
7362 Unit const* owner = GetOwner() ? GetOwner() : this;
7363 AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7364 for (AuraEffect const* aurEff : mOverrideClassScript)
7365 {
7366 if (!aurEff->IsAffectingSpell(spellProto))
7367 continue;
7368
7369 switch (aurEff->GetMiscValue())
7370 {
7371 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
7372 DoneTotal += aurEff->GetAmount();
7373 break;
7374 default:
7375 break;
7376 }
7377 }
7378
7379 // Done fixed damage bonus auras
7380 int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(spellProto->GetSchoolMask());
7381 // modify spell power by victim's SPELL_AURA_MOD_HEALING auras (eg Amplify/Dampen Magic)
7382 DoneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_HEALING, spellProto->GetSchoolMask());
7383
7384 // Pets just add their bonus damage to their spell damage
7385 // note that their spell damage is just gain of their own auras
7387 DoneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
7388
7389 // Check for table values
7390 if (spellEffectInfo.BonusCoefficientFromAP > 0.0f)
7391 {
7392 float attackPowerCoeff = spellEffectInfo.BonusCoefficientFromAP;
7393 if (Player* modOwner = GetSpellModOwner())
7394 {
7395 attackPowerCoeff *= 100.0f;
7396 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, attackPowerCoeff);
7397 attackPowerCoeff /= 100.0f;
7398 }
7399
7400 WeaponAttackType const attType = [&]()
7401 {
7402 if ((spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE))
7403 return RANGED_ATTACK;
7404
7406 return OFF_ATTACK;
7407
7408 return BASE_ATTACK;
7409 }();
7411 attackPowerBonus += GetTotalAttackPowerValue(attType);
7412 DoneTotal += int32(stack * attackPowerCoeff * attackPowerBonus);
7413 }
7414
7415 // Default calculation
7416 if (DoneAdvertisedBenefit)
7417 {
7418 float coeff = spellEffectInfo.BonusCoefficient;
7419 if (Player* modOwner = GetSpellModOwner())
7420 {
7421 coeff *= 100.0f;
7422 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, coeff);
7423 coeff /= 100.0f;
7424 }
7425
7426 DoneTotal += int32(DoneAdvertisedBenefit * coeff * stack);
7427 }
7428
7429 for (SpellEffectInfo const& otherSpellEffect : spellProto->GetEffects())
7430 {
7431 switch (otherSpellEffect.ApplyAuraName)
7432 {
7433 // Bonus healing does not apply to these spells
7436 DoneTotal = 0;
7437 break;
7438 default:
7439 break;
7440 }
7441 if (otherSpellEffect.IsEffect(SPELL_EFFECT_HEALTH_LEECH))
7442 DoneTotal = 0;
7443 }
7444
7445 if (spell)
7446 spell->CallScriptCalcHealingHandlers(spellEffectInfo, victim, healamount, DoneTotal, DoneTotalMod);
7447 else if (aurEff)
7448 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID()), victim, healamount, DoneTotal, DoneTotalMod);
7449
7450 float heal = float(healamount + DoneTotal) * DoneTotalMod;
7451
7452 // apply spellmod to Done amount
7453 if (Player* modOwner = GetSpellModOwner())
7454 modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, heal);
7455
7456 return int32(std::max(heal, 0.0f));
7457}
7458
7459float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const
7460{
7461 // For totems get healing bonus from owner
7462 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7463 if (Unit* owner = GetOwner())
7464 return owner->SpellHealingPctDone(victim, spellProto);
7465
7466 // Some spells don't benefit from done mods
7468 return 1.0f;
7469
7470 // Some spells don't benefit from done mods
7472 return 1.0f;
7473
7474 // Some spells don't benefit from done mods
7476 return 1.0f;
7477
7478 // No bonus healing for potion spells
7479 if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
7480 return 1.0f;
7481
7482 float DoneTotalMod = 1.0f;
7483
7484 // Healing done percent
7485 if (Player const* thisPlayer = ToPlayer())
7486 {
7487 float maxModDamagePercentSchool = 0.0f;
7488 for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
7489 if (spellProto->GetSchoolMask() & (1 << i))
7490 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, thisPlayer->m_activePlayerData->ModHealingDonePercent[i]);
7491
7492 DoneTotalMod *= maxModDamagePercentSchool;
7493 }
7494 else // SPELL_AURA_MOD_HEALING_DONE_PERCENT is included in m_activePlayerData->ModHealingDonePercent for players
7496
7497 // bonus against aurastate
7498 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim](AuraEffect const* aurEff) -> bool
7499 {
7500 if (victim->HasAuraState(static_cast<AuraStateType>(aurEff->GetMiscValue())))
7501 return true;
7502 return false;
7503 });
7504
7505 // bonus from missing health of target
7506 float healthPctDiff = 100.0f - victim->GetHealthPct();
7508 if (healingDonePctVsTargetHealth->IsAffectingSpell(spellProto))
7509 AddPct(DoneTotalMod, CalculatePct(healingDonePctVsTargetHealth->GetAmount(), healthPctDiff));
7510
7511 return DoneTotalMod;
7512}
7513
7514int32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, int32 healamount, DamageEffectType damagetype) const
7515{
7516 bool allowPositive = !spellProto->HasAttribute(SPELL_ATTR6_IGNORE_HEALING_MODIFIERS);
7518 if (!allowPositive && !allowNegative)
7519 return healamount;
7520
7521 float TakenTotalMod = 1.0f;
7522
7523 // Healing taken percent
7524 if (allowNegative)
7525 {
7527 if (minval)
7528 AddPct(TakenTotalMod, minval);
7529
7530 if (damagetype == DOT)
7531 {
7532 // Healing over time taken percent
7533 float minval_hot = float(GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT));
7534 if (minval_hot)
7535 AddPct(TakenTotalMod, minval_hot);
7536 }
7537 }
7538
7539 if (allowPositive)
7540 {
7542 if (maxval)
7543 AddPct(TakenTotalMod, maxval);
7544
7545 if (damagetype == DOT)
7546 {
7547 // Healing over time taken percent
7548 float maxval_hot = float(GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT));
7549 if (maxval_hot)
7550 AddPct(TakenTotalMod, maxval_hot);
7551 }
7552
7553 // Nourish cast
7554 if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[1] & 0x2000000)
7555 {
7556 // Rejuvenation, Regrowth, Lifebloom, or Wild Growth
7558 // increase healing by 20%
7559 TakenTotalMod *= 1.2f;
7560 }
7561 }
7562
7563 if (caster)
7564 {
7565 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_RECEIVED, [caster, spellProto, allowPositive, allowNegative](AuraEffect const* aurEff) -> bool
7566 {
7567 if (caster->GetGUID() != aurEff->GetCasterGUID() || !aurEff->IsAffectingSpell(spellProto))
7568 return false;
7569
7570 if (aurEff->GetAmount() > 0)
7571 {
7572 if (!allowPositive)
7573 return false;
7574 }
7575 else if (!allowNegative)
7576 return false;
7577
7578 return true;
7579 });
7580
7581 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_TAKEN_FROM_CASTER, [caster, allowPositive, allowNegative](AuraEffect const* aurEff) -> bool
7582 {
7583 if (aurEff->GetCasterGUID() != caster->GetGUID())
7584 return false;
7585
7586 if (aurEff->GetAmount() > 0)
7587 {
7588 if (!allowPositive)
7589 return false;
7590 }
7591 else if (!allowNegative)
7592 return false;
7593
7594 return true;
7595 });
7596 }
7597
7598 float heal = healamount * TakenTotalMod;
7599 return int32(std::max(heal, 0.0f));
7600}
7601
7603{
7604 if (Player const* thisPlayer = ToPlayer())
7605 {
7606 float overrideSP = thisPlayer->m_activePlayerData->OverrideSpellPowerByAPPercent;
7607 if (overrideSP > 0.0f)
7608 return int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), overrideSP) + 0.5f);
7609 }
7610
7611 int32 advertisedBenefit = GetTotalAuraModifier(SPELL_AURA_MOD_HEALING_DONE, [schoolMask](AuraEffect const* aurEff) -> bool
7612 {
7613 if (!aurEff->GetMiscValue() || (aurEff->GetMiscValue() & schoolMask) != 0)
7614 return true;
7615 return false;
7616 });
7617
7618 // Healing bonus of spirit, intellect and strength
7619 if (GetTypeId() == TYPEID_PLAYER)
7620 {
7621 // Base value
7622 advertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
7623
7624 // Check if we are ever using mana - PaperDollFrame.lua
7626 advertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT))); // spellpower from intellect
7627
7628 // Healing bonus from stats
7630 for (AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i)
7631 {
7632 // stat used dependent from misc value (stat index)
7633 Stats usedStat = Stats((*i)->GetSpellEffectInfo().MiscValue);
7634 advertisedBenefit += int32(CalculatePct(GetStat(usedStat), (*i)->GetAmount()));
7635 }
7636 }
7637 return advertisedBenefit;
7638}
7639
7641{
7642 return SpellBaseHealingBonusDone(schoolMask);
7643}
7644
7645int32 Unit::SpellAbsorbBonusDone(Unit* victim, SpellInfo const* spellProto, int32 absorbamount, SpellEffectInfo const& spellEffectInfo, uint32 stack /*= 1*/, AuraEffect const* aurEff /*= nullptr*/) const
7646{
7647 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7648 if (Unit* owner = GetOwner())
7649 return owner->SpellAbsorbBonusDone(victim, spellProto, absorbamount, spellEffectInfo, stack, aurEff);
7650
7653 return absorbamount;
7654
7655 int32 doneTotal = 0;
7656 float doneTotalMod = SpellAbsorbPctDone(victim, spellProto);
7657
7658 int32 doneAdvertisedBenefit = SpellBaseAbsorbBonusDone(spellProto->GetSchoolMask());
7659 doneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_HEALING, spellProto->GetSchoolMask());
7660
7662 doneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
7663
7664 if (spellEffectInfo.BonusCoefficientFromAP > 0.0f)
7665 {
7666 float attackPowerCoeff = spellEffectInfo.BonusCoefficientFromAP;
7667 if (Player* modOwner = GetSpellModOwner())
7668 {
7669 attackPowerCoeff *= 100.0f;
7670 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, attackPowerCoeff);
7671 attackPowerCoeff /= 100.0f;
7672 }
7673
7674 WeaponAttackType const attType = [&]()
7675 {
7676 if ((spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE))
7677 return RANGED_ATTACK;
7678
7680 return OFF_ATTACK;
7681
7682 return BASE_ATTACK;
7683 }();
7685 attackPowerBonus += GetTotalAttackPowerValue(attType);
7686 doneTotal += int32(stack * attackPowerCoeff * attackPowerBonus);
7687 }
7688
7689 if (doneAdvertisedBenefit)
7690 {
7691 float coeff = spellEffectInfo.BonusCoefficient;
7692
7693 if (Player* modOwner = GetSpellModOwner())
7694 {
7695 coeff *= 100.f;
7696 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, coeff);
7697 coeff /= 100.f;
7698 }
7699
7700 doneTotal += int32(doneAdvertisedBenefit * coeff * stack);
7701 }
7702
7703 if (aurEff)
7704 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID()), victim, absorbamount, doneTotal, doneTotalMod);
7705
7706 float absorbAmount = float(absorbamount + doneTotal) * doneTotalMod;
7707
7708 return static_cast<int32>(std::round(absorbAmount));
7709}
7710
7711float Unit::SpellAbsorbPctDone(Unit* victim, SpellInfo const* spellProto) const
7712{
7713 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7714 if (Unit* owner = GetOwner())
7715 return owner->SpellAbsorbPctDone(victim, spellProto);
7716
7717 float doneTotalMod = 1.f;
7718
7719 if (Player* modOwner = GetSpellModOwner())
7720 AddPct(doneTotalMod, modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_DONE) + modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY));
7721
7723
7724 return doneTotalMod;
7725}
7726
7727int32 Unit::SpellAbsorbBonusTaken(Unit* /*caster*/, SpellInfo const* spellProto, int32 absorbamount) const
7728{
7730 return absorbamount;
7731
7732 int32 doneTotal = 0;
7733 float takenTotalMod = 1.f;
7734
7736
7737 float absorb = float(absorbamount + doneTotal) * takenTotalMod;
7738
7739 return static_cast<int32>(std::round(absorb));
7740}
7741
7742bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute /*= false*/) const
7743{
7744 if (!spellInfo)
7745 return false;
7746
7747 auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
7748 {
7750 if (!requireImmunityPurgesEffectAttribute)
7751 return range.begin() != range.end();
7752
7753 return std::ranges::any_of(range, [](uint32 immunitySpellId)
7754 {
7755 if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(immunitySpellId, DIFFICULTY_NONE))
7756 if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
7757 return true;
7758
7759 return false;
7761 };
7762
7763 // Single spell immunity.
7765 if (hasImmunity(idList, spellInfo->Id))
7766 return true;
7767
7769 return false;
7770
7771 if (uint32 dispel = spellInfo->Dispel)
7772 {
7774 if (hasImmunity(dispelList, dispel))
7775 return true;
7776 }
7777
7778 // Spells that don't have effectMechanics.
7779 if (uint32 mechanic = spellInfo->Mechanic)
7780 {
7782 if (hasImmunity(mechanicList, mechanic))
7783 return true;
7784 }
7785
7786 bool immuneToAllEffects = true;
7787 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
7788 {
7789 // State/effect immunities applied by aura expect full spell immunity
7790 // Ignore effects with mechanic, they are supposed to be checked separately
7791 if (!spellEffectInfo.IsEffect() || !(effectMask & (1 << spellEffectInfo.EffectIndex)))
7792 continue;
7793 if (!IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute))
7794 {
7795 immuneToAllEffects = false;
7796 break;
7797 }
7799 return true;
7800 }
7801
7802 if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
7803 return true;
7804
7805 if (uint32 schoolMask = spellInfo->GetSchoolMask())
7806 {
7807 uint32 schoolImmunityMask = 0;
7809 for (auto [auraSchoolImmunityMask, immunityAuraId] : schoolList)
7810 {
7811 if ((auraSchoolImmunityMask & schoolMask) == 0)
7812 continue;
7813
7814 SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(immunityAuraId, GetMap()->GetDifficultyID());
7815 if (requireImmunityPurgesEffectAttribute)
7816 if (!immuneSpellInfo || !immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
7817 continue;
7818
7819 if (!(spellInfo->NegativeEffects.to_ulong() & effectMask) && !(immuneSpellInfo && immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS)))
7820 continue;
7821
7822 if (spellInfo->CanPierceImmuneAura(immuneSpellInfo))
7823 continue;
7824
7825 schoolImmunityMask |= auraSchoolImmunityMask;
7826 }
7827 if ((schoolImmunityMask & schoolMask) == schoolMask)
7828 return true;
7829 }
7830
7831 return false;
7832}
7833
7835{
7836 uint32 mask = 0;
7838 for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7839 mask |= itr->first;
7840
7841 return mask;
7842}
7843
7845{
7846 uint32 mask = 0;
7848 for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
7849 mask |= itr->first;
7850
7851 return mask;
7852}
7853
7855{
7856 uint64 mask = 0;
7858 for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
7859 mask |= (UI64LIT(1) << itr->first);
7860
7861 return mask;
7862}
7863
7865{
7866 SpellOtherImmunity mask = { };
7868 for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
7869 mask |= SpellOtherImmunity(itr->first);
7870
7871 return mask;
7872}
7873
7875{
7876 if (schoolMask == SPELL_SCHOOL_MASK_NONE)
7877 return false;
7878
7879 // If m_immuneToSchool type contain this school type, IMMUNE damage.
7880 uint32 schoolImmunityMask = GetSchoolImmunityMask();
7881 if ((schoolImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7882 return true;
7883
7884 // If m_immuneToDamage type contain magic, IMMUNE damage.
7885 uint32 damageImmunityMask = GetDamageImmunityMask();
7886 if ((damageImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7887 return true;
7888
7889 return false;
7890}
7891
7892bool Unit::IsImmunedToDamage(WorldObject const* /*caster*/, SpellInfo const* spellInfo, SpellEffectInfo const* spellEffectInfo /*= nullptr*/) const
7893{
7894 if (!spellInfo)
7895 return false;
7896
7898 return false;
7899
7900 if (spellEffectInfo && spellEffectInfo->EffectAttributes.HasFlag(SpellEffectAttributes::NoImmunity))
7901 return false;
7902
7903 if (uint32 schoolMask = spellInfo->GetSchoolMask())
7904 {
7905 auto hasImmunity = [&](SpellImmuneContainer const& container)
7906 {
7907 uint32 schoolImmunityMask = 0;
7908 for (auto&& [immunitySchoolMask, immunityAuraId] : container)
7909 {
7910 SpellInfo const* immuneAuraInfo = sSpellMgr->GetSpellInfo(immunityAuraId, GetMap()->GetDifficultyID());
7911 if (spellInfo->IsPositive() && !(immuneAuraInfo && immuneAuraInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS)))
7912 continue;
7913
7914 if (immuneAuraInfo && spellInfo->CanPierceImmuneAura(immuneAuraInfo))
7915 continue;
7916
7917 schoolImmunityMask |= immunitySchoolMask;
7918 }
7919
7920 // // We need to be immune to all types
7921 return (schoolImmunityMask & schoolMask) == schoolMask;
7922 };
7923
7924 // If m_immuneToSchool type contain this school type, IMMUNE damage.
7925 if (hasImmunity(m_spellImmune[IMMUNITY_SCHOOL]))
7926 return true;
7927
7928 // If m_immuneToDamage type contain magic, IMMUNE damage.
7929 if (hasImmunity(m_spellImmune[IMMUNITY_DAMAGE]))
7930 return true;
7931 }
7932
7933 return false;
7934}
7935
7936bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* /*caster*/,
7937 bool requireImmunityPurgesEffectAttribute /*= false*/) const
7938{
7939 if (!spellInfo)
7940 return false;
7941
7943 return false;
7944
7946 return false;
7947
7948 auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
7949 {
7951 if (!requireImmunityPurgesEffectAttribute)
7952 return range.begin() != range.end();
7953
7954 return std::ranges::any_of(range, [](uint32 immunitySpellId)
7955 {
7956 if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(immunitySpellId, DIFFICULTY_NONE))
7957 if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
7958 return true;
7959
7960 return false;
7962 };
7963
7964 // If m_immuneToEffect type contain this effect type, IMMUNE effect.
7965 auto const& effectList = m_spellImmune[IMMUNITY_EFFECT];
7966 if (hasImmunity(effectList, spellEffectInfo.Effect))
7967 return true;
7968
7969 if (uint32 mechanic = spellEffectInfo.Mechanic)
7970 {
7972 if (hasImmunity(mechanicList, mechanic))
7973 return true;
7974 }
7975
7976 if (AuraType aura = spellEffectInfo.ApplyAuraName)
7977 {
7978 if (!spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
7979 {
7981 if (hasImmunity(list, aura))
7982 return true;
7983 }
7984
7986 {
7987 // Check for immune to application of harmful magical effects
7989 {
7990 if (!(immuneAuraApply->GetMiscValue() & spellInfo->GetSchoolMask())) // Check school
7991 continue;
7992
7993 if (!spellInfo->IsPositiveEffect(spellEffectInfo.EffectIndex)) // Harmful
7994 return true;
7995
7996 if (immuneAuraApply->GetSpellInfo()->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS)) // Friendly
7997 return true;
7998 }
7999 }
8000 }
8001
8002 return false;
8003}
8004
8005bool Unit::IsImmunedToAuraPeriodicTick(WorldObject const* /*caster*/, AuraEffect const* auraEffect) const
8006{
8007 if (auraEffect->GetSpellInfo()->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) || auraEffect->GetSpellInfo()->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES) /*only school immunities are checked in this function*/)
8008 return false;
8009
8011 return false;
8012
8013 if (uint32 schoolMask = auraEffect->GetSpellInfo()->GetSchoolMask())
8014 {
8015 auto hasImmunity = [&](SpellImmuneContainer const& container)
8016 {
8017 bool isPositive = auraEffect->GetBase()->GetApplicationOfTarget(GetGUID())->IsPositive();
8018 uint32 schoolImmunityMask = 0;
8019 for (auto&& [immunitySchoolMask, immunityAuraId] : container)
8020 {
8021 SpellInfo const* immuneAuraInfo = sSpellMgr->GetSpellInfo(immunityAuraId, GetMap()->GetDifficultyID());
8022 if (isPositive && !(immuneAuraInfo && immuneAuraInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS)))
8023 continue;
8024
8025 schoolImmunityMask |= immunitySchoolMask;
8026 }
8027
8028 // // We need to be immune to all types
8029 return (schoolImmunityMask & schoolMask) == schoolMask;
8030 };
8031
8032 // If m_immuneToSchool type contain this school type, IMMUNE damage.
8033 if (hasImmunity(m_spellImmune[IMMUNITY_SCHOOL]))
8034 return true;
8035 }
8036
8037 return false;
8038}
8039
8040int32 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*/)
8041{
8042 if (!pVictim || damage == 0)
8043 return 0;
8044
8045 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
8046
8047 // Done fixed damage bonus auras
8048 int32 DoneFlatBenefit = 0;
8049
8050 // ..done
8051 DoneFlatBenefit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE, creatureTypeMask);
8052
8053 // ..done
8054 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
8055
8056 // ..done (base at attack power for marked target and base at attack power for creature type)
8057 int32 APbonus = 0;
8058
8059 if (attType == RANGED_ATTACK)
8060 {
8062
8063 // ..done (base at attack power and creature type)
8065 }
8066 else
8067 {
8069
8070 // ..done (base at attack power and creature type)
8072 }
8073
8074 if (APbonus != 0) // Can be negative
8075 {
8076 bool const normalized = spellProto && spellProto->HasEffect(SPELL_EFFECT_NORMALIZED_WEAPON_DMG);
8077 DoneFlatBenefit += int32(APbonus / 3.5f * GetAPMultiplier(attType, normalized));
8078 }
8079
8080 // Done total percent damage auras
8081 float DoneTotalMod = 1.0f;
8082
8083 SpellSchoolMask schoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask;
8084
8085 if (!(schoolMask & SPELL_SCHOOL_MASK_NORMAL))
8086 {
8087 // Some spells don't benefit from pct done mods
8088 // mods for SPELL_SCHOOL_MASK_NORMAL are already factored in base melee damage calculation
8089 if (!spellProto || !spellProto->HasAttribute(SPELL_ATTR6_IGNORE_CASTER_DAMAGE_MODIFIERS))
8090 {
8091 float maxModDamagePercentSchool = 0.0f;
8092 if (Player const* thisPlayer = ToPlayer())
8093 {
8094 for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
8095 if (schoolMask & (1 << i))
8096 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, thisPlayer->m_activePlayerData->ModDamageDonePercent[i]);
8097 }
8098 else
8099 maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, schoolMask);
8100
8101 DoneTotalMod *= maxModDamagePercentSchool;
8102 }
8103 }
8104
8105 if (!spellProto)
8106 {
8107 // melee attack
8109 AddPct(DoneTotalMod, autoAttackDamage->GetAmount());
8110 }
8111
8113
8114 // bonus against aurastate
8115 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [pVictim](AuraEffect const* aurEff) -> bool
8116 {
8117 if (pVictim->HasAuraState(AuraStateType(aurEff->GetMiscValue())))
8118 return true;
8119 return false;
8120 });
8121
8122 // bonus against target aura mechanic
8124 {
8125 if (pVictim->HasAuraWithMechanic(UI64LIT(1) << aurEff->GetMiscValue()))
8126 return true;
8127 return false;
8128 });
8129
8130 // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
8131 if (mechanic != MECHANIC_NONE)
8133 else if (spellProto && spellProto->Mechanic)
8135
8136 if (spell)
8137 spell->CallScriptCalcDamageHandlers(*spellEffectInfo, pVictim, damage, DoneFlatBenefit, DoneTotalMod);
8138 else if (aurEff)
8139 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(pVictim->GetGUID()), pVictim, damage, DoneFlatBenefit, DoneTotalMod);
8140
8141 float damageF = float(damage + DoneFlatBenefit) * DoneTotalMod;
8142
8143 // apply spellmod to Done damage
8144 if (spellProto)
8145 if (Player* modOwner = GetSpellModOwner())
8146 modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, damageF);
8147
8148 // bonus result can be negative
8149 return int32(std::max(damageF, 0.0f));
8150}
8151
8152int32 Unit::MeleeDamageBonusTaken(Unit* attacker, int32 pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/)
8153{
8154 if (pdamage == 0)
8155 return 0;
8156
8157 int32 TakenFlatBenefit = 0;
8158
8159 // ..taken
8161
8162 if (attType != RANGED_ATTACK)
8164 else
8166
8167 if ((TakenFlatBenefit < 0) && (pdamage < -TakenFlatBenefit))
8168 return 0;
8169
8170 // Taken total percent damage auras
8171 float TakenTotalMod = 1.0f;
8172
8173 // ..taken
8175
8176 // .. taken pct (special attacks)
8177 if (spellProto)
8178 {
8179 // From caster spells
8180 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SCHOOL_MASK_DAMAGE_FROM_CASTER, [attacker, spellProto](AuraEffect const* aurEff) -> bool
8181 {
8182 return aurEff->GetCasterGUID() == attacker->GetGUID() && (aurEff->GetMiscValue() & spellProto->GetSchoolMask());
8183 });
8184
8185 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER, [attacker, spellProto](AuraEffect const* aurEff) -> bool
8186 {
8187 return aurEff->GetCasterGUID() == attacker->GetGUID() && aurEff->IsAffectingSpell(spellProto);
8188 });
8189
8190 // Mod damage from spell mechanic
8191 uint64 mechanicMask = spellProto->GetAllEffectsMechanicMask();
8192
8193 // Shred, Maul - "Effects which increase Bleed damage also increase Shred damage"
8194 if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x00008800)
8195 mechanicMask |= (1 << MECHANIC_BLEED);
8196
8197 if (mechanicMask)
8198 {
8199 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
8200 {
8201 if (mechanicMask & uint64(UI64LIT(1) << (aurEff->GetMiscValue())))
8202 return true;
8203 return false;
8204 });
8205 }
8206
8207 if (damagetype == DOT)
8208 {
8209 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_PERIODIC_DAMAGE_TAKEN, [spellProto](AuraEffect const* aurEff) -> bool
8210 {
8211 return aurEff->GetMiscValue() & spellProto->GetSchoolMask();
8212 });
8213 }
8214 }
8215 else // melee attack
8216 {
8217 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MELEE_DAMAGE_FROM_CASTER, [attacker](AuraEffect const* aurEff) -> bool
8218 {
8219 return aurEff->GetCasterGUID() == attacker->GetGUID();
8220 });
8221 }
8222
8223 if (AuraEffect const* cheatDeath = GetAuraEffect(45182, EFFECT_0))
8224 AddPct(TakenTotalMod, cheatDeath->GetAmount());
8225
8226 if (attType != RANGED_ATTACK)
8228 else
8230
8231 // Versatility
8232 if (Player* modOwner = GetSpellModOwner())
8233 {
8234 // only 50% of SPELL_AURA_MOD_VERSATILITY for damage reduction
8235 float versaBonus = modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY) / 2.0f;
8236 AddPct(TakenTotalMod, -(modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_TAKEN) + versaBonus));
8237 }
8238
8239 // Sanctified Wrath (bypass damage reduction)
8240 if (TakenTotalMod < 1.0f)
8241 {
8242 SpellSchoolMask const attackSchoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask;
8243
8244 float damageReduction = 1.0f - TakenTotalMod;
8246 for (AuraEffect const* aurEff : casterIgnoreResist)
8247 {
8248 if (!(aurEff->GetMiscValue() & attackSchoolMask))
8249 continue;
8250
8251 AddPct(damageReduction, -aurEff->GetAmount());
8252 }
8253
8254 TakenTotalMod = 1.0f - damageReduction;
8255 }
8256
8257 float tmpDamage = float(pdamage + TakenFlatBenefit) * TakenTotalMod;
8258 return int32(std::max(tmpDamage, 0.0f));
8259}
8260
8261void Unit::ApplySpellImmune(uint32 spellId, SpellImmunity op, uint32 type, bool apply)
8262{
8263 if (apply)
8264 m_spellImmune[op].emplace(type, spellId);
8265 else
8266 {
8267 auto bounds = m_spellImmune[op].equal_range(type);
8268 for (auto itr = bounds.first; itr != bounds.second;)
8269 {
8270 if (itr->second == spellId)
8271 itr = m_spellImmune[op].erase(itr);
8272 else
8273 ++itr;
8274 }
8275 }
8276}
8277
8279{
8280 // normalized proc chance for weapon attack speed
8281 // (odd formula...)
8283 return (GetBaseAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
8285 return (GetBaseAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
8286 return 0;
8287}
8288
8289float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const* spellProto) const
8290{
8291 // proc per minute chance calculation
8292 if (PPM <= 0)
8293 return 0.0f;
8294
8295 // Apply chance modifer aura
8296 if (spellProto)
8297 if (Player* modOwner = GetSpellModOwner())
8298 modOwner->ApplySpellMod(spellProto, SpellModOp::ProcFrequency, PPM);
8299
8300 return std::floor((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8301}
8302
8303void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry)
8304{
8306 if (mount)
8307 SetMountDisplayId(mount);
8308
8310
8312
8313 if (Player* player = ToPlayer())
8314 {
8315 // mount as a vehicle
8316 if (VehicleId)
8317 {
8318 if (CreateVehicleKit(VehicleId, creatureEntry))
8319 {
8320 player->SendOnCancelExpectedVehicleRideAura();
8321
8322 // mounts can also have accessories
8324 }
8325 }
8326
8327 // disable pet controls
8328 player->DisablePetControlsOnMount(REACT_PASSIVE, COMMAND_FOLLOW);
8329
8330 player->SendMovementSetCollisionHeight(player->GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Mount);
8331 }
8332
8334}
8335
8337{
8338 if (!IsMounted())
8339 return;
8340
8343
8344 if (Player* thisPlayer = ToPlayer())
8345 thisPlayer->SendMovementSetCollisionHeight(thisPlayer->GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Mount);
8346
8348
8349 // dismount as a vehicle
8351 {
8352 // Remove vehicle from player
8354 }
8355
8357
8358 // only resummon old pet if the player is already added to a map
8359 // this prevents adding a pet to a not created map which would otherwise cause a crash
8360 // (it could probably happen when logging in after a previous crash)
8361 if (Player* player = ToPlayer())
8362 {
8363 player->EnablePetControlsOnDismount();
8364 player->ResummonPetTemporaryUnSummonedIfAny();
8365 player->ResummonBattlePetTemporaryUnSummonedIfAny();
8366 }
8367}
8368
8370{
8372 return;
8373
8375 {
8376 SpellInfo const* spellInfo = aurApp->GetBase()->GetSpellInfo();
8377 return force || (!spellInfo->HasAttribute(SPELL_ATTR0_NO_AURA_CANCEL) && spellInfo->IsPositive() && !spellInfo->IsPassive());
8378 });
8379}
8380
8382{
8383 if (!mountType)
8384 return nullptr;
8385
8386 DB2Manager::MountTypeXCapabilitySet const* capabilities = sDB2Manager.GetMountCapabilities(mountType);
8387 if (!capabilities)
8388 return nullptr;
8389
8390 uint32 areaId = GetAreaId();
8391 uint32 ridingSkill = 5000;
8393 bool isSubmerged = false;
8394 bool isInWater = false;
8395
8396 if (GetTypeId() == TYPEID_PLAYER)
8397 ridingSkill = ToPlayer()->GetSkillValue(SKILL_RIDING);
8398
8400 {
8402 mountFlags |= AreaMountFlags(auraEffect->GetMiscValue());
8403 }
8404 else if (AreaTableEntry const* areaTable = sAreaTableStore.LookupEntry(areaId))
8405 mountFlags = areaTable->GetMountFlags();
8406
8407 LiquidData liquid;
8408 ZLiquidStatus liquidStatus = GetMap()->GetLiquidStatus(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ(), {}, &liquid);
8409 isSubmerged = (liquidStatus & LIQUID_MAP_UNDER_WATER) != 0 || HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
8410 isInWater = (liquidStatus & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)) != 0;
8411
8412 for (MountTypeXCapabilityEntry const* mountTypeXCapability : *capabilities)
8413 {
8414 MountCapabilityEntry const* mountCapability = sMountCapabilityStore.LookupEntry(mountTypeXCapability->MountCapabilityID);
8415 if (!mountCapability)
8416 continue;
8417
8418 if (ridingSkill < mountCapability->ReqRidingSkill)
8419 continue;
8420
8421 if (!(mountCapability->Flags & MOUNT_CAPABIILTY_FLAG_IGNORE_RESTRICTIONS))
8422 {
8423 if (mountCapability->Flags & MOUNT_CAPABILITY_FLAG_GROUND && !(mountFlags.HasFlag(AreaMountFlags::AllowGroundMounts)))
8424 continue;
8425 if (mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLYING && !(mountFlags.HasFlag(AreaMountFlags::AllowFlyingMounts)))
8426 continue;
8428 continue;
8430 continue;
8431 }
8432
8433 if (!isSubmerged)
8434 {
8435 if (!isInWater)
8436 {
8437 // player is completely out of water
8438 if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_GROUND))
8439 continue;
8440 }
8441 // player is on water surface
8442 else if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLOAT))
8443 continue;
8444 }
8445 else if (isInWater)
8446 {
8447 if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_UNDERWATER))
8448 continue;
8449 }
8450 else if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLOAT))
8451 continue;
8452
8453 if (mountCapability->ReqMapID != -1 &&
8454 int32(GetMapId()) != mountCapability->ReqMapID &&
8455 GetMap()->GetEntry()->CosmeticParentMapID != mountCapability->ReqMapID &&
8456 GetMap()->GetEntry()->ParentMapID != mountCapability->ReqMapID)
8457 continue;
8458
8459 if (mountCapability->ReqAreaID && !DB2Manager::IsInArea(areaId, mountCapability->ReqAreaID))
8460 continue;
8461
8462 if (mountCapability->ReqSpellAuraID && !HasAura(mountCapability->ReqSpellAuraID))
8463 continue;
8464
8465 if (mountCapability->ReqSpellKnownID && !HasSpell(mountCapability->ReqSpellKnownID))
8466 continue;
8467
8468 if (Player const* thisPlayer = ToPlayer())
8469 if (!ConditionMgr::IsPlayerMeetingCondition(thisPlayer, mountCapability->PlayerConditionID))
8470 continue;
8471
8472 return mountCapability;
8473 }
8474
8475 return nullptr;
8476}
8477
8479{
8480 if (IsLoading())
8481 return;
8482
8483 if (SpellShapeshiftFormEntry const* spellShapeshiftForm = sSpellShapeshiftFormStore.LookupEntry(GetShapeshiftForm()))
8484 if (uint32 mountType = spellShapeshiftForm->MountTypeID)
8485 if (!GetMountCapability(mountType))
8487
8489 for (AuraEffect* aurEff : mounts)
8490 {
8491 aurEff->RecalculateAmount();
8492 if (!aurEff->GetAmountAsInt())
8493 aurEff->GetBase()->Remove();
8494 else if (MountCapabilityEntry const* capability = sMountCapabilityStore.LookupEntry(aurEff->GetAmountAsInt())) // aura may get removed by interrupt flag, reapply
8495 {
8496 SetFlightCapabilityID(capability->FlightCapabilityID, true);
8497
8498 if (!HasAura(capability->ModSpellAuraID))
8499 CastSpell(this, capability->ModSpellAuraID, aurEff);
8500 }
8501 }
8502}
8503
8512
8514{
8515 if (!enemy)
8516 return;
8517
8518 if (CanHaveThreatList())
8519 m_threatManager.AddThreat(enemy, 0.0f, nullptr, true, true);
8520 else
8521 SetInCombatWith(enemy);
8522}
8523
8524void Unit::SetImmuneToAll(bool apply, bool keepCombat)
8525{
8526 if (apply)
8527 {
8530 if (!keepCombat)
8532 }
8533 else
8535}
8536
8537void Unit::SetImmuneToPC(bool apply, bool keepCombat)
8538{
8539 if (apply)
8540 {
8543 if (!keepCombat)
8544 {
8545 std::list<CombatReference*> toEnd;
8546 for (auto const& pair : m_combatManager.GetPvECombatRefs())
8547 if (pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8548 toEnd.push_back(pair.second);
8549 for (auto const& pair : m_combatManager.GetPvPCombatRefs())
8550 if (pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8551 toEnd.push_back(pair.second);
8552 for (CombatReference* ref : toEnd)
8553 ref->EndCombat();
8554 }
8555 }
8556 else
8558}
8559
8560void Unit::SetImmuneToNPC(bool apply, bool keepCombat)
8561{
8562 if (apply)
8563 {
8566 if (!keepCombat)
8567 {
8568 std::list<CombatReference*> toEnd;
8569 for (auto const& pair : m_combatManager.GetPvECombatRefs())
8570 if (!pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8571 toEnd.push_back(pair.second);
8572 for (auto const& pair : m_combatManager.GetPvPCombatRefs())
8573 if (!pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8574 toEnd.push_back(pair.second);
8575 for (CombatReference* ref : toEnd)
8576 ref->EndCombat();
8577 }
8578 }
8579 else
8581}
8582
8584{
8585 if (apply)
8587 else
8589}
8590
8591void Unit::SetCannotTurn(bool apply)
8592{
8593 if (apply)
8595 else
8597}
8598
8600{
8602}
8603
8604bool Unit::isTargetableForAttack(bool checkFakeDeath) const
8605{
8606 if (!IsAlive())
8607 return false;
8608
8610 return false;
8611
8612 if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->IsGameMaster())
8613 return false;
8614
8615 return !HasUnitState(UNIT_STATE_UNATTACKABLE) && (!checkFakeDeath || !HasUnitState(UNIT_STATE_DIED));
8616}
8617
8619{
8620 int64 gain = 0;
8621
8622 if (dVal == 0)
8623 return 0;
8624
8625 int64 curHealth = (int64)GetHealth();
8626
8627 int64 val = dVal + curHealth;
8628 if (val <= 0)
8629 {
8630 SetHealth(0);
8631 return -curHealth;
8632 }
8633
8634 int64 maxHealth = (int64)GetMaxHealth();
8635
8636 if (val < maxHealth)
8637 {
8638 SetHealth(val);
8639 gain = val - curHealth;
8640 }
8641 else if (curHealth != maxHealth)
8642 {
8643 SetHealth(maxHealth);
8644 gain = maxHealth - curHealth;
8645 }
8646
8647 if (dVal < 0)
8648 {
8650 packet.Guid = GetGUID();
8651 packet.Health = GetHealth();
8652
8654 player->GetSession()->SendPacket(packet.Write());
8655 }
8656
8657 return gain;
8658}
8659
8661{
8662 int64 gain = 0;
8663
8664 if (dVal == 0)
8665 return 0;
8666
8667 int64 curHealth = (int64)GetHealth();
8668
8669 int64 val = dVal + curHealth;
8670 if (val <= 0)
8671 {
8672 return -curHealth;
8673 }
8674
8675 int64 maxHealth = (int64)GetMaxHealth();
8676
8677 if (val < maxHealth)
8678 gain = dVal;
8679 else if (curHealth != maxHealth)
8680 gain = maxHealth - curHealth;
8681
8682 return gain;
8683}
8684
8686{
8688 return;
8689
8691 for (AuraEffect const* effect : effects)
8692 {
8693 SpellEffectValue triggerHealthPct = effect->GetAmount();
8694 uint32 triggerSpell = effect->GetSpellEffectInfo().TriggerSpell;
8695 uint64 threshold = CountPctFromMaxHealth(triggerHealthPct);
8696
8697 switch (AuraTriggerOnHealthChangeDirection(effect->GetMiscValue()))
8698 {
8700 if (newVal < threshold || oldVal > threshold)
8701 continue;
8702 break;
8704 if (newVal > threshold || oldVal < threshold)
8705 continue;
8706 break;
8707 default:
8708 break;
8709 }
8710
8711 CastSpell(this, triggerSpell, effect);
8712 }
8713}
8714
8715// returns negative amount on power reduction
8716int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true*/)
8717{
8718 int32 gain = 0;
8719
8720 if (dVal == 0)
8721 return 0;
8722
8723 if (dVal > 0)
8725
8726 int32 curPower = GetPower(power);
8727
8728 int32 val = dVal + curPower;
8729 if (val <= GetMinPower(power))
8730 {
8731 SetPower(power, GetMinPower(power), withPowerUpdate);
8732 return -curPower;
8733 }
8734
8735 int32 maxPower = GetMaxPower(power);
8736
8737 if (val < maxPower)
8738 {
8739 SetPower(power, val, withPowerUpdate);
8740 gain = val - curPower;
8741 }
8742 else if (curPower != maxPower)
8743 {
8744 SetPower(power, maxPower, withPowerUpdate);
8745 gain = maxPower - curPower;
8746 }
8747
8748 return gain;
8749}
8750
8752{
8754 return true;
8755
8756 // Always seen by owner
8758 if (!guid.IsEmpty())
8759 if (seer->GetGUID() == guid)
8760 return true;
8761
8762 if (Player const* seerPlayer = seer->ToPlayer())
8763 if (Unit* owner = GetOwner())
8764 if (Player* ownerPlayer = owner->ToPlayer())
8765 if (ownerPlayer->IsGroupVisibleFor(seerPlayer))
8766 return true;
8767
8768 return false;
8769}
8770
8772{
8774 return true;
8775
8777 return true;
8778
8779 return false;
8780}
8781
8783{
8785}
8786
8796
8798{
8799 float main_speed_mod = 0.0f;
8800 float stack_bonus = 1.0f;
8801 float non_stack_bonus = 1.0f;
8802
8803 switch (mtype)
8804 {
8805 // Only apply debuffs
8806 case MOVE_FLIGHT_BACK:
8807 case MOVE_RUN_BACK:
8808 case MOVE_SWIM_BACK:
8809 break;
8810 case MOVE_WALK:
8811 return;
8812 case MOVE_RUN:
8813 {
8814 if (IsMounted()) // Use on mount auras
8815 {
8819 }
8820 else
8821 {
8825 }
8826 break;
8827 }
8828 case MOVE_SWIM:
8829 {
8831 break;
8832 }
8833 case MOVE_FLIGHT:
8834 {
8835 if (GetTypeId() == TYPEID_UNIT && IsControlledByPlayer()) // not sure if good for pet
8836 {
8839
8840 // for some spells this mod is applied on vehicle owner
8841 float owner_speed_mod = 0.0f;
8842
8843 if (Unit* owner = GetCharmer())
8844 owner_speed_mod = owner->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED);
8845
8846 main_speed_mod = std::max(main_speed_mod, owner_speed_mod);
8847 }
8848 else if (IsMounted())
8849 {
8852 }
8853 else // Use not mount (shapeshift for example) auras (should stack)
8855
8857
8858 // Update speed for vehicle if available
8859 if (GetTypeId() == TYPEID_PLAYER && GetVehicle())
8861 break;
8862 }
8863 default:
8864 TC_LOG_ERROR("entities.unit", "Unit::UpdateSpeed: Unsupported move type ({})", mtype);
8865 return;
8866 }
8867
8868 // now we ready for speed calculation
8869 float speed = std::max(non_stack_bonus, stack_bonus);
8870 if (main_speed_mod)
8871 AddPct(speed, main_speed_mod);
8872
8873 switch (mtype)
8874 {
8875 case MOVE_RUN:
8876 case MOVE_SWIM:
8877 case MOVE_FLIGHT:
8878 {
8879 // Set creature speed rate
8880 if (GetTypeId() == TYPEID_UNIT)
8881 speed *= ToCreature()->GetCreatureTemplate()->speed_run; // at this point, MOVE_WALK is never reached
8882
8883 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8886 {
8887 if (Creature* creature = ToCreature())
8888 if (CreatureImmunities const* immunities = SpellMgr::GetCreatureImmunities(creature->GetCreatureTemplate()->CreatureImmunitiesId))
8889 if (immunities->Mechanic[MECHANIC_SNARE] || immunities->Mechanic[MECHANIC_DAZE])
8890 break;
8891
8892 // Use speed from aura
8893 float max_speed = normalization / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8894 if (speed > max_speed)
8895 speed = max_speed;
8896 }
8897
8898 if (mtype == MOVE_RUN)
8899 {
8900 // force minimum speed rate @ aura 437 SPELL_AURA_MOD_MINIMUM_SPEED_RATE
8902 {
8903 float minSpeed = minSpeedMod / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8904 if (speed < minSpeed)
8905 speed = minSpeed;
8906 }
8907 }
8908 break;
8909 }
8910 default:
8911 break;
8912 }
8913
8914 if (Creature* creature = ToCreature())
8915 {
8916 if (creature->HasUnitTypeMask(UNIT_MASK_MINION) && !creature->IsInCombat())
8917 {
8919 {
8920 Unit* followed = ASSERT_NOTNULL(dynamic_cast<AbstractFollower*>(GetMotionMaster()->GetCurrentMovementGenerator()))->GetTarget();
8921 if (followed && followed->GetGUID() == GetOwnerGUID() && !followed->IsInCombat())
8922 {
8923 float ownerSpeed = followed->GetSpeedRate(mtype);
8924 if (speed < ownerSpeed || creature->IsWithinDist3d(followed, 10.0f))
8925 speed = ownerSpeed;
8926 speed *= std::min(std::max(1.0f, 0.75f + (GetDistance(followed) - PET_FOLLOW_DIST) * 0.05f), 1.3f);
8927 }
8928 }
8929 }
8930 }
8931
8932 // Apply strongest slow aura mod to speed
8934 if (slow)
8935 AddPct(speed, slow);
8936
8938 {
8939 float baseMinSpeed = 1.0f;
8940 if (!GetOwnerGUID().IsPlayer() && !IsHunterPet() && GetTypeId() == TYPEID_UNIT)
8941 baseMinSpeed = ToCreature()->GetCreatureTemplate()->speed_run;
8942
8943 float min_speed = CalculatePct(baseMinSpeed, minSpeedMod);
8944 if (speed < min_speed)
8945 speed = min_speed;
8946 }
8947
8948 SetSpeedRate(mtype, speed);
8949}
8950
8952{
8953 return m_speed_rate[mtype]*(IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8954}
8955
8956void Unit::SetSpeed(UnitMoveType mtype, float newValue)
8957{
8958 SetSpeedRate(mtype, newValue / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]));
8959}
8960
8961void Unit::SetSpeedRate(UnitMoveType mtype, float rate)
8962{
8963 rate = std::max(rate, 0.01f);
8964
8965 // Update speed only on change
8966 if (m_speed_rate[mtype] == rate)
8967 return;
8968
8969 m_speed_rate[mtype] = rate;
8970
8972
8973 // Spline packets are for creatures and move_update are for players
8974 static OpcodeServer const moveTypeToOpcode[MAX_MOVE_TYPE][3] =
8975 {
8985 };
8986
8987 if (GetTypeId() == TYPEID_PLAYER)
8988 {
8989 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8990 // and do it only for real sent packets and use run for run/mounted as client expected
8991 ++ToPlayer()->m_forced_speed_changes[mtype];
8992
8993 if (!IsInCombat())
8994 if (Pet* pet = ToPlayer()->GetPet())
8995 pet->SetSpeedRate(mtype, m_speed_rate[mtype]);
8996 }
8997
8998 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved())) // unit controlled by a player.
8999 {
9000 // Send notification to self
9001 WorldPackets::Movement::MoveSetSpeed selfpacket(moveTypeToOpcode[mtype][1]);
9002 selfpacket.MoverGUID = GetGUID();
9003 selfpacket.SequenceIndex = m_movementCounter++;
9004 selfpacket.Speed = GetSpeed(mtype);
9005 playerMover->GetSession()->SendPacket(selfpacket.Write());
9006
9007 // Send notification to other players
9008 WorldPackets::Movement::MoveUpdateSpeed packet(moveTypeToOpcode[mtype][2]);
9009 packet.Status = &m_movementInfo;
9010 packet.Speed = GetSpeed(mtype);
9011 playerMover->SendMessageToSet(packet.Write(), false);
9012 }
9013 else
9014 {
9015 WorldPackets::Movement::MoveSplineSetSpeed packet(moveTypeToOpcode[mtype][0]);
9016 packet.MoverGUID = GetGUID();
9017 packet.Speed = GetSpeed(mtype);
9018 SendMessageToSet(packet.Write(), true);
9019 }
9020}
9021
9043
9044void Unit::UpdateAdvFlyingSpeed(AdvFlyingRateTypeSingle speedType, bool clientUpdate)
9045{
9046 FlightCapabilityEntry const* flightCapabilityEntry = sFlightCapabilityStore.LookupEntry(GetFlightCapabilityID());
9047 if (!flightCapabilityEntry)
9048 flightCapabilityEntry = sFlightCapabilityStore.AssertEntry(1);
9049
9050 auto [opcode, newValue, rateAura] = [&]
9051 {
9052 switch (speedType)
9053 {
9056 case ADV_FLYING_MAX_VEL:
9057 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_MAX_VEL, flightCapabilityEntry->MaxVel, SPELL_AURA_MOD_ADV_FLYING_MAX_VEL);
9061 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_DOUBLE_JUMP_VEL_MOD, flightCapabilityEntry->DoubleJumpVelMod, SPELL_AURA_NONE);
9067 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_SURFACE_FRICTION, flightCapabilityEntry->SurfaceFriction, SPELL_AURA_NONE);
9072 default:
9073 return std::tuple<OpcodeServer, float, AuraType>();
9074 }
9075 }();
9076
9077 if (rateAura != SPELL_AURA_NONE)
9078 {
9079 // take only lowest negative and highest positive auras - these effects do not stack
9080 if (float neg = GetMaxNegativeAuraModifier(rateAura, [](AuraEffect const* mod) { return mod->GetAmount() > 0 && mod->GetAmount() < 100; }))
9081 ApplyPct(newValue, neg);
9082
9083 if (float pos = GetMaxPositiveAuraModifier(rateAura, [](AuraEffect const* mod) { return mod->GetAmount() > 100; }))
9084 ApplyPct(newValue, pos);
9085 }
9086
9087 if (m_advFlyingSpeed[speedType] == newValue)
9088 return;
9089
9090 m_advFlyingSpeed[speedType] = newValue;
9091
9092 if (!clientUpdate)
9093 return;
9094
9095 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
9096 {
9098 selfpacket.MoverGUID = GetGUID();
9099 selfpacket.SequenceIndex = m_movementCounter++;
9100 selfpacket.Speed = newValue;
9101 playerMover->GetSession()->SendPacket(selfpacket.Write());
9102 }
9103}
9104
9105void Unit::UpdateAdvFlyingSpeed(AdvFlyingRateTypeRange speedType, bool clientUpdate)
9106{
9107 FlightCapabilityEntry const* flightCapabilityEntry = sFlightCapabilityStore.LookupEntry(GetFlightCapabilityID());
9108 if (!flightCapabilityEntry)
9109 flightCapabilityEntry = sFlightCapabilityStore.AssertEntry(1);
9110
9111 auto [opcode, min, max, rateAura] = [&]
9112 {
9113 switch (speedType)
9114 {
9116 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_BANKING_RATE, flightCapabilityEntry->BankingRateMin, flightCapabilityEntry->BankingRateMax, SPELL_AURA_MOD_ADV_FLYING_BANKING_RATE);
9120 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_PITCHING_RATE_UP, flightCapabilityEntry->PitchingRateUpMin, flightCapabilityEntry->PitchingRateUpMax, SPELL_AURA_MOD_ADV_FLYING_PITCHING_RATE_UP);
9122 return std::tuple(SMSG_MOVE_SET_ADV_FLYING_TURN_VELOCITY_THRESHOLD, flightCapabilityEntry->TurnVelocityThresholdMin, flightCapabilityEntry->TurnVelocityThresholdMax, SPELL_AURA_NONE);
9123 default:
9124 return std::tuple<OpcodeServer, float, float, AuraType>();
9125 }
9126 }();
9127
9128 if (rateAura != SPELL_AURA_NONE)
9129 {
9130 // take only lowest negative and highest positive auras - these effects do not stack
9131 if (float neg = GetMaxNegativeAuraModifier(rateAura, [](AuraEffect const* mod) { return mod->GetAmount() > 0 && mod->GetAmount() < 100; }))
9132 {
9133 ApplyPct(min, neg);
9134 ApplyPct(max, neg);
9135 }
9136
9137 if (float pos = GetMaxPositiveAuraModifier(rateAura, [](AuraEffect const* mod) { return mod->GetAmount() > 100; }))
9138 {
9139 ApplyPct(min, pos);
9140 ApplyPct(max, pos);
9141 }
9142 }
9143
9144 if (m_advFlyingSpeed[speedType] == min && m_advFlyingSpeed[speedType + 1] == max)
9145 return;
9146
9147 m_advFlyingSpeed[speedType] = min;
9148 m_advFlyingSpeed[speedType + 1] = max;
9149
9150 if (!clientUpdate)
9151 return;
9152
9153 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
9154 {
9156 selfpacket.MoverGUID = GetGUID();
9157 selfpacket.SequenceIndex = m_movementCounter++;
9158 selfpacket.SpeedMin = min;
9159 selfpacket.SpeedMax = max;
9160 playerMover->GetSession()->SendPacket(selfpacket.Write());
9161 }
9162}
9163
9165{
9166 m_followingMe.insert(f);
9167}
9168
9170{
9171 m_followingMe.erase(f);
9172}
9173
9175{
9176 while (!m_followingMe.empty())
9177 (*m_followingMe.begin())->SetTarget(nullptr);
9178}
9179
9181{
9182 // Death state needs to be updated before RemoveAllAurasOnDeath() is called, to prevent entering combat
9183 m_deathState = s;
9184
9185 bool isOnVehicle = GetVehicle() != nullptr;
9186
9187 if (s != ALIVE && s != JUST_RESPAWNED)
9188 {
9189 CombatStop();
9190
9191 if (IsNonMeleeSpellCast(false))
9193
9194 ExitVehicle(); // Exit vehicle before calling RemoveAllControlled
9195 // vehicles use special type of charm that is not removed by the next function
9196 // triggering an assert
9200 }
9201
9202 if (s == JUST_DIED)
9203 {
9204 // remove aurastates allowing special moves
9207
9208 // Don't clear the movement if the Unit was on a vehicle as we are exiting now
9209 if (!isOnVehicle)
9210 {
9211 if (GetMotionMaster()->StopOnDeath())
9212 DisableSpline();
9213 }
9214
9215 // without this when removing IncreaseMaxHealth aura player may stuck with 1 hp
9216 // do not why since in IncreaseMaxHealth currenthealth is checked
9217 SetHealth(0);
9218 SetPower(GetPowerType(), 0);
9221
9222 if (m_vignette && !m_vignette->Data->GetFlags().HasFlag(VignetteFlags::PersistsThroughDeath))
9223 SetVignette(0);
9224
9225 // players in instance don't have ZoneScript, but they have InstanceScript
9226 if (ZoneScript* zoneScript = GetZoneScript() ? GetZoneScript() : GetInstanceScript())
9227 zoneScript->OnUnitDeath(this);
9228 }
9229 else if (s == JUST_RESPAWNED)
9230 RemoveUnitFlag(UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground)
9231}
9232
9233//======================================================================
9234
9236{
9237 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end();)
9238 {
9239 AuraApplication* aurApp = itr->second;
9240 ++itr;
9241
9242 aurApp->GetBase()->CallScriptEnterLeaveCombatHandlers(aurApp, true);
9243 }
9244
9246 if (spell->getState() == SPELL_STATE_PREPARING
9247 && spell->m_spellInfo->HasAttribute(SPELL_ATTR0_NOT_IN_COMBAT_ONLY_PEACEFUL)
9248 && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Combat)
9249 && !spell->m_spellInfo->HasAura(SPELL_AURA_MOUNTED)) // for some reason mounts are not interrupted by entering combat even with both interrupt flag and attribute
9251
9254
9257}
9258
9260{
9261 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end();)
9262 {
9263 AuraApplication* aurApp = itr->second;
9264 ++itr;
9265
9266 aurApp->GetBase()->CallScriptEnterLeaveCombatHandlers(aurApp, false);
9267 }
9268
9270
9272
9275}
9276
9282
9283void Unit::AtTargetAttacked(Unit* target, bool canInitialAggro)
9284{
9285 if (!target->IsEngaged() && !canInitialAggro)
9286 return;
9287 target->EngageWithTarget(this);
9288 if (Unit* targetOwner = target->GetCharmerOrOwner())
9289 targetOwner->EngageWithTarget(this);
9290
9292 Player* targetPlayerOwner = target->GetCharmerOrOwnerPlayerOrPlayerItself();
9293 if (myPlayerOwner && targetPlayerOwner && !(myPlayerOwner->duel && myPlayerOwner->duel->Opponent == targetPlayerOwner))
9294 {
9295 myPlayerOwner->UpdatePvP(true);
9296 myPlayerOwner->SetContestedPvP(targetPlayerOwner);
9298 }
9299}
9300
9302{
9303 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
9304
9305 bool state = false;
9306 for (Unit* minion : m_Controlled)
9307 if (minion->IsInCombat())
9308 {
9309 state = true;
9310 break;
9311 }
9312
9313 if (state)
9315 else
9317}
9318
9319void Unit::SetInteractionAllowedWhileHostile(bool interactionAllowed)
9320{
9321 if (interactionAllowed)
9323 else
9325
9327}
9328
9339
9347
9348//======================================================================
9349
9351{
9352 DiminishingReturn const& diminish = m_Diminishing[group];
9353 if (!diminish.hitCount)
9354 return DIMINISHING_LEVEL_1;
9355
9356 // If last spell was cast more than 18 seconds ago - reset level.
9357 if (!diminish.stack && GetMSTimeDiffToNow(diminish.hitTime) > 18 * IN_MILLISECONDS)
9358 return DIMINISHING_LEVEL_1;
9359
9360 return DiminishingLevels(diminish.hitCount);
9361}
9362
9363void Unit::IncrDiminishing(SpellInfo const* auraSpellInfo)
9364{
9366 uint32 currentLevel = GetDiminishing(group);
9367 uint32 const maxLevel = auraSpellInfo->GetDiminishingReturnsMaxLevel();
9368
9369 DiminishingReturn& diminish = m_Diminishing[group];
9370 if (currentLevel < maxLevel)
9371 diminish.hitCount = currentLevel + 1;
9372}
9373
9374bool Unit::ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, int32& duration, WorldObject* caster, DiminishingLevels previousLevel) const
9375{
9376 DiminishingGroup const group = auraSpellInfo->GetDiminishingReturnsGroupForSpell();
9377 if (duration == -1 || group == DIMINISHING_NONE)
9378 return true;
9379
9380 int32 const limitDuration = auraSpellInfo->GetDiminishingReturnsLimitDuration();
9381
9382 // test pet/charm masters instead pets/charmeds
9383 Unit const* targetOwner = GetCharmerOrOwner();
9384 Unit const* casterOwner = caster->GetCharmerOrOwner();
9385
9386 if (limitDuration > 0 && duration > limitDuration)
9387 {
9388 Unit const* target = targetOwner ? targetOwner : this;
9389 WorldObject const* source = casterOwner ? casterOwner : caster;
9390
9391 if (target->IsAffectedByDiminishingReturns() && source->GetTypeId() == TYPEID_PLAYER)
9392 duration = limitDuration;
9393 }
9394
9395 float mod = 1.0f;
9396 switch (group)
9397 {
9398 case DIMINISHING_TAUNT:
9399 {
9400 if (GetTypeId() == TYPEID_UNIT && (ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS))
9401 {
9402 DiminishingLevels diminish = previousLevel;
9403 switch (diminish)
9404 {
9405 case DIMINISHING_LEVEL_1: break;
9406 case DIMINISHING_LEVEL_2: mod = 0.65f; break;
9407 case DIMINISHING_LEVEL_3: mod = 0.4225f; break;
9408 case DIMINISHING_LEVEL_4: mod = 0.274625f; break;
9409 case DIMINISHING_LEVEL_TAUNT_IMMUNE: mod = 0.0f; break;
9410 default: break;
9411 }
9412 }
9413 break;
9414 }
9416 {
9417 if (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_ALL ||
9418 (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_PLAYER &&
9419 (targetOwner ? targetOwner->IsAffectedByDiminishingReturns() : IsAffectedByDiminishingReturns())))
9420 {
9421 DiminishingLevels diminish = previousLevel;
9422 switch (diminish)
9423 {
9424 case DIMINISHING_LEVEL_1: break;
9425 case DIMINISHING_LEVEL_2: mod = 0.0f; break;
9426 default: break;
9427 }
9428 }
9429 break;
9430 }
9431 default:
9432 {
9433 if (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_ALL ||
9434 (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_PLAYER &&
9435 (targetOwner ? targetOwner->IsAffectedByDiminishingReturns() : IsAffectedByDiminishingReturns())))
9436 {
9437 DiminishingLevels diminish = previousLevel;
9438 switch (diminish)
9439 {
9440 case DIMINISHING_LEVEL_1: break;
9441 case DIMINISHING_LEVEL_2: mod = 0.5f; break;
9442 case DIMINISHING_LEVEL_3: mod = 0.25f; break;
9443 case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f; break;
9444 default: break;
9445 }
9446 }
9447 break;
9448 }
9449 }
9450
9451 duration = int32(duration * mod);
9452 return (duration != 0);
9453}
9454
9456{
9457 // Checking for existing in the table
9458 DiminishingReturn& diminish = m_Diminishing[group];
9459
9460 if (apply)
9461 ++diminish.stack;
9462 else if (diminish.stack)
9463 {
9464 --diminish.stack;
9465
9466 // Remember time after last aura from group removed
9467 if (!diminish.stack)
9468 diminish.hitTime = GameTime::GetGameTimeMS();
9469 }
9470}
9471
9473{
9474 for (DiminishingReturn& dim : m_Diminishing)
9475 dim.Clear();
9476}
9477
9479{
9480 if (GetTypeId() == TYPEID_PLAYER)
9481 {
9483 SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form);
9484 if (ssEntry && ssEntry->CreatureType > 0)
9485 return ssEntry->CreatureType;
9486 else
9487 {
9488 ChrRacesEntry const* raceEntry = sChrRacesStore.AssertEntry(GetRace());
9489 return raceEntry->CreatureType;
9490 }
9491 }
9492 else
9493 return ToCreature()->GetCreatureTemplate()->type;
9494}
9495
9497{
9498 uint32 creatureType = GetCreatureType();
9499 return (creatureType >= 1) ? (1 << (creatureType - 1)) : 0;
9500}
9501
9503{
9504 uint8 creatureType = [&]() -> uint8
9505 {
9506 if (Creature const* creature = ToCreature())
9507 return creature->GetCreatureTemplate()->type;
9508
9510 SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form);
9511 if (ssEntry && ssEntry->CreatureType > 0)
9512 return ssEntry->CreatureType;
9513
9514 ChrRacesEntry const* raceEntry = sChrRacesStore.AssertEntry(GetRace());
9515 return raceEntry->CreatureType;
9516 }();
9517
9519}
9520
9526
9527void Unit::CancelShapeshiftForm(bool onlyTravelShapeshiftForm /*= false*/, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/, bool force /*= false*/)
9528{
9530 if (form == FORM_NONE)
9531 return;
9532
9533 bool isTravelShapeshiftForm = [form]()
9534 {
9535 if (SpellShapeshiftFormEntry const* shapeInfo = sSpellShapeshiftFormStore.LookupEntry(form))
9536 {
9537 if (shapeInfo->MountTypeID)
9538 return true;
9539
9540 if (shapeInfo->ID == FORM_TRAVEL_FORM || shapeInfo->ID == FORM_AQUATIC_FORM)
9541 return true;
9542 }
9543
9544 return false;
9545 }();
9546
9547 if (onlyTravelShapeshiftForm && !isTravelShapeshiftForm)
9548 return;
9549
9551 for (AuraEffect* aurEff : shapeshifts)
9552 {
9553 SpellInfo const* spellInfo = aurEff->GetBase()->GetSpellInfo();
9554 if (force || (!spellInfo->HasAttribute(SPELL_ATTR0_NO_AURA_CANCEL) && spellInfo->IsPositive() && !spellInfo->IsPassive()))
9555 aurEff->GetBase()->Remove(removeMode);
9556 }
9557}
9558
9560{
9562 return form == FORM_CAT_FORM || form == FORM_BEAR_FORM || form == FORM_DIRE_BEAR_FORM || form == FORM_GHOST_WOLF;
9563}
9564
9569
9570bool Unit::IsDisallowedMountForm(uint32 spellId, ShapeshiftForm form, uint32 displayId) const
9571{
9572 if (SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()))
9573 if (transformSpellInfo->HasAttribute(SPELL_ATTR0_ALLOW_WHILE_MOUNTED))
9574 return false;
9575
9576 if (form)
9577 {
9578 SpellShapeshiftFormEntry const* shapeshift = sSpellShapeshiftFormStore.LookupEntry(form);
9579 if (!shapeshift)
9580 return true;
9581
9582 if (!shapeshift->GetFlags().HasFlag(SpellShapeshiftFormFlags::Stance))
9583 return true;
9584 }
9585
9586 if (displayId == GetNativeDisplayId())
9587 return false;
9588
9589 CreatureDisplayInfoEntry const* display = sCreatureDisplayInfoStore.LookupEntry(displayId);
9590 if (!display)
9591 return true;
9592
9594 if (!displayExtra)
9595 return true;
9596
9597 CreatureModelDataEntry const* model = sCreatureModelDataStore.LookupEntry(display->ModelID);
9598 ChrRacesEntry const* race = sChrRacesStore.LookupEntry(displayExtra->DisplayRaceID);
9599
9601 if (race && !race->GetFlags().HasFlag(ChrRacesFlag::CanMount))
9602 return true;
9603
9604 return false;
9605}
9606
9607/*#######################################
9608######## ########
9609######## STAT SYSTEM ########
9610######## ########
9611#######################################*/
9612
9613void ApplyPercentModFloatVar(float& var, float val, bool apply)
9614{
9615 var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
9616}
9617
9618void Unit::HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
9619{
9620 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END)
9621 {
9622 TC_LOG_ERROR("entities.unit", "ERROR in HandleStatFlatModifier(): non-existing UnitMods or wrong UnitModifierType!");
9623 return;
9624 }
9625
9626 if (!amount)
9627 return;
9628
9629 switch (modifierType)
9630 {
9631 case BASE_VALUE:
9632 case TOTAL_VALUE:
9633 m_auraFlatModifiersGroup[unitMod][modifierType] += apply ? amount : -amount;
9634 break;
9635 default:
9636 break;
9637 }
9638
9639 UpdateUnitMod(unitMod);
9640}
9641
9642void Unit::ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float pct)
9643{
9644 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
9645 {
9646 TC_LOG_ERROR("entities.unit", "ERROR in ApplyStatPctModifier(): non-existing UnitMods or wrong UnitModifierType!");
9647 return;
9648 }
9649
9650 if (!pct)
9651 return;
9652
9653 switch (modifierType)
9654 {
9655 case BASE_PCT:
9656 case TOTAL_PCT:
9657 AddPct(m_auraPctModifiersGroup[unitMod][modifierType], pct);
9658 break;
9659 default:
9660 break;
9661 }
9662
9663 UpdateUnitMod(unitMod);
9664}
9665
9666void Unit::SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
9667{
9668 if (m_auraFlatModifiersGroup[unitMod][modifierType] == val)
9669 return;
9670
9671 m_auraFlatModifiersGroup[unitMod][modifierType] = val;
9672 UpdateUnitMod(unitMod);
9673}
9674
9675void Unit::SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
9676{
9677 if (m_auraPctModifiersGroup[unitMod][modifierType] == val)
9678 return;
9679
9680 m_auraPctModifiersGroup[unitMod][modifierType] = val;
9681 UpdateUnitMod(unitMod);
9682}
9683
9685{
9686 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END)
9687 {
9688 TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
9689 return 0.0f;
9690 }
9691
9692 return m_auraFlatModifiersGroup[unitMod][modifierType];
9693}
9694
9696{
9697 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
9698 {
9699 TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
9700 return 1.0f;
9701 }
9702
9703 return m_auraPctModifiersGroup[unitMod][modifierType];
9704}
9705
9707{
9708 if (!CanModifyStats())
9709 return;
9710
9711 switch (unitMod)
9712 {
9718
9719 case UNIT_MOD_ARMOR: UpdateArmor(); break;
9720 case UNIT_MOD_HEALTH: UpdateMaxHealth(); break;
9721
9722 case UNIT_MOD_MANA:
9723 case UNIT_MOD_RAGE:
9724 case UNIT_MOD_FOCUS:
9725 case UNIT_MOD_ENERGY:
9727 case UNIT_MOD_RUNES:
9732 case UNIT_MOD_ALTERNATE:
9733 case UNIT_MOD_MAELSTROM:
9734 case UNIT_MOD_CHI:
9735 case UNIT_MOD_INSANITY:
9739 case UNIT_MOD_FURY:
9740 case UNIT_MOD_PAIN:
9741 case UNIT_MOD_ESSENCE:
9748
9755
9759
9760 default:
9761 ABORT_MSG("Not implemented UnitMod %u", unitMod);
9762 break;
9763 }
9764}
9765
9766void Unit::HandleAttackPowerModifier(AttackPowerModIndex index, AttackPowerModType modifierType, float amount, bool apply)
9767{
9768 if (index >= AttackPowerModIndex::End || modifierType >= AttackPowerModType::End)
9769 {
9770 TC_LOG_ERROR("entities.unit", "ERROR in HandleAttackPowerModifier(): non-existing AttackPowerModIndex or wrong AttackPowerModType!");
9771 return;
9772 }
9773
9774 switch (modifierType)
9775 {
9777 ApplyPercentModFloatVar(m_attackPowerMods[uint32(index)][uint32(modifierType)], amount, apply);
9778 break;
9779 default:
9780 m_attackPowerMods[uint32(index)][uint32(modifierType)] += apply ? amount : -amount;
9781 break;
9782 }
9783
9784 if (!CanModifyStats())
9785 return;
9786
9788}
9789
9791{
9792 if (index >= AttackPowerModIndex::End || modifierType >= AttackPowerModType::End)
9793 {
9794 TC_LOG_ERROR("entities.unit", "ERROR in GetAttackPowerModifierValue(): non-existing AttackPowerModIndex or wrong AttackPowerModType!");
9795 return 0.0f;
9796 }
9797
9798 return m_attackPowerMods[uint32(index)][uint32(modifierType)];
9799}
9800
9801void Unit::UpdateDamageDoneMods(WeaponAttackType attackType, int32 /*skipEnchantSlot = -1*/)
9802{
9803 UnitMods unitMod;
9804 switch (attackType)
9805 {
9806 case BASE_ATTACK:
9807 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
9808 break;
9809 case OFF_ATTACK:
9810 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
9811 break;
9812 case RANGED_ATTACK:
9813 unitMod = UNIT_MOD_DAMAGE_RANGED;
9814 break;
9815 default:
9816 ABORT();
9817 break;
9818 }
9819
9820 float amount = GetTotalAuraModifier(SPELL_AURA_MOD_DAMAGE_DONE, [&](AuraEffect const* aurEff) -> bool
9821 {
9822 if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
9823 return false;
9824
9825 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9826 });
9827
9828 SetStatFlatModifier(unitMod, TOTAL_VALUE, amount);
9829}
9830
9836
9838{
9839 float factor;
9840 UnitMods unitMod;
9841 switch (attackType)
9842 {
9843 case BASE_ATTACK:
9844 factor = 1.0f;
9845 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
9846 break;
9847 case OFF_ATTACK:
9848 // off hand has 50% penalty
9849 factor = 0.5f;
9850 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
9851 break;
9852 case RANGED_ATTACK:
9853 factor = 1.0f;
9854 unitMod = UNIT_MOD_DAMAGE_RANGED;
9855 break;
9856 default:
9857 ABORT();
9858 break;
9859 }
9860
9861 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, [attackType, this](AuraEffect const* aurEff) -> bool
9862 {
9863 if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
9864 return false;
9865
9866 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9867 });
9868
9869 if (attackType == OFF_ATTACK)
9870 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT, [this, attackType](AuraEffect const* aurEff)
9871 {
9872 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9873 });
9874
9875 SetStatPctModifier(unitMod, TOTAL_PCT, factor);
9876}
9877
9883
9885{
9887
9888 // value = (base_value * base_pct) * total_pct + total_value * total_pct
9889 float baseValue = GetFlatModifierValue(unitMod, BASE_VALUE);
9890 baseValue *= GetPctModifierValue(unitMod, BASE_PCT);
9891 baseValue *= GetPctModifierValue(unitMod, TOTAL_PCT);
9892
9893 float totalValue = GetFlatModifierValue(unitMod, TOTAL_VALUE);
9895 totalValue *= GetPctModifierValue(unitMod, TOTAL_PCT);
9896
9897 return baseValue + totalValue;
9898}
9899
9901{
9902 if (unitMod >= UNIT_MOD_END)
9903 {
9904 TC_LOG_ERROR("entities.unit", "attempt to access non-existing UnitMods in GetTotalAuraModValue()!");
9905 return 0.0f;
9906 }
9907
9908 float value = GetFlatModifierValue(unitMod, BASE_VALUE);
9909 value *= GetPctModifierValue(unitMod, BASE_PCT);
9910 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9911 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9912
9913 return value;
9914}
9915
9917{
9919
9920 switch (unitMod)
9921 {
9922 case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break;
9923 case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break;
9924 case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break;
9925 case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break;
9926 case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break;
9927 case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break;
9928
9929 default:
9930 break;
9931 }
9932
9933 return school;
9934}
9935
9937{
9938 Stats stat = STAT_STRENGTH;
9939
9940 switch (unitMod)
9941 {
9942 case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break;
9943 case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break;
9944 case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break;
9945 case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break;
9946 case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break;
9947 default:
9948 break;
9949 }
9950
9951 return stat;
9952}
9953
9955{
9956 if (school > SPELL_SCHOOL_NORMAL)
9957 {
9958 UnitMods unitMod = UnitMods(UNIT_MOD_RESISTANCE_START + school);
9959
9960 float value = GetFlatModifierValue(unitMod, BASE_VALUE);
9961 value *= GetPctModifierValue(unitMod, BASE_PCT);
9962
9963 float baseValue = value;
9964
9965 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9966 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9967
9968 SetResistance(SpellSchools(school), int32(value));
9969 SetBonusResistanceMod(SpellSchools(school), int32(value - baseValue));
9970 }
9971 else
9972 UpdateArmor();
9973}
9974
9975float Unit::GetTotalAttackPowerValue(WeaponAttackType attType, bool includeWeapon /*= true*/) const
9976{
9977 if (attType == RANGED_ATTACK)
9978 {
9979 float ap = m_unitData->RangedAttackPower + m_unitData->RangedAttackPowerModPos + m_unitData->RangedAttackPowerModNeg;
9980 if (includeWeapon)
9981 ap += std::max<float>(m_unitData->MainHandWeaponAttackPower, m_unitData->RangedWeaponAttackPower);
9982 if (ap < 0)
9983 return 0.0f;
9984 return ap * (1.0f + m_unitData->RangedAttackPowerMultiplier);
9985 }
9986 else
9987 {
9988 float ap = m_unitData->AttackPower + m_unitData->AttackPowerModPos + m_unitData->AttackPowerModNeg;
9989 if (includeWeapon)
9990 {
9991 if (attType == BASE_ATTACK)
9992 ap += std::max<float>(m_unitData->MainHandWeaponAttackPower, m_unitData->RangedWeaponAttackPower);
9993 else
9994 {
9995 ap += m_unitData->OffHandWeaponAttackPower;
9996 ap /= 2;
9997 }
9998 }
9999 if (ap < 0)
10000 return 0.0f;
10001 return ap * (1.0f + m_unitData->AttackPowerMultiplier);
10002 }
10003}
10004
10006{
10007 if (attType == OFF_ATTACK && !haveOffhandWeapon())
10008 return 0.0f;
10009
10010 return m_weaponDamage[attType][type];
10011}
10012
10018
10019void Unit::SetLevel(uint8 lvl, bool sendUpdate/* = true*/)
10020{
10022
10023 if (!sendUpdate)
10024 return;
10025
10026 if (Player* player = ToPlayer())
10027 {
10028 // group update
10029 if (player->GetGroup())
10030 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL);
10031
10032 sCharacterCache->UpdateCharacterLevel(GetGUID(), lvl);
10033 }
10034}
10035
10040
10042{
10044 val = 0;
10045 else if (GetTypeId() == TYPEID_PLAYER && getDeathState() == DEAD)
10046 val = 1;
10047 else
10048 {
10049 uint64 maxHealth = GetMaxHealth();
10050 if (maxHealth < val)
10051 val = maxHealth;
10052 }
10053
10054 uint64 oldVal = GetHealth();
10056
10057 TriggerOnHealthChangeAuras(oldVal, val);
10058
10059 // group update
10060 if (Player* player = ToPlayer())
10061 {
10062 if (player->GetGroup())
10063 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP);
10064 }
10065 else if (Pet* pet = ToCreature()->ToPet())
10066 {
10067 if (pet->isControlled())
10068 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP);
10069 }
10070}
10071
10073{
10074 if (!val)
10075 val = 1;
10076
10077 uint64 health = GetHealth();
10079
10080 // group update
10081 if (GetTypeId() == TYPEID_PLAYER)
10082 {
10083 if (ToPlayer()->GetGroup())
10085 }
10086 else if (Pet* pet = ToCreature()->ToPet())
10087 {
10088 if (pet->isControlled())
10089 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP);
10090 }
10091
10092 if (val < health)
10093 SetHealth(val);
10094}
10095
10097{
10098 uint32 powerIndex = GetPowerIndex(power);
10099 if (powerIndex >= MAX_POWERS_PER_CLASS)
10100 return 0;
10101
10102 return m_unitData->Power[powerIndex];
10103}
10104
10106{
10107 uint32 powerIndex = GetPowerIndex(power);
10108 if (powerIndex >= MAX_POWERS_PER_CLASS)
10109 return 0;
10110
10111 return m_unitData->MaxPower[powerIndex];
10112}
10113
10114void Unit::SetPower(Powers power, int32 val, bool withPowerUpdate /*= true*/)
10115{
10116 uint32 powerIndex = GetPowerIndex(power);
10117 if (powerIndex >= MAX_POWERS_PER_CLASS)
10118 return;
10119
10120 int32 maxPower = GetMaxPower(power);
10121 if (maxPower < val)
10122 val = maxPower;
10123
10124 int32 oldPower = m_unitData->Power[powerIndex];
10126
10127 if (IsInWorld() && withPowerUpdate)
10128 {
10130 packet.Guid = GetGUID();
10132 packet.Powers.emplace_back(val, power);
10134 }
10135
10136 TriggerOnPowerChangeAuras(power, oldPower, val);
10137
10138 // group update
10139 if (Player* player = ToPlayer())
10140 {
10141 if (player->GetGroup())
10142 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
10143 }
10144 /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x
10145 {
10146 if (pet->isControlled())
10147 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER);
10148 }*/
10149}
10150
10152{
10153 uint32 powerIndex = GetPowerIndex(power);
10154 if (powerIndex >= MAX_POWERS_PER_CLASS)
10155 return;
10156
10157 int32 cur_power = GetPower(power);
10159
10160 // group update
10161 if (GetTypeId() == TYPEID_PLAYER)
10162 {
10163 if (ToPlayer()->GetGroup())
10165 }
10166 /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x
10167 {
10168 if (pet->isControlled())
10169 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER);
10170 }*/
10171
10172 if (val < cur_power)
10173 SetPower(power, val);
10174}
10175
10177{
10178 auto processAuras = [&](AuraEffectVector const& effects)
10179 {
10180 for (AuraEffect const* effect : effects)
10181 {
10182 if (effect->GetMiscValue() == power)
10183 {
10184 SpellEffectValue effectAmount = effect->GetAmount();
10185 uint32 triggerSpell = effect->GetSpellEffectInfo().TriggerSpell;
10186
10187 SpellEffectValue oldValueCheck = oldVal;
10188 SpellEffectValue newValueCheck = newVal;
10189
10190 if (effect->GetAuraType() == SPELL_AURA_TRIGGER_SPELL_ON_POWER_PCT)
10191 {
10192 int32 maxPower = GetMaxPower(power);
10193 if (!maxPower)
10194 continue;
10195
10196 oldValueCheck = GetPctOf(oldVal, maxPower);
10197 newValueCheck = GetPctOf(newVal, maxPower);
10198 }
10199
10200 switch (AuraTriggerOnPowerChangeDirection(effect->GetMiscValueB()))
10201 {
10203 if (oldValueCheck >= effect->GetAmount() || newValueCheck < effectAmount)
10204 continue;
10205 break;
10207 if (oldValueCheck <= effect->GetAmount() || newValueCheck > effectAmount)
10208 continue;
10209 break;
10210 default:
10211 break;
10212 }
10213
10214 CastSpell(this, triggerSpell, effect);
10215 }
10216 }
10217 };
10218
10221}
10222
10224{
10225 if (UnitAI* ai = GetAI())
10226 {
10227 m_aiLocked = true;
10228 ai->UpdateAI(diff);
10229 m_aiLocked = false;
10230 }
10231}
10232
10234{
10235 i_AIs.emplace(newAI);
10236}
10237
10239{
10240 PushAI(newAI);
10241 RefreshAI();
10242}
10243
10245{
10246 if (!i_AIs.empty())
10247 {
10248 i_AIs.pop();
10249 return true;
10250 }
10251 else
10252 return false;
10253}
10254
10256{
10257 ASSERT(!m_aiLocked, "Tried to change current AI during UpdateAI()");
10258 if (i_AIs.empty())
10259 i_AI = nullptr;
10260 else
10261 i_AI = i_AIs.top();
10262}
10263
10265{
10266 bool const charmed = IsCharmed();
10267
10268 if (charmed)
10270 else
10271 {
10273 PushAI(GetScheduledChangeAI()); //This could actually be PopAI() to get the previous AI but it's required atm to trigger UpdateCharmAI()
10274 }
10275}
10276
10278{
10279 // Keep popping the stack until we either reach the bottom or find a valid AI
10280 while (PopAI())
10281 if (GetTopAI() && dynamic_cast<ScheduledChangeAI*>(GetTopAI()) == nullptr)
10282 return;
10283}
10284
10286{
10287 if (Creature* creature = ToCreature())
10288 return sCreatureAIRegistry->GetRegistryItem("ScheduledChangeAI")->Create(creature);
10289 else
10290 return nullptr;
10291}
10292
10294{
10295 if (UnitAI* ai = GetAI())
10296 return dynamic_cast<ScheduledChangeAI*>(ai) != nullptr;
10297 else
10298 return true;
10299}
10300
10308
10310{
10311 // cleanup
10312 ASSERT(GetGUID());
10313
10314 if (IsInWorld())
10315 {
10316 if (IsAreaSpiritHealer())
10317 {
10318 if (Creature* creature = ToCreature())
10319 creature->SummonGraveyardTeleporter();
10320 }
10321
10323 if (UnitAI* ai = GetAI())
10324 ai->OnDespawn();
10325
10326 if (IsVehicle())
10327 RemoveVehicleKit(true);
10328
10333
10337 ExitAllAreaTriggers(); // exit all areatriggers the unit is in
10338
10339 ExitVehicle(); // Remove applied auras with SPELL_AURA_CONTROL_VEHICLE
10342
10344
10346
10347 if (IsCharmed())
10348 RemoveCharmedBy(nullptr);
10349
10350 ASSERT(!GetCharmedGUID(), "Unit %u has charmed guid when removed from world", GetEntry());
10351 ASSERT(!GetCharmerGUID(), "Unit %u has charmer guid when removed from world", GetEntry());
10352
10353 if (Unit* owner = GetOwner())
10354 {
10355 if (owner->m_Controlled.find(this) != owner->m_Controlled.end())
10356 {
10357 TC_LOG_FATAL("entities.unit", "Unit {} is in controlled list of {} when removed from world", GetEntry(), owner->GetEntry());
10358 ABORT();
10359 }
10360 }
10361
10364 }
10365}
10366
10368{
10369 // This needs to be before RemoveFromWorld to make GetCaster() return a valid pointer on aura removal
10371
10372 SetVignette(0);
10373
10374 if (IsInWorld())
10376 else
10377 {
10378 // cleanup that must happen even if not in world
10379 if (IsVehicle())
10380 RemoveVehicleKit(true);
10381 }
10382
10383 ASSERT(GetGUID());
10384
10385 // A unit may be in removelist and not in world, but it is still in grid
10386 // and may have some references during delete
10389
10390 if (finalCleanup)
10391 m_cleanupDone = true;
10392
10393 CombatStop();
10394}
10395
10396void Unit::CleanupsBeforeDelete(bool finalCleanup)
10397{
10398 CleanupBeforeRemoveFromMap(finalCleanup);
10399
10401}
10402
10404{
10405 if (IsCharmed())
10406 {
10407 UnitAI* newAI = nullptr;
10408 if (GetTypeId() == TYPEID_PLAYER)
10409 {
10410 if (Unit* charmer = GetCharmer())
10411 {
10412 // first, we check if the creature's own AI specifies an override playerai for its owned players
10413 if (Creature* creatureCharmer = charmer->ToCreature())
10414 {
10415 if (CreatureAI* charmerAI = creatureCharmer->AI())
10416 newAI = charmerAI->GetAIForCharmedPlayer(ToPlayer());
10417 }
10418 else
10419 TC_LOG_ERROR("entities.unit.ai", "Attempt to assign charm AI to player {} who is charmed by non-creature {}.", GetGUID().ToString(), GetCharmerGUID().ToString());
10420 }
10421 if (!newAI) // otherwise, we default to the generic one
10422 newAI = new SimpleCharmedPlayerAI(ToPlayer());
10423 }
10424 else
10425 {
10427 if (isPossessed() || IsVehicle())
10428 newAI = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PossessedAI"))->Create(ToCreature());
10429 else
10430 newAI = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PetAI"))->Create(ToCreature());
10431 }
10432
10433 ASSERT(newAI);
10434 SetAI(newAI);
10435 newAI->OnCharmed(true);
10436 }
10437 else
10438 {
10440 // Hack: this is required because we want to call OnCharmed(true) on the restored AI
10441 RefreshAI();
10442 if (UnitAI* ai = GetAI())
10443 ai->OnCharmed(true);
10444 }
10445}
10446
10448{
10449 if (!m_charmInfo)
10450 m_charmInfo = std::make_unique<CharmInfo>(this);
10451
10452 return m_charmInfo.get();
10453}
10454
10456{
10457 if (!m_charmInfo)
10458 return;
10459
10460 m_charmInfo->RestoreState();
10461 m_charmInfo = nullptr;
10462}
10463
10465{
10469
10471 packet.MoverGUID = target->GetGUID();
10472 ToPlayer()->SendDirectMessage(packet.Write());
10473}
10474
10476{
10477 ProcFlagsHit hitMask = PROC_HIT_NONE;
10478 // Check victim state
10479 if (missCondition != SPELL_MISS_NONE)
10480 {
10481 switch (missCondition)
10482 {
10483 case SPELL_MISS_MISS:
10484 hitMask |= PROC_HIT_MISS;
10485 break;
10486 case SPELL_MISS_DODGE:
10487 hitMask |= PROC_HIT_DODGE;
10488 break;
10489 case SPELL_MISS_PARRY:
10490 hitMask |= PROC_HIT_PARRY;
10491 break;
10492 case SPELL_MISS_BLOCK:
10493 // spells can't be partially blocked (it's damage can though)
10495 break;
10496 case SPELL_MISS_EVADE:
10497 hitMask |= PROC_HIT_EVADE;
10498 break;
10499 case SPELL_MISS_IMMUNE:
10500 case SPELL_MISS_IMMUNE2:
10501 hitMask |= PROC_HIT_IMMUNE;
10502 break;
10503 case SPELL_MISS_DEFLECT:
10504 hitMask |= PROC_HIT_DEFLECT;
10505 break;
10506 case SPELL_MISS_ABSORB:
10507 hitMask |= PROC_HIT_ABSORB;
10508 break;
10509 case SPELL_MISS_REFLECT:
10510 hitMask |= PROC_HIT_REFLECT;
10511 break;
10512 case SPELL_MISS_RESIST:
10513 hitMask |= PROC_HIT_FULL_RESIST;
10514 break;
10515 default:
10516 break;
10517 }
10518 }
10519 else
10520 {
10521 // On block
10522 if (damageInfo->blocked)
10523 {
10524 hitMask |= PROC_HIT_BLOCK;
10525 if (damageInfo->fullBlock)
10526 hitMask |= PROC_HIT_FULL_BLOCK;
10527 }
10528 // On absorb
10529 if (damageInfo->absorb)
10530 hitMask |= PROC_HIT_ABSORB;
10531
10532 // Don't set hit/crit hitMask if damage is nullified
10533 bool const damageNullified = (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || (hitMask & PROC_HIT_FULL_BLOCK) != 0;
10534 if (!damageNullified)
10535 {
10536 // On crit
10537 if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT)
10538 hitMask |= PROC_HIT_CRITICAL;
10539 else
10540 hitMask |= PROC_HIT_NORMAL;
10541 }
10542 else if ((damageInfo->HitInfo & HITINFO_FULL_RESIST) != 0)
10543 hitMask |= PROC_HIT_FULL_RESIST;
10544 }
10545
10546 return hitMask;
10547}
10548
10549void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, ProcFlagsInit const& typeMask, ProcFlagsHit hitMask, WeaponAttackType /*attType*/)
10550{
10551 // Player is loaded now - do not allow passive spell casts to proc
10552 if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetSession()->PlayerLoading())
10553 return;
10554
10555 // For melee/ranged based attack need update skills and set some Aura states if victim present
10556 if (typeMask & MELEE_BASED_TRIGGER_MASK && procTarget)
10557 {
10558 // If exist crit/parry/dodge/block need update aura state (for victim and attacker)
10560 {
10561 // for victim
10562 if (isVictim)
10563 {
10564 // if victim and dodge attack
10565 if (hitMask & PROC_HIT_DODGE)
10566 {
10567 // Update AURA_STATE on dodge
10568 if (GetClass() != CLASS_ROGUE) // skip Rogue Riposte
10569 {
10572 }
10573 }
10574 // if victim and parry attack
10575 if (hitMask & PROC_HIT_PARRY)
10576 {
10579 }
10580 // if and victim block attack
10581 if (hitMask & PROC_HIT_BLOCK)
10582 {
10585 }
10586 }
10587 }
10588 }
10589}
10590
10592{
10593 TimePoint now = GameTime::Now();
10594
10595 auto processAuraApplication = [&](AuraApplication* aurApp)
10596 {
10597 if (uint32 procEffectMask = aurApp->GetBase()->GetProcEffectMask(aurApp, eventInfo, now))
10598 {
10599 aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now);
10600 aurasTriggeringProc.emplace_back(procEffectMask, aurApp);
10601 }
10602 else
10603 {
10605 {
10606 if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(aurApp->GetBase()->GetSpellInfo()))
10607 {
10608 aurApp->GetBase()->PrepareProcChargeDrop(procEntry, eventInfo);
10609 aurasTriggeringProc.emplace_back(0, aurApp);
10610 }
10611 }
10612
10614 if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(aurApp->GetBase()->GetSpellInfo()))
10615 aurApp->GetBase()->AddProcCooldown(procEntry, now);
10616 }
10617 };
10618
10619 // use provided list of auras which can proc
10620 if (procAuras)
10621 {
10622 for (AuraApplication* aurApp : *procAuras)
10623 {
10624 ASSERT(aurApp->GetTarget() == this);
10625 processAuraApplication(aurApp);
10626 }
10627 }
10628 // or generate one on our own
10629 else
10630 {
10631 for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr)
10632 processAuraApplication(itr->second);
10633 }
10634}
10635
10636void Unit::TriggerAurasProcOnEvent(AuraApplicationList* myProcAuras, AuraApplicationList* targetProcAuras, Unit* actionTarget,
10637 ProcFlagsInit const& typeMaskActor, ProcFlagsInit const& typeMaskActionTarget, ProcFlagsSpellType spellTypeMask,
10638 ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
10639{
10640 // prepare data for self trigger
10641 ProcEventInfo myProcEventInfo(this, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
10642 AuraApplicationProcContainer myAurasTriggeringProc;
10643 if (typeMaskActor)
10644 {
10645 GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, myProcAuras, myProcEventInfo);
10646
10647 // needed for example for Cobra Strikes, pet does the attack, but aura is on owner
10648 if (Player* modOwner = GetSpellModOwner())
10649 {
10650 if (modOwner != this && spell)
10651 {
10652 AuraApplicationList modAuras;
10653 for (auto itr = modOwner->GetAppliedAuras().begin(); itr != modOwner->GetAppliedAuras().end(); ++itr)
10654 {
10655 if (spell->m_appliedMods.count(itr->second->GetBase()) != 0)
10656 modAuras.push_front(itr->second);
10657 }
10658 modOwner->GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, &modAuras, myProcEventInfo);
10659 }
10660 }
10661 }
10662
10663 // prepare data for target trigger
10664 ProcEventInfo targetProcEventInfo(this, actionTarget, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
10665 AuraApplicationProcContainer targetAurasTriggeringProc;
10666 if (typeMaskActionTarget && actionTarget)
10667 actionTarget->GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, targetProcAuras, targetProcEventInfo);
10668
10669 TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc);
10670
10671 if (typeMaskActionTarget && actionTarget)
10672 actionTarget->TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc);
10673}
10674
10676{
10677 Spell const* triggeringSpell = eventInfo.GetProcSpell();
10678 bool const disableProcs = triggeringSpell && triggeringSpell->IsProcDisabled();
10679
10680 int32 oldProcChainLength = std::exchange(m_procChainLength, std::max(m_procChainLength + 1, triggeringSpell ? triggeringSpell->GetProcChainLength() : 0));
10681
10682 if (disableProcs)
10683 SetCantProc(true);
10684
10685 for (auto const& [procEffectMask, aurApp] : aurasTriggeringProc)
10686 {
10687 if (aurApp->GetRemoveMode())
10688 continue;
10689
10690 aurApp->GetBase()->TriggerProcOnEvent(procEffectMask, aurApp, eventInfo);
10691 }
10692
10693 if (disableProcs)
10694 SetCantProc(false);
10695
10696 m_procChainLength = oldProcChainLength;
10697}
10698
10701{
10702 Unit* owner = GetOwner();
10703 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10704 return;
10705
10706 WorldPackets::Pet::PetActionFeedback petActionFeedback;
10707 petActionFeedback.SpellID = spellId;
10708 petActionFeedback.Response = msg;
10709 owner->ToPlayer()->SendDirectMessage(petActionFeedback.Write());
10710}
10711
10713{
10714 WorldPackets::Pet::PetActionSound petActionSound;
10715 petActionSound.UnitGUID = GetGUID();
10716 petActionSound.Action = action;
10717 SendMessageToSet(petActionSound.Write(), false);
10718}
10719
10721{
10722 WorldPackets::Pet::PetDismissSound petDismissSound;
10723 petDismissSound.UnitGUID = GetGUID();
10724 petDismissSound.CreatureDisplayInfoID = GetNativeDisplayId();
10725 petDismissSound.ModelPosition = GetPosition();
10726 SendMessageToSet(petDismissSound.Write(), false);
10727}
10728
10730{
10731 Unit* owner = GetOwner();
10732 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10733 return;
10734
10736 packet.UnitGUID = guid;
10738 owner->ToPlayer()->SendDirectMessage(packet.Write());
10739}
10740
10742
10747
10752
10753void Unit::StopMoving(bool force /*= false*/)
10754{
10756
10757 // not need send any packets if not in world or not moving
10758 if (!IsInWorld() || (!force && movespline->Finalized()))
10759 return;
10760
10761 // Update position now since Stop does not start a new movement that can be updated later
10762 if (movespline->HasStarted())
10764 Movement::MoveSplineInit init(this);
10765 init.Stop(force);
10766}
10767
10768void Unit::PauseMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/, bool forced/* = true*/)
10769{
10770 if (IsInvalidMovementSlot(slot))
10771 return;
10772
10773 if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot)))
10774 movementGenerator->Pause(timer);
10775
10776 if (forced && GetMotionMaster()->GetCurrentSlot() == MovementSlot(slot))
10777 StopMoving();
10778}
10779
10780void Unit::ResumeMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/)
10781{
10782 if (IsInvalidMovementSlot(slot))
10783 return;
10784
10785 if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot)))
10786 movementGenerator->Resume(timer);
10787}
10788
10797
10799{
10802}
10803
10804void Unit::SetStandState(UnitStandStateType state, uint32 animKitID /* = 0*/)
10805{
10807
10808 if (state == UNIT_STAND_STATE_STAND)
10810
10811 if (GetTypeId() == TYPEID_PLAYER)
10812 {
10813 WorldPackets::Misc::StandStateUpdate packet(state, animKitID);
10814 ToPlayer()->SendDirectMessage(packet.Write());
10815 }
10816}
10817
10818void Unit::SetAnimTier(AnimTier animTier, bool notifyClient /*= true*/)
10819{
10821
10822 if (notifyClient)
10823 {
10825 setAnimTier.Unit = GetGUID();
10826 setAnimTier.Tier = AsUnderlyingType(animTier);
10827 SendMessageToSet(setAnimTier.Write(), true);
10828 }
10829}
10830
10832{
10833 uint32 transformId = GetTransformSpell();
10834 if (!transformId)
10835 return false;
10836
10837 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(transformId, GetMap()->GetDifficultyID());
10838 if (!spellInfo)
10839 return false;
10840
10841 return spellInfo->GetSpellSpecific() == SPELL_SPECIFIC_MAGE_POLYMORPH;
10842}
10843
10845{
10847 float scale = GetNativeObjectScale() + CalculatePct(1.0f, scaleAuras);
10848 float scaleMin = GetTypeId() == TYPEID_PLAYER ? 0.1f : 0.01f;
10849 SetObjectScale(std::max(scale, scaleMin));
10850}
10851
10852void Unit::SetDisplayId(uint32 displayId, bool setNative /*= false*/)
10853{
10854 float displayScale = DEFAULT_PLAYER_DISPLAY_SCALE;
10855
10856 if (IsCreature() && !IsPet())
10857 if (CreatureModel const* model = ToCreature()->GetCreatureTemplate()->GetModelWithDisplayId(displayId))
10858 displayScale = model->DisplayScale;
10859
10862
10863 if (setNative)
10864 {
10867 }
10868
10869 // Set Gender by ModelInfo
10870 if (CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(displayId))
10871 SetGender(Gender(modelInfo->gender));
10872
10874}
10875
10876void Unit::RestoreDisplayId(bool ignorePositiveAurasPreventingMounting /*= false*/)
10877{
10878 AuraEffect* handledAura = nullptr;
10879 // try to receive model from transform auras
10881 if (!transforms.empty())
10882 {
10883 // iterate over already applied transform auras - from newest to oldest
10884 for (auto i = transforms.begin(); i != transforms.end(); ++i)
10885 {
10886 if (AuraApplication const* aurApp = (*i)->GetBase()->GetApplicationOfTarget(GetGUID()))
10887 {
10888 if (!handledAura)
10889 {
10890 if (!ignorePositiveAurasPreventingMounting)
10891 handledAura = (*i);
10892 else if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate((*i)->GetMiscValue()))
10894 handledAura = (*i);
10895 }
10896 // prefer negative auras
10897 if (!aurApp->IsPositive())
10898 {
10899 handledAura = (*i);
10900 break;
10901 }
10902 }
10903 }
10904 }
10905
10907
10908 // transform aura was found
10909 if (handledAura)
10910 {
10911 handledAura->HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true);
10912 return;
10913 }
10914 // we've found shapeshift
10915 else if (!shapeshiftAura.empty()) // we've found shapeshift
10916 {
10917 // only one such aura possible at a time
10918 if (uint32 modelId = GetModelForForm(GetShapeshiftForm(), shapeshiftAura.front()->GetId()))
10919 {
10920 if (!ignorePositiveAurasPreventingMounting || !IsDisallowedMountForm(0, GetShapeshiftForm(), modelId))
10921 SetDisplayId(modelId);
10922 else
10924 return;
10925 }
10926 }
10927 // no auras found - set modelid to default
10929}
10930
10932{
10933 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
10934 m_reactiveTimer[i] = 0;
10935
10940}
10941
10943{
10944 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
10945 {
10946 ReactiveType reactive = ReactiveType(i);
10947
10948 if (!m_reactiveTimer[reactive])
10949 continue;
10950
10951 if (m_reactiveTimer[reactive] <= p_time)
10952 {
10953 m_reactiveTimer[reactive] = 0;
10954
10955 switch (reactive)
10956 {
10957 case REACTIVE_DEFENSE:
10960 break;
10961 case REACTIVE_DEFENSE_2:
10964 break;
10965 default:
10966 break;
10967 }
10968 }
10969 else
10970 {
10971 m_reactiveTimer[reactive] -= p_time;
10972 }
10973 }
10974}
10975
10976Unit* Unit::SelectNearbyTarget(Unit* exclude, float dist) const
10977{
10978 std::list<Unit*> targets;
10979 Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, dist);
10981 Cell::VisitAllObjects(this, searcher, dist);
10982
10983 // remove current target
10984 if (GetVictim())
10985 targets.remove(GetVictim());
10986
10987 if (exclude)
10988 targets.remove(exclude);
10989
10990 // remove not LoS targets
10991 for (std::list<Unit*>::iterator tIter = targets.begin(); tIter != targets.end();)
10992 {
10993 if (!IsWithinLOSInMap(*tIter) || (*tIter)->IsTotem() || (*tIter)->IsSpiritService() || (*tIter)->IsCritter())
10994 targets.erase(tIter++);
10995 else
10996 ++tIter;
10997 }
10998
10999 // no appropriate targets
11000 if (targets.empty())
11001 return nullptr;
11002
11003 // select random
11005}
11006
11008{
11009 return m_baseAttackSpeed[att];
11010}
11011
11013{
11014 m_baseAttackSpeed[att] = val;
11016}
11017
11033
11035{
11036 float remainingTimePct = float(m_attackTimer[att]) / (m_baseAttackSpeed[att] * m_modAttackSpeedPct[att]);
11037 if (val > 0.f)
11038 {
11040
11041 if (att == BASE_ATTACK)
11043 else if (att == RANGED_ATTACK)
11045 }
11046 else
11047 {
11049
11050 if (att == BASE_ATTACK)
11052 else if (att == RANGED_ATTACK)
11054 }
11055
11057 m_attackTimer[att] = uint32(m_baseAttackSpeed[att] * m_modAttackSpeedPct[att] * remainingTimePct);
11058}
11059
11060void Unit::ApplyCastTimePercentMod(float val, bool apply)
11061{
11062 if (val > 0.f)
11063 {
11065 }
11066 else
11067 {
11070 }
11071}
11072
11073void Unit::ApplySpellHastePercentMod(float val, bool apply)
11074{
11075 if (val > 0.f)
11077 else
11079}
11080
11081void Unit::ApplyHasteRegenPercentMod(float val, bool apply)
11082{
11083 if (val > 0.f)
11085 else if (val < 0.0f)
11087 else
11088 return;
11089
11090 if (Player* player = ToPlayer())
11091 for (Powers power : GetPowerTypes())
11092 if (sDB2Manager.GetPowerTypeEntry(power)->GetFlags().HasFlag(PowerTypeFlags::RegenAffectedByHaste))
11093 player->UpdatePowerRegen(power);
11094}
11095
11097{
11098 if (Player* player = ToPlayer())
11099 {
11100 if (player->GetGroup())
11101 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS);
11102 }
11103 else if (GetTypeId() == TYPEID_UNIT && IsPet())
11104 {
11105 Pet* pet = ((Pet*)this);
11106 if (pet->isControlled())
11108 }
11109}
11110
11111void Unit::SetCantProc(bool apply)
11112{
11113 if (apply)
11114 ++m_procDeep;
11115 else
11116 {
11118 --m_procDeep;
11119 }
11120}
11121
11122float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) const
11123{
11124 if (GetTypeId() != TYPEID_PLAYER || (IsInFeralForm() && !normalized))
11125 return GetBaseAttackTime(attType) / 1000.0f;
11126
11127 Item* weapon = ToPlayer()->GetWeaponForAttack(attType, true);
11128 if (!weapon)
11129 return 2.0f;
11130
11131 if (!normalized)
11132 return weapon->GetTemplate()->GetDelay() / 1000.0f;
11133
11134 switch (weapon->GetTemplate()->GetSubClass())
11135 {
11142 return 3.3f;
11150 return 2.4f;
11152 return 1.7f;
11154 return 2.0f;
11155 default:
11156 return weapon->GetTemplate()->GetDelay() / 1000.0f;
11157 }
11158}
11159
11160Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget, uint32 spell_id)
11161{
11162 if (GetTypeId() != TYPEID_PLAYER)
11163 return nullptr;
11164
11165 Pet* pet = new Pet(ToPlayer(), HUNTER_PET);
11166
11167 if (!pet->CreateBaseAtCreature(creatureTarget))
11168 {
11169 delete pet;
11170 return nullptr;
11171 }
11172
11173 if (!InitTamedPet(pet, GetLevel(), spell_id))
11174 {
11175 delete pet;
11176 return nullptr;
11177 }
11178
11179 return pet;
11180}
11181
11183{
11184 if (GetTypeId() != TYPEID_PLAYER)
11185 return nullptr;
11186
11187 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creatureEntry);
11188 if (!creatureInfo)
11189 return nullptr;
11190
11191 Pet* pet = new Pet(ToPlayer(), HUNTER_PET);
11192
11193 if (!pet->CreateBaseAtCreatureInfo(creatureInfo, this) || !InitTamedPet(pet, GetLevel(), spell_id))
11194 {
11195 delete pet;
11196 return nullptr;
11197 }
11198
11199 return pet;
11200}
11201
11202bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
11203{
11204 Player* player = ToPlayer();
11205 PetStable& petStable = player->GetOrInitPetStable();
11206 auto freeActiveSlotItr = std::find_if(petStable.ActivePets.begin(), petStable.ActivePets.end(), [](Optional<PetStable::PetInfo> const& petInfo)
11207 {
11208 return !petInfo.has_value();
11209 });
11210
11211 if (freeActiveSlotItr == petStable.ActivePets.end())
11212 return false;
11213
11214 pet->SetCreatorGUID(GetGUID());
11215 pet->SetFaction(GetFaction());
11216 pet->SetCreatedBySpell(spell_id);
11218
11219 if (!pet->InitStatsForLevel(level))
11220 {
11221 TC_LOG_ERROR("entities.unit", "Pet::InitStatsForLevel() failed for creature (Entry: {})!", pet->GetEntry());
11222 return false;
11223 }
11224
11226
11227 pet->GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true);
11228 // this enables pet details window (Shift+P)
11229 pet->InitPetCreateSpells();
11230 //pet->InitLevelupSpellsForLevel();
11231 pet->SetFullHealth();
11232
11233 petStable.SetCurrentActivePetIndex(std::distance(petStable.ActivePets.begin(), freeActiveSlotItr));
11234 pet->FillPetInfo(&freeActiveSlotItr->emplace());
11235 player->AddPetToUpdateFields(**freeActiveSlotItr, PetSaveMode(*petStable.GetCurrentActivePetIndex()), PET_STABLE_ACTIVE);
11236 return true;
11237}
11238
11240{
11242 packet.Percent = percent;
11243 receiver->GetSession()->SendPacket(packet.Write());
11244}
11245
11247{
11248 if (!sAnimKitStore.LookupEntry(animKitId))
11249 {
11250 TC_LOG_ERROR("entities.unit", "Unit::PlayOneShotAnimKitId using invalid AnimKit ID: {}", animKitId);
11251 return;
11252 }
11253
11255 data.Unit = GetGUID();
11256 data.AnimKitID = animKitId;
11257 SendMessageToSet(data.Write(), true);
11258}
11259
11261{
11262 if (_aiAnimKitId == animKitId)
11263 return;
11264
11265 if (animKitId && !sAnimKitStore.LookupEntry(animKitId))
11266 return;
11267
11268 _aiAnimKitId = animKitId;
11270
11272 data.Unit = GetGUID();
11273 data.AnimKitID = animKitId;
11274 SendMessageToSet(data.Write(), true);
11275}
11276
11278{
11279 if (_movementAnimKitId == animKitId)
11280 return;
11281
11282 if (animKitId && !sAnimKitStore.LookupEntry(animKitId))
11283 return;
11284
11285 _movementAnimKitId = animKitId;
11287
11289 data.Unit = GetGUID();
11290 data.AnimKitID = animKitId;
11291 SendMessageToSet(data.Write(), true);
11292}
11293
11295{
11296 if (_meleeAnimKitId == animKitId)
11297 return;
11298
11299 if (animKitId && !sAnimKitStore.LookupEntry(animKitId))
11300 return;
11301
11302 _meleeAnimKitId = animKitId;
11304
11306 data.Unit = GetGUID();
11307 data.AnimKitID = animKitId;
11308 SendMessageToSet(data.Write(), true);
11309}
11310
11311/*static*/ void Unit::Kill(Unit* attacker, Unit* victim, bool durabilityLoss /*= true*/, bool skipSettingDeathState /*= false*/)
11312{
11313 // Prevent killing unit twice (and giving reward from kill twice)
11314 if (!victim->GetHealth())
11315 return;
11316
11317 if (attacker && !attacker->IsInMap(victim))
11318 attacker = nullptr;
11319
11320 // find player: owner of controlled `this` or `this` itself maybe
11321 Player* player = nullptr;
11322 if (attacker)
11323 player = attacker->GetCharmerOrOwnerPlayerOrPlayerItself();
11324
11325 Creature* creature = victim->ToCreature();
11326
11327 bool isRewardAllowed = attacker != victim;
11328 if (creature)
11329 isRewardAllowed = isRewardAllowed && !creature->GetTapList().empty();
11330
11331 std::vector<Player*> tappers;
11332 if (isRewardAllowed && creature)
11333 {
11334 for (ObjectGuid tapperGuid : creature->GetTapList())
11335 if (Player* tapper = ObjectAccessor::GetPlayer(*creature, tapperGuid))
11336 tappers.push_back(tapper);
11337
11338 if (!creature->CanHaveLoot())
11339 isRewardAllowed = false;
11340 }
11341
11342 // Exploit fix
11343 if (creature && creature->IsPet() && creature->GetOwnerGUID().IsPlayer())
11344 isRewardAllowed = false;
11345
11346 // Reward player, his pets, and group/raid members
11347 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
11348 if (isRewardAllowed)
11349 {
11350 std::unordered_set<Group*> groups;
11351 for (Player* tapper : tappers)
11352 {
11353 if (Group* tapperGroup = tapper->GetGroup())
11354 {
11355 if (groups.insert(tapperGroup).second)
11356 {
11358 partyKillLog.Player = player && tapperGroup->IsMember(player->GetGUID()) ? player->GetGUID() : tapper->GetGUID();
11359 partyKillLog.Victim = victim->GetGUID();
11360 partyKillLog.Write();
11361
11362 tapperGroup->BroadcastPacket(partyKillLog.GetRawPacket(), tapperGroup->GetMemberGroup(tapper->GetGUID()) != 0);
11363
11364 if (creature)
11365 tapperGroup->UpdateLooterGuid(creature, true);
11366 }
11367 }
11368 else
11369 {
11371 partyKillLog.Player = tapper->GetGUID();
11372 partyKillLog.Victim = victim->GetGUID();
11373 tapper->SendDirectMessage(partyKillLog.Write());
11374 }
11375 }
11376
11377 // Generate loot before updating looter
11378 if (creature)
11379 {
11380 DungeonEncounterEntry const* dungeonEncounter = nullptr;
11381 if (InstanceScript const* instance = creature->GetInstanceScript())
11382 dungeonEncounter = instance->GetBossDungeonEncounter(creature);
11383
11384 if (creature->GetMap()->IsDungeon())
11385 {
11386 if (dungeonEncounter)
11387 {
11388 creature->m_personalLoot = GenerateDungeonEncounterPersonalLoot(dungeonEncounter->ID, creature->GetLootId(),
11390 creature->GetLootMode(), creature->GetMap()->GetMapDifficulty(), tappers);
11391 }
11392 else if (!tappers.empty())
11393 {
11394 Group* group = !groups.empty() ? *groups.begin() : nullptr;
11395 Player* looter = group ? ASSERT_NOTNULL(ObjectAccessor::GetPlayer(*creature, group->GetLooterGuid())) : tappers[0];
11396
11397 Loot* loot = new Loot(creature->GetMap(), creature->GetGUID(), LOOT_CORPSE, dungeonEncounter ? group : nullptr);
11398
11399 if (uint32 lootid = creature->GetLootId())
11400 loot->FillLoot(lootid, LootTemplates_Creature, looter, dungeonEncounter != nullptr, false, creature->GetLootMode(), ItemBonusMgr::GetContextForPlayer(creature->GetMap()->GetMapDifficulty(), looter));
11401
11402 if (creature->GetLootMode() > 0)
11404
11405 if (group)
11406 loot->NotifyLootList(creature->GetMap());
11407
11408 creature->m_personalLoot[looter->GetGUID()].reset(loot); // trash mob loot is personal, generated with round robin rules
11409
11410 // Update round robin looter only if the creature had loot
11411 if (!loot->isLooted())
11412 for (Group* tapperGroup : groups)
11413 tapperGroup->UpdateLooterGuid(creature);
11414 }
11415 }
11416 else
11417 {
11418 for (Player* tapper : tappers)
11419 {
11420 Loot* loot = new Loot(creature->GetMap(), creature->GetGUID(), LOOT_CORPSE, nullptr);
11421
11422 if (dungeonEncounter)
11423 loot->SetDungeonEncounterId(dungeonEncounter->ID);
11424
11425 if (uint32 lootid = creature->GetLootId())
11426 loot->FillLoot(lootid, LootTemplates_Creature, tapper, true, false, creature->GetLootMode(), ItemBonusMgr::GetContextForPlayer(creature->GetMap()->GetMapDifficulty(), tapper));
11427
11428 if (creature->GetLootMode() > 0)
11430
11431 creature->m_personalLoot[tapper->GetGUID()].reset(loot);
11432 }
11433 }
11434 }
11435
11436 if (Vignettes::VignetteData const* vignette = victim->GetVignette())
11437 {
11438 for (Player* tapper : tappers)
11439 {
11440 if (Quest const* reward = sObjectMgr->GetQuestTemplate(vignette->Data->RewardQuestID))
11441 tapper->RewardQuest(reward, LootItemType::Item, 0, victim, false);
11442
11443 if (vignette->Data->VisibleTrackingQuestID)
11444 tapper->SetRewardedQuest(vignette->Data->VisibleTrackingQuestID);
11445 }
11446 }
11447
11448 KillRewarder(Trinity::IteratorPair(tappers.data(), tappers.data() + tappers.size()), victim, false).Reward();
11449 }
11450
11451 // 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
11452 if (attacker && (attacker->IsPet() || attacker->IsTotem()))
11453 {
11454 // proc only once for victim
11455 if (Unit* owner = attacker->GetOwner())
11457 }
11458
11459 if (!victim->IsCritter())
11460 {
11462
11463 for (Player* tapper : tappers)
11464 if (tapper->IsAtGroupRewardDistance(victim))
11466 }
11467
11468 // Proc auras on death - must be before aura/combat remove
11470
11471 // update get killing blow achievements, must be done before setDeathState to be able to require auras on target
11472 // and before Spirit of Redemption as it also removes auras
11473 if (attacker)
11474 if (Player* killerPlayer = attacker->GetCharmerOrOwnerPlayerOrPlayerItself())
11475 killerPlayer->UpdateCriteria(CriteriaType::DeliveredKillingBlow, 1, 0, 0, victim);
11476
11477 if (!skipSettingDeathState)
11478 {
11479 TC_LOG_DEBUG("entities.unit", "SET JUST_DIED");
11480 victim->setDeathState(JUST_DIED);
11481 }
11482
11483 // Inform pets (if any) when player kills target)
11484 // MUST come after victim->setDeathState(JUST_DIED); or pet next target
11485 // selection will get stuck on same target and break pet react state
11486 for (Player* tapper : tappers)
11487 {
11488 Pet* pet = tapper->GetPet();
11489 if (pet && pet->IsAlive() && pet->isControlled())
11490 {
11491 if (pet->IsAIEnabled())
11492 pet->AI()->KilledUnit(victim);
11493 else
11494 TC_LOG_ERROR("entities.unit", "Pet doesn't have any AI in Unit::Kill(). {}", pet->GetDebugInfo());
11495 }
11496 }
11497
11498 // 10% durability loss on death
11499 if (Player* plrVictim = victim->ToPlayer())
11500 {
11501 // remember victim PvP death for corpse type and corpse reclaim delay
11502 // at original death (not at SpiritOfRedemtionTalent timeout)
11503 plrVictim->SetPvPDeath(player != nullptr);
11504
11505 // only if not player and not controlled by player pet. And not at BG
11506 if ((durabilityLoss && !player && !victim->ToPlayer()->InBattleground()) || (player && sWorld->getBoolConfig(CONFIG_DURABILITY_LOSS_IN_PVP)))
11507 {
11508 double baseLoss = sWorld->getRate(RATE_DURABILITY_LOSS_ON_DEATH);
11509 uint32 loss = uint32(baseLoss - (baseLoss * plrVictim->GetTotalAuraMultiplier(SPELL_AURA_MOD_DURABILITY_LOSS)));
11510 TC_LOG_DEBUG("entities.unit", "We are dead, losing {} percent durability", loss);
11511 // Durability loss is calculated more accurately again for each item in Player::DurabilityLoss
11512 plrVictim->DurabilityLossAll(baseLoss, false);
11513 // durability lost message
11514 plrVictim->SendDurabilityLoss(plrVictim, loss);
11515 }
11516 // Call KilledUnit for creatures
11517 if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())
11518 attacker->ToCreature()->AI()->KilledUnit(victim);
11519
11520 // last damage from non duel opponent or opponent controlled creature
11521 if (plrVictim->duel)
11522 {
11523 plrVictim->duel->Opponent->CombatStopWithPets(true);
11524 plrVictim->CombatStopWithPets(true);
11525 plrVictim->DuelComplete(DUEL_INTERRUPTED);
11526 }
11527 }
11528 else // creature died
11529 {
11530 TC_LOG_DEBUG("entities.unit", "DealDamageNotPlayer");
11531 ASSERT_NODEBUGINFO(creature);
11532
11533 if (!creature->IsPet())
11534 {
11535 // must be after setDeathState which resets dynamic flags
11536 if (!creature->IsFullyLooted())
11538 else
11539 creature->AllLootRemovedFromCorpse();
11540
11542 {
11545 }
11546 }
11547
11548 // Call KilledUnit for creatures, this needs to be called after the lootable flag is set
11549 if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())
11550 attacker->ToCreature()->AI()->KilledUnit(victim);
11551
11552 // Call creature just died function
11553 if (CreatureAI* ai = creature->AI())
11554 {
11555 ai->OnHealthDepleted(attacker, true);
11556 ai->JustDied(attacker);
11557 }
11558
11559 if (TempSummon * summon = creature->ToTempSummon())
11560 {
11561 if (WorldObject * summoner = summon->GetSummoner())
11562 {
11563 if (summoner->ToCreature() && summoner->ToCreature()->IsAIEnabled())
11564 summoner->ToCreature()->AI()->SummonedCreatureDies(creature, attacker);
11565 else if (summoner->ToGameObject() && summoner->ToGameObject()->AI())
11566 summoner->ToGameObject()->AI()->SummonedCreatureDies(creature, attacker);
11567 }
11568 }
11569 }
11570
11571 // outdoor pvp things, do these after setting the death state, else the player activity notify won't work... doh...
11572 // handle player kill only if not suicide (spirit of redemption for example)
11573 if (player && attacker != victim)
11574 {
11575 if (OutdoorPvP* pvp = player->GetOutdoorPvP())
11576 pvp->HandleKill(player, victim);
11577
11578 if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetMap(), player->GetZoneId()))
11579 bf->HandleKill(player, victim);
11580 }
11581
11582 //if (victim->GetTypeId() == TYPEID_PLAYER)
11583 // if (OutdoorPvP* pvp = victim->ToPlayer()->GetOutdoorPvP())
11584 // pvp->HandlePlayerActivityChangedpVictim->ToPlayer();
11585
11586 // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
11587 if (attacker)
11588 {
11589 if (BattlegroundMap* bgMap = victim->GetMap()->ToBattlegroundMap())
11590 {
11591 if (Battleground* bg = bgMap->GetBG())
11592 {
11593 if (Player* playerVictim = victim->ToPlayer())
11594 {
11595 if (player)
11596 bg->HandleKillPlayer(playerVictim, player);
11597 }
11598 else
11599 bg->HandleKillUnit(victim->ToCreature(), attacker);
11600 }
11601 }
11602 }
11603
11604 // achievement stuff
11605 if (attacker && victim->GetTypeId() == TYPEID_PLAYER)
11606 {
11607 if (attacker->GetTypeId() == TYPEID_UNIT)
11609 else if (attacker->GetTypeId() == TYPEID_PLAYER && victim != attacker)
11611 }
11612
11613 // Hook for OnPVPKill Event
11614 if (attacker)
11615 {
11616 if (Player* killerPlr = attacker->ToPlayer())
11617 {
11618 if (Player* killedPlr = victim->ToPlayer())
11619 sScriptMgr->OnPVPKill(killerPlr, killedPlr);
11620 else if (Creature* killedCre = victim->ToCreature())
11621 sScriptMgr->OnCreatureKill(killerPlr, killedCre);
11622 }
11623 else if (Creature* killerCre = attacker->ToCreature())
11624 {
11625 if (Player* killed = victim->ToPlayer())
11626 sScriptMgr->OnPlayerKilledByCreature(killerCre, killed);
11627 }
11628 }
11629}
11630
11631void Unit::SetControlled(bool apply, UnitState state)
11632{
11633 if (apply)
11634 {
11635 if (HasUnitState(state))
11636 return;
11637
11638 if (state & UNIT_STATE_CONTROLLED)
11639 CastStop();
11640
11641 AddUnitState(state);
11642 switch (state)
11643 {
11644 case UNIT_STATE_STUNNED:
11645 SetStunned(true);
11646 break;
11647 case UNIT_STATE_ROOT:
11649 SetRooted(true);
11650 break;
11653 {
11655 // SendAutoRepeatCancel ?
11656 SetConfused(true);
11657 }
11658 break;
11659 case UNIT_STATE_FLEEING:
11661 {
11663 // SendAutoRepeatCancel ?
11664 SetFeared(true);
11665 }
11666 break;
11667 default:
11668 break;
11669 }
11670 }
11671 else
11672 {
11673 switch (state)
11674 {
11675 case UNIT_STATE_STUNNED:
11677 return;
11678
11679 ClearUnitState(state);
11680 SetStunned(false);
11681 break;
11682 case UNIT_STATE_ROOT:
11684 return;
11685
11686 ClearUnitState(state);
11688 SetRooted(false);
11689 break;
11692 return;
11693
11694 ClearUnitState(state);
11695 SetConfused(false);
11696 break;
11697 case UNIT_STATE_FLEEING:
11699 return;
11700
11701 ClearUnitState(state);
11702 SetFeared(false);
11703 break;
11704 default:
11705 return;
11706 }
11707
11709 }
11710}
11711
11713{
11714 // Unit States might have been already cleared but auras still present. I need to check with HasAuraType
11716 SetStunned(true);
11717
11719 SetRooted(true);
11720
11722 SetConfused(true);
11723
11725 SetFeared(true);
11726}
11727
11728void Unit::SetStunned(bool apply)
11729{
11730 if (apply)
11731 {
11734
11735 StopMoving();
11736
11737 if (GetTypeId() == TYPEID_PLAYER)
11739
11740 SetRooted(true);
11741
11742 CastStop();
11743 }
11744 else
11745 {
11746 if (IsAlive() && GetVictim())
11748
11749 // don't remove UNIT_FLAG_STUNNED for pet when owner is mounted (disabled pet's interface)
11750 Unit* owner = GetCharmerOrOwner();
11751 if (!owner || owner->GetTypeId() != TYPEID_PLAYER || !owner->ToPlayer()->IsMounted())
11753
11754 if (!HasUnitState(UNIT_STATE_ROOT)) // prevent moving if it also has root effect
11755 SetRooted(false);
11756 }
11757}
11758
11759void Unit::SetRooted(bool apply)
11760{
11761 if (apply)
11762 {
11763 // MOVEMENTFLAG_ROOT cannot be used in conjunction with MOVEMENTFLAG_MASK_MOVING (tested 3.3.5a)
11764 // this will freeze clients. That's why we remove MOVEMENTFLAG_MASK_MOVING before
11765 // setting MOVEMENTFLAG_ROOT
11768 StopMoving();
11769 }
11770 else
11772
11773 static OpcodeServer const rootOpcodeTable[2][2] =
11774 {
11777 };
11778
11779 if (Player* playerMover = GetPlayerMovingMe()) // unit controlled by a player.
11780 {
11781 WorldPackets::Movement::MoveSetFlag packet(rootOpcodeTable[apply][1]);
11782 packet.MoverGUID = GetGUID();
11784 playerMover->SendDirectMessage(packet.Write());
11785
11787 moveUpdate.Status = &m_movementInfo;
11788 SendMessageToSet(moveUpdate.Write(), playerMover);
11789 }
11790 else
11791 {
11792 WorldPackets::Movement::MoveSplineSetFlag packet(rootOpcodeTable[apply][0]);
11793 packet.MoverGUID = GetGUID();
11794 SendMessageToSet(packet.Write(), true);
11795 }
11796}
11797
11798void Unit::SetFeared(bool apply)
11799{
11800 if (apply)
11801 {
11803
11804 Unit* caster = nullptr;
11806 if (!fearAuras.empty())
11807 caster = ObjectAccessor::GetUnit(*this, fearAuras.front()->GetCasterGUID());
11808 if (!caster)
11809 caster = getAttackerForHelper();
11810 GetMotionMaster()->MoveFleeing(caster, fearAuras.empty() ? Milliseconds(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY)) : 0ms); // caster == NULL processed in MoveFleeing
11812 }
11813 else
11814 {
11816 if (IsAlive())
11817 {
11819 if (Unit const* victim = GetVictim())
11820 SetTarget(victim->GetGUID());
11821 if (!IsPlayer() && !IsInCombat())
11823 }
11824 }
11825
11826 // block / allow control to real player in control (eg charmer)
11827 if (GetTypeId() == TYPEID_PLAYER)
11828 {
11829 if (m_playerMovingMe)
11830 m_playerMovingMe->SetClientControl(this, !apply);
11831 }
11832}
11833
11834void Unit::SetConfused(bool apply)
11835{
11836 if (apply)
11837 {
11840 }
11841 else
11842 {
11843 if (IsAlive())
11844 {
11846 if (GetVictim())
11848 }
11849 }
11850
11851 // block / allow control to real player in control (eg charmer)
11852 if (GetTypeId() == TYPEID_PLAYER)
11853 {
11854 if (m_playerMovingMe)
11855 m_playerMovingMe->SetClientControl(this, !apply);
11856 }
11857}
11858
11859bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* aurApp)
11860{
11861 if (!charmer)
11862 return false;
11863
11864 // dismount players when charmed
11865 if (GetTypeId() == TYPEID_PLAYER)
11867
11868 if (charmer->GetTypeId() == TYPEID_PLAYER)
11870
11871 ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
11872 ASSERT((type == CHARM_TYPE_VEHICLE) == (GetVehicleKit() && GetVehicleKit()->IsControllableVehicle()));
11873
11874 TC_LOG_DEBUG("entities.unit", "SetCharmedBy: charmer {}, charmed {}, type {}.", charmer->GetGUID().ToString(), GetGUID().ToString(), uint32(type));
11875
11876 if (this == charmer)
11877 {
11878 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: Unit {} is trying to charm itself!", GetGUID().ToString());
11879 return false;
11880 }
11881
11882 //if (HasUnitState(UNIT_STATE_UNATTACKABLE))
11883 // return false;
11884
11886 {
11887 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} is trying to charm Player {} on transport", charmer->GetGUID().ToString(), GetGUID().ToString());
11888 return false;
11889 }
11890
11891 // Already charmed
11892 if (!GetCharmerGUID().IsEmpty())
11893 {
11894 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} has already been charmed but {} is trying to charm it!", GetGUID().ToString(), charmer->GetGUID().ToString());
11895 return false;
11896 }
11897
11898 CastStop();
11899 AttackStop();
11900
11901 Player* playerCharmer = charmer->ToPlayer();
11902
11903 // Charmer stop charming
11904 if (playerCharmer)
11905 {
11906 playerCharmer->StopCastingCharm();
11907 playerCharmer->StopCastingBindSight();
11908 }
11909
11910 // Charmed stop charming
11911 if (GetTypeId() == TYPEID_PLAYER)
11912 {
11915 }
11916
11917 // StopCastingCharm may remove a possessed pet?
11918 if (!IsInWorld())
11919 {
11920 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} is not in world but {} is trying to charm it!", GetGUID().ToString(), charmer->GetGUID().ToString());
11921 return false;
11922 }
11923
11924 // charm is set by aura, and aura effect remove handler was called during apply handler execution
11925 // prevent undefined behaviour
11926 if (aurApp && aurApp->GetRemoveMode())
11927 return false;
11928
11930 SetFaction(charmer->GetFaction());
11931
11932 // Pause any Idle movement
11933 PauseMovement(0, 0, false);
11934
11935 // Remove any active voluntary movement
11937
11938 // Stop any remaining spline, if no involuntary movement is found
11939 auto criteria = [](MovementGenerator const* movement) -> bool
11940 {
11941 return movement->Priority == MOTION_PRIORITY_HIGHEST;
11942 };
11943 if (!GetMotionMaster()->HasMovementGenerator(criteria))
11944 StopMoving();
11945
11946 // Set charmed
11947 charmer->SetCharm(this, true);
11949
11950 if (Player* player = ToPlayer())
11951 {
11952 if (player->isAFK())
11953 player->ToggleAFK();
11954
11955 player->SetClientControl(this, false);
11956 }
11957
11958 // charm is set by aura, and aura effect remove handler was called during apply handler execution
11959 // prevent undefined behaviour
11960 if (aurApp && aurApp->GetRemoveMode())
11961 {
11962 // properly clean up charm changes up to this point to avoid leaving the unit in partially charmed state
11965 charmer->SetCharm(this, false);
11966 return false;
11967 }
11968
11969 // Pets already have a properly initialized CharmInfo, don't overwrite it.
11970 if (type != CHARM_TYPE_VEHICLE && !GetCharmInfo())
11971 {
11972 InitCharmInfo();
11973 if (type == CHARM_TYPE_POSSESS)
11975 else
11977 }
11978
11979 if (playerCharmer)
11980 {
11981 switch (type)
11982 {
11983 case CHARM_TYPE_VEHICLE:
11985 playerCharmer->SetClientControl(this, true);
11986 playerCharmer->VehicleSpellInitialize();
11987 break;
11988 case CHARM_TYPE_POSSESS:
11991 playerCharmer->SetClientControl(this, true);
11992 playerCharmer->PossessSpellInitialize();
11994 break;
11995 case CHARM_TYPE_CHARM:
11996 if (GetTypeId() == TYPEID_UNIT && charmer->GetClass() == CLASS_WARLOCK)
11997 {
11999 if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
12000 {
12001 // to prevent client crash
12003
12004 // just to enable stat window
12005 if (GetCharmInfo())
12006 GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true);
12007
12008 // if charmed two demons the same session, the 2nd gets the 1st one's name
12010 }
12011 }
12012 playerCharmer->CharmSpellInitialize();
12013 break;
12014 default:
12015 case CHARM_TYPE_CONVERT:
12016 break;
12017 }
12018 }
12019
12021
12022 if ((GetTypeId() != TYPEID_PLAYER) || (charmer->GetTypeId() != TYPEID_PLAYER))
12023 {
12024 // AI will schedule its own change if appropriate
12025 if (UnitAI* ai = GetAI())
12026 ai->OnCharmed(false);
12027 else
12029 }
12030 return true;
12031}
12032
12034{
12035 if (!IsCharmed())
12036 return;
12037
12038 if (charmer)
12039 ASSERT(charmer == GetCharmer());
12040 else
12041 charmer = GetCharmer();
12042
12043 ASSERT(charmer);
12044
12045 CharmType type;
12047 type = CHARM_TYPE_POSSESS;
12048 else if (charmer->IsOnVehicle(this))
12049 type = CHARM_TYPE_VEHICLE;
12050 else
12051 type = CHARM_TYPE_CHARM;
12052
12053 CastStop();
12054 AttackStop();
12055
12056 if (_oldFactionId)
12057 {
12059 _oldFactionId = 0;
12060 }
12061 else
12063
12064 if (type != CHARM_TYPE_CHARM && !IsPlayer())
12065 {
12066 StopMoving(true);
12067
12068 // Purge flags left over by client control
12070 }
12071
12074
12075 // Vehicle should not attack its passenger after he exists the seat
12076 if (type != CHARM_TYPE_VEHICLE)
12077 LastCharmerGUID = charmer->GetGUID();
12078
12079 ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
12081
12082 charmer->SetCharm(this, false);
12084
12085 Player* playerCharmer = charmer->ToPlayer();
12086 if (playerCharmer)
12087 {
12088 switch (type)
12089 {
12090 case CHARM_TYPE_VEHICLE:
12091 playerCharmer->SetClientControl(this, false);
12092 playerCharmer->SetClientControl(charmer, true);
12094 break;
12095 case CHARM_TYPE_POSSESS:
12097 playerCharmer->SetClientControl(this, false);
12098 playerCharmer->SetClientControl(charmer, true);
12101 break;
12102 case CHARM_TYPE_CHARM:
12103 if (GetTypeId() == TYPEID_UNIT && charmer->GetClass() == CLASS_WARLOCK)
12104 {
12106 if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
12107 {
12108 SetClass(uint8(cinfo->unit_class));
12109 if (GetCharmInfo())
12110 GetCharmInfo()->SetPetNumber(0, true);
12111 else
12112 TC_LOG_ERROR("entities.unit", "Aura::HandleModCharm: {} has a charm aura but no charm info!", GetGUID().ToString());
12113 }
12114 }
12115 break;
12116 case CHARM_TYPE_CONVERT:
12117 break;
12118 }
12119 }
12120
12121 if (Player* player = ToPlayer())
12122 player->SetClientControl(this, true);
12123
12124 if (playerCharmer && this != charmer->GetFirstControlled())
12125 playerCharmer->SendRemoveControlBar();
12126
12127 // a guardian should always have charminfo
12128 if (!IsGuardian())
12130
12131 // reset confused movement for example
12133
12134 if (GetTypeId() != TYPEID_PLAYER || charmer->GetTypeId() == TYPEID_UNIT)
12135 {
12136 if (UnitAI* charmedAI = GetAI())
12137 charmedAI->OnCharmed(false); // AI will potentially schedule a charm ai update
12138 else
12140 }
12141}
12142
12144{
12146 {
12147 SetFaction(GetAuraEffectsByType(SPELL_AURA_MOD_FACTION).front()->GetMiscValue());
12148 return;
12149 }
12150
12151 if (GetTypeId() == TYPEID_PLAYER)
12153 else
12154 {
12156 {
12157 if (Unit* owner = GetOwner())
12158 {
12159 SetFaction(owner->GetFaction());
12160 return;
12161 }
12162 }
12163
12164 if (CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate()) // normal creature
12165 SetFaction(cinfo->faction);
12166 }
12167}
12168
12169bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry, bool loading /*= false*/)
12170{
12171 VehicleEntry const* vehInfo = sVehicleStore.LookupEntry(id);
12172 if (!vehInfo)
12173 return false;
12174
12175 m_vehicleKit = Trinity::make_unique_trackable<Vehicle>(this, vehInfo, creatureEntry);
12176 m_updateFlag.Vehicle = true;
12178
12179 if (!loading)
12181
12182 return true;
12183}
12184
12185void Unit::RemoveVehicleKit(bool onRemoveFromWorld /*= false*/)
12186{
12187 if (!m_vehicleKit)
12188 return;
12189
12190 if (!onRemoveFromWorld)
12192
12194 m_vehicleKit = nullptr;
12195
12196 m_updateFlag.Vehicle = false;
12197 m_unitTypeMask &= ~UNIT_MASK_VEHICLE;
12199}
12200
12201bool Unit::IsOnVehicle(Unit const* vehicle) const
12202{
12203 return m_vehicle && m_vehicle == vehicle->GetVehicleKit();
12204}
12205
12207{
12208 return m_vehicle ? m_vehicle->GetBase() : nullptr;
12209}
12210
12212{
12213 Unit* vehicleRoot = GetVehicleBase();
12214
12215 if (!vehicleRoot)
12216 return nullptr;
12217
12218 for (;;)
12219 {
12220 if (!vehicleRoot->GetVehicleBase())
12221 return vehicleRoot;
12222
12223 vehicleRoot = vehicleRoot->GetVehicleBase();
12224 }
12225}
12226
12228{
12229 if (Unit* veh = GetVehicleBase())
12230 if (Creature* c = veh->ToCreature())
12231 return c;
12232
12233 return nullptr;
12234}
12235
12237{
12238 if (GetVehicle())
12239 return GetVehicleBase()->GetGUID();
12240 if (GetTransport())
12241 return GetTransport()->GetTransportGUID();
12242
12243 return ObjectGuid::Empty;
12244}
12245
12247{
12248 if (Vehicle* veh = GetVehicle())
12249 return veh;
12250 return GetTransport();
12251}
12252
12253bool Unit::IsInPartyWith(Unit const* unit) const
12254{
12255 if (this == unit)
12256 return true;
12257
12258 Unit const* u1 = GetCharmerOrOwnerOrSelf();
12259 Unit const* u2 = unit->GetCharmerOrOwnerOrSelf();
12260 if (u1 == u2)
12261 return true;
12262
12263 if (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
12264 return u1->ToPlayer()->IsInSameGroupWith(u2->ToPlayer());
12265 else if ((u2->GetTypeId() == TYPEID_PLAYER && u1->GetTypeId() == TYPEID_UNIT && u1->ToCreature()->IsTreatedAsRaidUnit()) ||
12267 return true;
12268
12269 return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
12270}
12271
12272bool Unit::IsInRaidWith(Unit const* unit) const
12273{
12274 if (this == unit)
12275 return true;
12276
12277 Unit const* u1 = GetCharmerOrOwnerOrSelf();
12278 Unit const* u2 = unit->GetCharmerOrOwnerOrSelf();
12279 if (u1 == u2)
12280 return true;
12281
12282 if (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
12283 return u1->ToPlayer()->IsInSameRaidWith(u2->ToPlayer());
12284 else if ((u2->GetTypeId() == TYPEID_PLAYER && u1->GetTypeId() == TYPEID_UNIT && u1->ToCreature()->IsTreatedAsRaidUnit()) ||
12286 return true;
12287
12288 return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
12289}
12290
12291void Unit::GetPartyMembers(std::list<Unit*> &TagUnitMap)
12292{
12293 Unit* owner = GetCharmerOrOwnerOrSelf();
12294 Group* group = nullptr;
12295 if (owner->GetTypeId() == TYPEID_PLAYER)
12296 group = owner->ToPlayer()->GetGroup();
12297
12298 if (group)
12299 {
12300 uint8 subgroup = owner->ToPlayer()->GetSubGroup();
12301
12302 for (GroupReference const& itr : group->GetMembers())
12303 {
12304 Player* Target = itr.GetSource();
12305
12306 // IsHostileTo check duel and controlled by enemy
12307 if (Target->IsInMap(owner) && Target->GetSubGroup() == subgroup && !IsHostileTo(Target))
12308 {
12309 if (Target->IsAlive())
12310 TagUnitMap.push_back(Target);
12311
12312 if (Guardian* pet = Target->GetGuardianPet())
12313 if (pet->IsAlive())
12314 TagUnitMap.push_back(pet);
12315 }
12316 }
12317 }
12318 else
12319 {
12320 if ((owner == this || IsInMap(owner)) && owner->IsAlive())
12321 TagUnitMap.push_back(owner);
12322 if (Guardian* pet = owner->GetGuardianPet())
12323 if ((pet == this || IsInMap(pet)) && pet->IsAlive())
12324 TagUnitMap.push_back(pet);
12325 }
12326}
12327
12329{
12330 if (FactionTemplateEntry const* entry = GetFactionTemplateEntry())
12331 return entry->IsContestedGuardFaction();
12332
12333 return false;
12334}
12335
12336void Unit::SetPvP(bool state)
12337{
12338 if (state)
12340 else
12342}
12343
12344Aura* Unit::AddAura(uint32 spellId, Unit* target)
12345{
12346 if (!target)
12347 return nullptr;
12348
12349 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID());
12350 if (!spellInfo)
12351 return nullptr;
12352
12353 return AddAura(spellInfo, MAX_EFFECT_MASK, target);
12354}
12355
12356Aura* Unit::AddAura(SpellInfo const* spellInfo, uint32 effMask, Unit* target)
12357{
12358 if (!spellInfo)
12359 return nullptr;
12360
12361 if (!target->IsAlive() && !spellInfo->IsPassive() && !spellInfo->HasAttribute(SPELL_ATTR2_ALLOW_DEAD_TARGET))
12362 return nullptr;
12363
12364 if (target->IsImmunedToSpell(spellInfo, effMask, this))
12365 return nullptr;
12366
12367 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
12368 {
12369 if (!(effMask & (1 << spellEffectInfo.EffectIndex)))
12370 continue;
12371
12372 if (target->IsImmunedToSpellEffect(spellInfo, spellEffectInfo, this))
12373 effMask &= ~(1 << spellEffectInfo.EffectIndex);
12374 }
12375
12376 if (!effMask)
12377 return nullptr;
12378
12379 ObjectGuid castId = ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellInfo->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>());
12380 AuraCreateInfo createInfo(castId, spellInfo, GetMap()->GetDifficultyID(), effMask, target);
12381 createInfo.SetCaster(this);
12382
12383 if (Aura* aura = Aura::TryRefreshStackOrCreate(createInfo))
12384 {
12385 aura->ApplyForTargets();
12386 return aura;
12387 }
12388 return nullptr;
12389}
12390
12391void Unit::SetAuraStack(uint32 spellId, Unit* target, uint32 stack)
12392{
12393 Aura* aura = target->GetAura(spellId, GetGUID());
12394 if (!aura)
12395 aura = AddAura(spellId, target);
12396 if (aura && stack)
12397 aura->SetStackAmount(stack);
12398}
12399
12400void Unit::SendPlaySpellVisual(Unit* target, uint32 spellVisualId, uint8 missReason, uint8 reflectStatus, float travelSpeed, bool speedAsTime /*= false*/, float launchDelay /*= 0.0f*/)
12401{
12403 playSpellVisual.Source = GetGUID();
12404 playSpellVisual.Target = target->GetGUID();
12405 playSpellVisual.TargetPosition = target->GetPosition();
12406 playSpellVisual.SpellVisualID = spellVisualId;
12407 playSpellVisual.TravelSpeed = travelSpeed;
12408 playSpellVisual.MissReason = missReason;
12409 playSpellVisual.ReflectStatus = reflectStatus;
12410 playSpellVisual.SpeedAsTime = speedAsTime;
12411 playSpellVisual.LaunchDelay = launchDelay;
12412 SendMessageToSet(playSpellVisual.Write(), true);
12413}
12414
12415void Unit::SendPlaySpellVisual(Position const& targetPosition, uint32 spellVisualId, uint8 missReason, uint8 reflectStatus, float travelSpeed, bool speedAsTime /*= false*/, float launchDelay /*= 0.0f*/)
12416{
12418 playSpellVisual.Source = GetGUID();
12419 playSpellVisual.TargetPosition = targetPosition;
12420 playSpellVisual.SpellVisualID = spellVisualId;
12421 playSpellVisual.TravelSpeed = travelSpeed;
12422 playSpellVisual.MissReason = missReason;
12423 playSpellVisual.ReflectStatus = reflectStatus;
12424 playSpellVisual.SpeedAsTime = speedAsTime;
12425 playSpellVisual.LaunchDelay = launchDelay;
12426 SendMessageToSet(playSpellVisual.Write(), true);
12427}
12428
12430{
12432 cancelSpellVisual.Source = GetGUID();
12433 cancelSpellVisual.SpellVisualID = id;
12434 SendMessageToSet(cancelSpellVisual.Write(), true);
12435}
12436
12437void Unit::SendPlaySpellVisualKit(uint32 id, uint32 type, uint32 duration) const
12438{
12440 playSpellVisualKit.Unit = GetGUID();
12441 playSpellVisualKit.KitRecID = id;
12442 playSpellVisualKit.KitType = type;
12443 playSpellVisualKit.Duration = duration;
12444 SendMessageToSet(playSpellVisualKit.Write(), true);
12445}
12446
12448{
12449 WorldPackets::Spells::CancelSpellVisualKit cancelSpellVisualKit;
12450 cancelSpellVisualKit.Source = GetGUID();
12451 cancelSpellVisualKit.SpellVisualKitID = id;
12452 SendMessageToSet(cancelSpellVisualKit.Write(), true);
12453}
12454
12455void Unit::CancelSpellMissiles(uint32 spellId, bool reverseMissile /*= false*/, bool abortSpell /*= false*/)
12456{
12457 bool hasMissile = false;
12458 if (abortSpell)
12459 {
12460 for (std::pair<uint64 const, BasicEvent*> const& itr : m_Events.GetEvents())
12461 {
12462 if (Spell const* spell = Spell::ExtractSpellFromEvent(itr.second))
12463 {
12464 if (spell->GetSpellInfo()->Id == spellId)
12465 {
12466 itr.second->ScheduleAbort();
12467 hasMissile = true;
12468 }
12469 }
12470 }
12471 }
12472 else
12473 hasMissile = true;
12474
12475 if (hasMissile)
12476 {
12478 packet.OwnerGUID = GetGUID();
12479 packet.SpellID = spellId;
12480 packet.Reverse = reverseMissile;
12481 SendMessageToSet(packet.Write(), false);
12482 }
12483}
12484
12486{
12487 return !IsVehicle() && GetOwnerGUID().IsPlayer();
12488}
12489
12490/*static*/ void Unit::ApplyResilience(Unit const* victim, int32* damage)
12491{
12492 // player mounted on multi-passenger mount is also classified as vehicle
12493 if (victim->IsVehicle() && victim->GetTypeId() != TYPEID_PLAYER)
12494 return;
12495
12496 Unit const* target = nullptr;
12497 if (victim->GetTypeId() == TYPEID_PLAYER)
12498 target = victim;
12499 else // victim->GetTypeId() == TYPEID_UNIT
12500 {
12501 if (Unit* owner = victim->GetOwner())
12502 if (owner->GetTypeId() == TYPEID_PLAYER)
12503 target = owner;
12504 }
12505
12506 if (!target)
12507 return;
12508
12509 *damage -= target->GetDamageReduction(*damage);
12510}
12511
12512int32 Unit::CalculateAOEAvoidance(int32 damage, uint32 schoolMask, bool npcCaster) const
12513{
12514 damage = int32(float(damage) * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, schoolMask));
12515 if (npcCaster)
12517
12518 return damage;
12519}
12520
12521// Melee based spells can be miss, parry or dodge on this step
12522// Crit or block - determined on damage calculation phase! (and can be both in some time)
12523float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, SpellInfo const* spellInfo) const
12524{
12525 if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_MISS))
12526 return 0.f;
12527
12528 //calculate miss chance
12529 float missChance = victim->GetUnitMissChance();
12530
12531 // melee attacks while dual wielding have +19% chance to miss
12532 if (!spellInfo && haveOffhandWeapon() && attType != RANGED_ATTACK && !m_currentSpells[CURRENT_MELEE_SPELL]
12534 missChance += 19.0f;
12535
12536 // Spellmod from SpellModOp::HitChance
12537 float resistMissChance = 100.0f;
12538 if (spellInfo)
12539 if (Player* modOwner = GetSpellModOwner())
12540 modOwner->ApplySpellMod(spellInfo, SpellModOp::HitChance, resistMissChance);
12541
12542 missChance -= resistMissChance - 100.0f;
12543
12544 if (attType == RANGED_ATTACK)
12545 missChance -= m_modRangedHitChance;
12546 else
12547 missChance -= m_modMeleeHitChance;
12548
12549 // miss chance from auras after calculating skill based miss
12551 if (attType == RANGED_ATTACK)
12553 else
12555
12556 return std::max(missChance, 0.f);
12557}
12558
12560{
12561}
12562
12564{
12565 if (!forced)
12567 else
12568 {
12570 // call MoveInLineOfSight for nearby creatures
12571 Trinity::AIRelocationNotifier notifier(*this);
12572 Cell::VisitAllObjects(this, notifier, GetVisibilityRange());
12573 }
12574}
12575
12576void Unit::SendMoveKnockBack(Player* player, float speedXY, float speedZ, float vcos, float vsin)
12577{
12579 moveKnockBack.MoverGUID = GetGUID();
12580 moveKnockBack.SequenceIndex = m_movementCounter++;
12581 moveKnockBack.Speeds.HorzSpeed = speedXY;
12582 moveKnockBack.Speeds.VertSpeed = speedZ;
12583 moveKnockBack.Direction = Position(vcos, vsin);
12584 player->GetSession()->SendPacket(moveKnockBack.Write());
12585}
12586
12587void Unit::KnockbackFrom(Position const& origin, float speedXY, float speedZ, float angle /*= M_PI*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
12588{
12589 Player* player = ToPlayer();
12590 if (!player)
12591 {
12592 if (Unit* charmer = GetCharmer())
12593 {
12594 player = charmer->ToPlayer();
12595 if (player && player->GetUnitBeingMoved() != this)
12596 player = nullptr;
12597 }
12598 }
12599
12600 if (!player)
12601 GetMotionMaster()->MoveKnockbackFrom(origin, speedXY, speedZ, angle, spellEffectExtraData);
12602 else
12603 {
12604 float o = (GetPosition() == origin ? GetOrientation() : GetAbsoluteAngle(origin)) + angle;
12605 if (speedXY < 0)
12606 {
12607 speedXY = -speedXY;
12608 o = o - float(M_PI);
12609 }
12610
12611 float vcos = std::cos(o);
12612 float vsin = std::sin(o);
12613 SendMoveKnockBack(player, speedXY, -speedZ, vcos, vsin);
12614 }
12615}
12616
12618{
12619 if (Player const* player = ToPlayer())
12620 return player->GetRatingBonusValue(cr);
12621 // Player's pet get resilience from owner
12622 else if (IsPet() && GetOwner())
12623 if (Player* owner = GetOwner()->ToPlayer())
12624 return owner->GetRatingBonusValue(cr);
12625
12626 return 0.0f;
12627}
12628
12629uint32 Unit::GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const
12630{
12631 float percent = std::min(GetCombatRatingReduction(cr) * rate, cap);
12632 return CalculatePct(damage, percent);
12633}
12634
12636{
12637 // Hardcoded cases
12638 switch (spellId)
12639 {
12640 case 7090: // Bear Form
12641 return 29414;
12642 case 35200: // Roc Form
12643 return 4877;
12644 case 24858: // Moonkin Form
12645 {
12646 if (HasAura(114301)) // Glyph of Stars
12647 return 0;
12648 break;
12649 }
12650 default:
12651 break;
12652 }
12653
12654 if (Player const* player = ToPlayer())
12655 {
12657 if (Item* artifact = player->GetItemByGuid(artifactAura->GetCastItemGUID()))
12658 if (ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifact->GetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID)))
12659 if (ShapeshiftForm(artifactAppearance->OverrideShapeshiftFormID) == form)
12660 return artifactAppearance->OverrideShapeshiftDisplayID;
12661
12662 if (ShapeshiftFormModelData const* formModelData = sDB2Manager.GetShapeshiftFormModelData(GetRace(), player->GetNativeGender(), form))
12663 {
12664 bool useRandom = false;
12665 switch (form)
12666 {
12667 case FORM_CAT_FORM: useRandom = HasAura(210333); break; // Glyph of the Feral Chameleon
12668 case FORM_TRAVEL_FORM: useRandom = HasAura(344336); break; // Glyph of the Swift Chameleon
12669 case FORM_AQUATIC_FORM: useRandom = HasAura(344338); break; // Glyph of the Aquatic Chameleon
12671 case FORM_BEAR_FORM: useRandom = HasAura(107059); break; // Glyph of the Ursol Chameleon
12673 case FORM_FLIGHT_FORM: useRandom = HasAura(344342); break; // Glyph of the Aerial Chameleon
12674 default:
12675 break;
12676 }
12677
12678 if (useRandom)
12679 {
12680 std::vector<uint32> displayIds;
12681 displayIds.reserve(formModelData->Choices->size());
12682
12683 for (std::size_t i = 0; i < formModelData->Choices->size(); ++i)
12684 {
12685 if (ChrCustomizationDisplayInfoEntry const* displayInfo = formModelData->Displays[i])
12686 {
12687 ChrCustomizationReqEntry const* choiceReq = sChrCustomizationReqStore.LookupEntry((*formModelData->Choices)[i]->ChrCustomizationReqID);
12688 if (!choiceReq || player->GetSession()->MeetsChrCustomizationReq(choiceReq, Races(GetRace()), Classes(GetClass()), false,
12689 MakeChrCustomizationChoiceRange(player->m_playerData->Customizations)))
12690 displayIds.push_back(displayInfo->DisplayID);
12691 }
12692 }
12693
12694 if (!displayIds.empty())
12696 }
12697 else
12698 {
12699 if (uint32 formChoice = player->GetCustomizationChoice(formModelData->OptionID))
12700 {
12701 auto choiceItr = std::find_if(formModelData->Choices->begin(), formModelData->Choices->end(), [formChoice](ChrCustomizationChoiceEntry const* choice)
12702 {
12703 return choice->ID == formChoice;
12704 });
12705
12706 if (choiceItr != formModelData->Choices->end())
12707 if (ChrCustomizationDisplayInfoEntry const* displayInfo = formModelData->Displays[std::distance(formModelData->Choices->begin(), choiceItr)])
12708 return displayInfo->DisplayID;
12709 }
12710 }
12711 }
12712 switch (form)
12713 {
12714 case FORM_GHOST_WOLF:
12715 {
12716 if (HasAura(58135)) // Glyph of Spectral Wolf
12717 return 60247;
12718 break;
12719 }
12720 default:
12721 break;
12722 }
12723 }
12724
12725 SpellShapeshiftFormEntry const* formEntry = sSpellShapeshiftFormStore.LookupEntry(form);
12726 if (formEntry && formEntry->CreatureDisplayID)
12727 return formEntry->CreatureDisplayID;
12728
12729 return 0;
12730}
12731
12732void Unit::HandleSpellClick(Unit* clicker, int8 seatId /*= -1*/)
12733{
12734 bool spellClickHandled = false;
12735 uint32 spellClickEntry = GetVehicleKit() ? GetVehicleKit()->GetCreatureEntry() : GetEntry();
12737
12738 auto clickBounds = sObjectMgr->GetSpellClickInfoMapBounds(spellClickEntry);
12739 for (auto const& clickPair : clickBounds)
12740 {
12742 if (!clickPair.second.IsFitToRequirements(clicker, this))
12743 continue;
12744
12746 if (!sConditionMgr->IsObjectMeetingSpellClickConditions(spellClickEntry, clickPair.second.spellId, clicker, this))
12747 continue;
12748
12749 spellClickHandled = HandleSpellClick(clicker, seatId, clickPair.second.spellId, flags, &clickPair.second);
12750
12751 // if (!spellEntry) should be checked at npc_spellclick load
12752 }
12753
12754 Creature* creature = ToCreature();
12755 if (creature && creature->IsAIEnabled())
12756 creature->AI()->OnSpellClick(clicker, spellClickHandled);
12757}
12758
12759bool Unit::HandleSpellClick(Unit* clicker, int8 seatId, uint32 spellId, TriggerCastFlags flags /*= TRIGGERED_NONE*/, SpellClickInfo const* spellClickInfo /*= nullptr*/)
12760{
12761 Unit* caster = clicker;
12762 Unit* target = this;
12763 ObjectGuid origCasterGUID = caster->GetGUID();
12765
12766 if (spellClickInfo)
12767 {
12768 caster = (spellClickInfo->castFlags & NPC_CLICK_CAST_CASTER_CLICKER) ? clicker : this;
12769 target = (spellClickInfo->castFlags & NPC_CLICK_CAST_TARGET_CLICKER) ? clicker : this;
12770 origCasterGUID = (spellClickInfo->castFlags & NPC_CLICK_CAST_ORIG_CASTER_OWNER) ? GetOwnerGUID() : clicker->GetGUID();
12771 }
12772
12773 if (!spellId)
12774 {
12775 TC_LOG_ERROR("sql.sql", "No valid spell specified for clickee {} and clicker {}!", target->GetGUID(), caster->GetGUID());
12776 return false;
12777 }
12778
12779 SpellInfo const* spellEntry = sSpellMgr->AssertSpellInfo(spellId, caster->GetMap()->GetDifficultyID());
12780
12781 uint8 effectIndex = 0;
12782 bool hasControlVehicleAura = false;
12783 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
12784 {
12785 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_CONTROL_VEHICLE)
12786 {
12787 hasControlVehicleAura = true;
12788 break;
12789 }
12790 ++effectIndex;
12791 }
12792
12793 if (seatId > -1)
12794 {
12795 if (!hasControlVehicleAura)
12796 {
12797 if (!spellClickInfo)
12798 TC_LOG_ERROR("sql.sql", "RideSpell {} specified in vehicle_accessory or vehicle_template_accessory is not a valid vehicle enter aura!", spellId);
12799 else
12800 TC_LOG_ERROR("sql.sql", "Spell {} specified in npc_spellclick_spells is not a valid vehicle enter aura!", spellId);
12801 return false;
12802 }
12803
12804 if (IsInMap(caster))
12805 {
12807 args.OriginalCaster = origCasterGUID;
12808 args.AddSpellMod(SpellValueModFloat(SPELLVALUE_BASE_POINT0 + effectIndex), seatId + 1);
12809 castResult = caster->CastSpell(target, spellId, args);
12810 }
12811 else // This can happen during Player::_LoadAuras
12812 {
12813 std::array<SpellEffectValue, MAX_SPELL_EFFECTS> bp = { };
12814 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
12815 bp[spellEffectInfo.EffectIndex] = spellEffectInfo.BasePoints;
12816
12817 bp[effectIndex] = seatId;
12818
12819 AuraCreateInfo createInfo(ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), spellEntry, GetMap()->GetDifficultyID(), MAX_EFFECT_MASK, this);
12820 createInfo
12821 .SetCaster(clicker)
12822 .SetBaseAmount(bp.data())
12823 .SetCasterGUID(origCasterGUID);
12824
12826 }
12827 }
12828 else
12829 {
12830 if (IsInMap(caster))
12831 castResult = caster->CastSpell(target, spellEntry->Id, CastSpellExtraArgs().SetOriginalCaster(origCasterGUID));
12832 else
12833 {
12834 AuraCreateInfo createInfo(ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), spellEntry, GetMap()->GetDifficultyID(), MAX_EFFECT_MASK, this);
12835 createInfo
12836 .SetCaster(clicker)
12837 .SetCasterGUID(origCasterGUID);
12838
12840 }
12841 }
12842 return castResult == SPELL_FAILED_SUCCESS;
12843}
12844
12845void Unit::EnterVehicle(Unit* base, int8 seatId /*= -1*/)
12846{
12848 args.AddSpellMod(SPELLVALUE_BASE_POINT0, seatId + 1);
12850}
12851
12852void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* aurApp)
12853{
12854 // Must be called only from aura handler
12855 ASSERT(aurApp);
12856
12857 if (!IsAlive() || GetVehicleKit() == vehicle || vehicle->GetBase()->IsOnVehicle(this))
12858 return;
12859
12860 if (m_vehicle)
12861 {
12862 if (m_vehicle != vehicle)
12863 {
12864 TC_LOG_DEBUG("entities.vehicle", "EnterVehicle: {} exit {} and enter {}.", GetEntry(), m_vehicle->GetBase()->GetEntry(), vehicle->GetBase()->GetEntry());
12865 ExitVehicle();
12866 }
12867 else if (seatId >= 0 && seatId == GetTransSeat())
12868 return;
12869 else
12870 {
12871 //Exit the current vehicle because unit will reenter in a new seat.
12873 }
12874 }
12875
12876 if (aurApp->GetRemoveMode())
12877 return;
12878
12879 if (Player* player = ToPlayer())
12880 {
12881 if (vehicle->GetBase()->GetTypeId() == TYPEID_PLAYER && player->IsInCombat())
12882 {
12883 vehicle->GetBase()->RemoveAura(const_cast<AuraApplication*>(aurApp));
12884 return;
12885 }
12886
12887 if (Creature* vehicleBaseCreature = vehicle->GetBase()->ToCreature())
12888 {
12889 // If a player entered a vehicle that is part of a formation, remove it from said formation
12890 if (CreatureGroup* creatureGroup = vehicleBaseCreature->GetFormation())
12891 FormationMgr::RemoveCreatureFromGroup(creatureGroup, vehicleBaseCreature);
12892 }
12893 }
12894
12895 ASSERT(!m_vehicle);
12896 (void)vehicle->AddVehiclePassenger(this, seatId);
12897}
12898
12899void Unit::ChangeSeat(int8 seatId, bool next)
12900{
12901 if (!m_vehicle)
12902 return;
12903
12904 // Don't change if current and new seat are identical
12905 if (seatId == GetTransSeat())
12906 return;
12907
12908 SeatMap::const_iterator seat = (seatId < 0 ? m_vehicle->GetNextEmptySeat(GetTransSeat(), next) : m_vehicle->Seats.find(seatId));
12909 // The second part of the check will only return true if seatId >= 0. @Vehicle::GetNextEmptySeat makes sure of that.
12910 if (seat == m_vehicle->Seats.end() || !seat->second.IsEmpty())
12911 return;
12912
12913 AuraEffect* rideVehicleEffect = nullptr;
12915 for (AuraEffectList::const_iterator itr = vehicleAuras.begin(); itr != vehicleAuras.end(); ++itr)
12916 {
12917 if ((*itr)->GetCasterGUID() != GetGUID())
12918 continue;
12919
12920 // Make sure there is only one ride vehicle aura on target cast by the unit changing seat
12921 ASSERT(!rideVehicleEffect);
12922 rideVehicleEffect = *itr;
12923 }
12924
12925 // Unit riding a vehicle must always have control vehicle aura on target
12926 ASSERT(rideVehicleEffect);
12927
12928 rideVehicleEffect->ChangeAmount(seat->first + 1);
12929}
12930
12931void Unit::ExitVehicle(Position const* /*exitPosition*/)
12932{
12934 if (!m_vehicle)
12935 return;
12936
12941 /*_ExitVehicle(exitPosition);*/
12948}
12949
12950void Unit::_ExitVehicle(Position const* exitPosition)
12951{
12955 if (!m_vehicle)
12956 return;
12957
12958 // This should be done before dismiss, because there may be some aura removal
12960 Vehicle* vehicle = m_vehicle->RemovePassenger(this);
12961
12962 if (!vehicle)
12963 {
12964 TC_LOG_ERROR("entities.vehicle", "RemovePassenger() couldn't remove current unit from vehicle. Debug info: {}", GetDebugInfo());
12965 return;
12966 }
12967
12968 Player* player = ToPlayer();
12969
12970 // If the player is on mounted duel and exits the mount, he should immediatly lose the duel
12971 if (player && player->duel && player->duel->IsMounted)
12972 player->DuelComplete(DUEL_FLED);
12973
12974 SetControlled(false, UNIT_STATE_ROOT); // SMSG_MOVE_FORCE_UNROOT, ~MOVEMENTFLAG_ROOT
12975
12977
12978 if (player)
12979 player->SetFallInformation(0, GetPositionZ());
12980
12981 Position pos;
12982 // If we ask for a specific exit position, use that one. Otherwise allow scripts to modify it
12983 if (exitPosition)
12984 pos = *exitPosition;
12985 else
12986 {
12987 // Set exit position to vehicle position and use the current orientation
12988 pos = vehicle->GetBase()->GetPosition();
12990
12991 // Change exit position based on seat entry addon data
12992 if (seatAddon)
12993 {
12995 pos.RelocateOffset({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
12997 pos.Relocate({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
12998 }
12999 }
13000
13001 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this, vehicleCollisionHeight = vehicle->GetBase()->GetCollisionHeight()](Movement::MoveSplineInit& init)
13002 {
13003 float height = pos.GetPositionZ() + vehicleCollisionHeight;
13004
13005 // Creatures without inhabit type air should begin falling after exiting the vehicle
13006 if (GetTypeId() == TYPEID_UNIT && !CanFly() && height > GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() + vehicleCollisionHeight, &height))
13007 init.SetFall();
13008
13009 init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), height, false);
13010 init.SetFacing(pos.GetOrientation());
13011 init.SetTransportExit();
13012 };
13014
13015 if (player)
13017
13018 if (vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION) && vehicle->GetBase()->GetTypeId() == TYPEID_UNIT)
13019 if (((Minion*)vehicle->GetBase())->GetOwner() == this)
13020 vehicle->GetBase()->ToCreature()->DespawnOrUnsummon(vehicle->GetDespawnDelay());
13021
13023 {
13024 // Vehicle just died, we die too
13025 if (vehicle->GetBase()->getDeathState() == JUST_DIED)
13027 // If for other reason we as minion are exiting the vehicle (ejected, master dismounted) - unsummon
13028 else
13029 ToTempSummon()->UnSummon(2000); // Approximation
13030 }
13031
13033}
13034
13039
13040bool Unit::CanSwim() const
13041{
13042 // 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
13044 return false;
13045 if (HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) // is player
13046 return true;
13048 return false;
13050 return true;
13052}
13053
13054void Unit::NearTeleportTo(TeleportLocation const& target, bool casting)
13055{
13056 if (Player* player = ToPlayer())
13057 player->TeleportTo(target, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | (casting ? TELE_TO_SPELL : TELE_TO_NONE));
13058 else
13059 {
13060 DisableSpline();
13062 SendTeleportPacket(target);
13063 UpdatePosition(target.Location, true);
13065 }
13066}
13067
13068void Unit::NearTeleportTo(Position const& pos, bool casting /*= false*/)
13069{
13070 NearTeleportTo(TeleportLocation{ .Location = { GetMapId(), pos } }, casting);
13071}
13072
13073void Unit::SendTeleportPacket(TeleportLocation const& teleportLocation)
13074{
13075 // SMSG_MOVE_UPDATE_TELEPORT is sent to nearby players to signal the teleport
13076 // SMSG_MOVE_TELEPORT is sent to self in order to trigger CMSG_MOVE_TELEPORT_ACK and update the position server side
13077
13079 moveUpdateTeleport.Status = &m_movementInfo;
13080 if (_movementForces)
13081 moveUpdateTeleport.MovementForces = *_movementForces->GetForces();
13082
13083 // should this really be the unit _being_ moved? not the unit doing the moving?
13084 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13085 {
13087 moveTeleport.MoverGUID = GetGUID();
13088 moveTeleport.Pos = teleportLocation.Location;
13089 moveTeleport.TransportGUID = teleportLocation.TransportGuid;
13090 moveTeleport.Facing = teleportLocation.Location.GetOrientation();
13091 moveTeleport.SequenceIndex = m_movementCounter++;
13092 playerMover->SendDirectMessage(moveTeleport.Write());
13093
13094 // Broadcast the packet to everyone except self.
13095 SendMessageToSet(moveUpdateTeleport.Write(), playerMover);
13096 }
13097 else
13098 {
13099 // This is the only packet sent for creatures which contains MovementInfo structure
13100 // we do not update m_movementInfo for creatures so it needs to be done manually here
13101 moveUpdateTeleport.Status->guid = GetGUID();
13102 moveUpdateTeleport.Status->time = GameTime::GetGameTimeMS();
13103
13104 if (teleportLocation.TransportGuid)
13105 {
13106 Transport* transport = GetMap()->GetTransport(*teleportLocation.TransportGuid);
13107 if (!transport)
13108 return;
13109
13110 moveUpdateTeleport.Status->pos.Relocate(transport->GetPositionWithOffset(teleportLocation.Location));
13111 moveUpdateTeleport.Status->transport.pos.Relocate(teleportLocation.Location);
13112 }
13113 else
13114 {
13115 moveUpdateTeleport.Status->pos.Relocate(teleportLocation.Location);
13116 moveUpdateTeleport.Status->transport.Reset();
13117 }
13118
13119 SendMessageToSet(moveUpdateTeleport.Write(), true);
13120 }
13121}
13122
13123bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool teleport)
13124{
13125 // prevent crash when a bad coord is sent by the client
13126 if (!Trinity::IsValidMapCoord(x, y, z, orientation))
13127 {
13128 TC_LOG_DEBUG("entities.unit", "Unit::UpdatePosition({}, {}, {}) .. bad coordinates!", x, y, z);
13129 return false;
13130 }
13131
13132 // Check if angular distance changed
13133 bool const turn = G3D::fuzzyGt(M_PI - fabs(fabs(GetOrientation() - orientation) - M_PI), 0.0f);
13134
13135 // G3D::fuzzyEq won't help here, in some cases magnitudes differ by a little more than G3D::eps, but should be considered equal
13136 bool const relocated = (teleport ||
13137 std::fabs(GetPositionX() - x) > 0.001f ||
13138 std::fabs(GetPositionY() - y) > 0.001f ||
13139 std::fabs(GetPositionZ() - z) > 0.001f);
13140
13141 if (relocated)
13142 {
13143 // move and update visible state if need
13144 if (GetTypeId() == TYPEID_PLAYER)
13145 GetMap()->PlayerRelocation(ToPlayer(), x, y, z, orientation);
13146 else
13147 GetMap()->CreatureRelocation(ToCreature(), x, y, z, orientation);
13148
13150 for (AuraEffect const* auraEffect : controlZoneAuras)
13151 if (GameObject* controlZone = GetGameObject(auraEffect->GetSpellInfo()->Id))
13152 GetMap()->GameObjectRelocation(controlZone, x, y, z, orientation);
13153 }
13154 else if (turn)
13155 UpdateOrientation(orientation);
13156
13157 _positionUpdateInfo.Relocated = relocated;
13159
13160 if (IsFalling())
13162
13163 bool isInWater = IsInWater();
13164 if (!IsFalling() || isInWater || IsFlying())
13166
13167 if (isInWater)
13169
13170 return (relocated || turn);
13171}
13172
13173bool Unit::UpdatePosition(Position const& pos, bool teleport)
13174{
13175 return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport);
13176}
13177
13179void Unit::UpdateOrientation(float orientation)
13180{
13181 SetOrientation(orientation);
13182 if (IsVehicle())
13184}
13185
13187void Unit::UpdateHeight(float newZ)
13188{
13190 if (IsVehicle())
13192}
13193
13194// baseRage means damage taken when attacker = false
13196{
13197 float addRage = baseRage;
13198
13199 // talent who gave more rage on attack
13201
13202 addRage *= sWorld->getRate(RATE_POWER_RAGE_INCOME);
13203
13204 return ModifyPower(POWER_RAGE, uint32(addRage * 10), false);
13205}
13206
13208{
13209 if (Unit* victim = GetVictim())
13210 {
13211 if (victim->GetFactionTemplateEntry()->Faction == faction_id)
13212 {
13213 AttackStop();
13214 if (IsNonMeleeSpellCast(false))
13216
13217 // melee and ranged forced attack cancel
13218 if (GetTypeId() == TYPEID_PLAYER)
13220 }
13221 }
13222
13223 AttackerSet const& attackers = getAttackers();
13224 for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end();)
13225 {
13226 if ((*itr)->GetFactionTemplateEntry()->Faction == faction_id)
13227 {
13228 (*itr)->AttackStop();
13229 itr = attackers.begin();
13230 }
13231 else
13232 ++itr;
13233 }
13234
13235 std::vector<CombatReference*> refsToEnd;
13236 for (auto const& pair : m_combatManager.GetPvECombatRefs())
13237 if (pair.second->GetOther(this)->GetFactionTemplateEntry()->Faction == faction_id)
13238 refsToEnd.push_back(pair.second);
13239 for (CombatReference* ref : refsToEnd)
13240 ref->EndCombat();
13241
13242 for (Unit* minion : m_Controlled)
13243 minion->StopAttackFaction(faction_id);
13244}
13245
13247{
13248 TC_LOG_ERROR("entities.unit", "Unit::OutDebugInfo");
13249 TC_LOG_DEBUG("entities.unit", "{} name {}", GetGUID().ToString(), GetName());
13250 TC_LOG_DEBUG("entities.unit", "Owner {}, Minion {}, Charmer {}, Charmed {}", GetOwnerGUID().ToString(), GetMinionGUID().ToString(), GetCharmerGUID().ToString(), GetCharmedGUID().ToString());
13251 TC_LOG_DEBUG("entities.unit", "In world {}, unit type mask {}", (uint32)(IsInWorld() ? 1 : 0), m_unitTypeMask);
13252 if (IsInWorld())
13253 TC_LOG_DEBUG("entities.unit", "Mapid {}", GetMapId());
13254
13255 std::ostringstream o;
13256 o << "Summon Slot: ";
13257 for (uint32 i = 0; i < MAX_SUMMON_SLOT; ++i)
13258 o << m_SummonSlot[i].ToString() << ", ";
13259
13260 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13261 o.str("");
13262
13263 o << "Controlled List: ";
13264 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
13265 o << (*itr)->GetGUID().ToString() << ", ";
13266 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13267 o.str("");
13268
13269 o << "Aura List: ";
13270 for (AuraApplicationMap::const_iterator itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
13271 o << itr->first << ", ";
13272 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13273 o.str("");
13274
13275 if (IsVehicle())
13276 {
13277 o << "Passenger List: ";
13278 for (SeatMap::iterator itr = GetVehicleKit()->Seats.begin(); itr != GetVehicleKit()->Seats.end(); ++itr)
13279 if (Unit* passenger = ObjectAccessor::GetUnit(*GetVehicleBase(), itr->second.Passenger.Guid))
13280 o << passenger->GetGUID().ToString() << ", ";
13281 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13282 }
13283
13284 if (GetVehicle())
13285 TC_LOG_DEBUG("entities.unit", "On vehicle {}.", GetVehicleBase()->GetEntry());
13286}
13287
13289{
13291 breakTarget.UnitGUID = GetGUID();
13292 SendMessageToSet(breakTarget.Write(), false);
13293}
13294
13296{
13297 Optional<int32> resist;
13298 for (int32 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
13299 {
13300 int32 schoolResistance = GetResistance(SpellSchools(i));
13301 if (mask & (1 << i) && (!resist || *resist > schoolResistance))
13302 resist = schoolResistance;
13303 }
13304
13305 return resist.value_or(0);
13306}
13307
13309{
13310 _isCommandAttack = val;
13311}
13312
13314{
13315 return _isCommandAttack;
13316}
13317
13319{
13320 _isCommandFollow = val;
13321}
13322
13324{
13325 return _isCommandFollow;
13326}
13327
13329{
13331 G3D::Vector3 stayPos = _unit->movespline->FinalDestination();
13332
13333 if (_unit->movespline->onTransport)
13334 if (TransportBase* transport = _unit->GetDirectTransport())
13335 transport->GetPositionWithOffset({ stayPos.x, stayPos.y, stayPos.z }).GetPosition(stayPos.x, stayPos.y, stayPos.z);
13336
13337 _stayX = stayPos.x;
13338 _stayY = stayPos.y;
13339 _stayZ = stayPos.z;
13340}
13341
13342void CharmInfo::GetStayPosition(float &x, float &y, float &z)
13343{
13344 x = _stayX;
13345 y = _stayY;
13346 z = _stayZ;
13347}
13348
13350{
13351 _isAtStay = val;
13352}
13353
13355{
13356 return _isAtStay;
13357}
13358
13360{
13361 _isFollowing = val;
13362}
13363
13365{
13366 return _isFollowing;
13367}
13368
13370{
13371 _isReturning = val;
13372}
13373
13375{
13376 return _isReturning;
13377}
13378
13380{
13383}
13384
13385void Unit::SetFacingTo(float ori, bool force /*= true*/, uint32 movementId /*= EVENT_FACE*/)
13386{
13387 // do not face when already moving
13388 if (!force && (!IsStopped() || !movespline->Finalized()))
13389 return;
13390
13391 GetMotionMaster()->MoveFace(ori, movementId);
13392}
13393
13394void Unit::SetFacingToObject(WorldObject const* object, bool force /*= true*/, uint32 movementId /*= EVENT_FACE*/)
13395{
13396 // do not face when already moving
13397 if (!force && (!IsStopped() || !movespline->Finalized()))
13398 return;
13399
13400 GetMotionMaster()->MoveFace(object, movementId);
13401}
13402
13403void Unit::SetFacingToPoint(Position const& point, bool force)
13404{
13405 // do not face when already moving
13406 if (!force && (!IsStopped() || !movespline->Finalized()))
13407 return;
13408
13410 Movement::MoveSplineInit init(this);
13411 init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false);
13412 if (GetTransport())
13413 init.DisableTransportPathTransformations(); // It makes no sense to target global orientation
13414 init.SetFacing(point.GetPositionX(), point.GetPositionY(), point.GetPositionZ());
13415
13416 //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_PRIORITY_HIGHEST);
13418 if (Creature* creature = ToCreature())
13419 creature->AI()->MovementInform(EFFECT_MOTION_TYPE, EVENT_FACE);
13420}
13421
13422bool Unit::SetWalk(bool enable)
13423{
13424 if (enable == IsWalking())
13425 return false;
13426
13427 if (enable)
13429 else
13431
13433
13434 WorldPackets::Movement::MoveSplineSetFlag packet(walkModeTable[enable]);
13435 packet.MoverGUID = GetGUID();
13436 SendMessageToSet(packet.Write(), true);
13437 return true;
13438}
13439
13440bool Unit::SetDisableGravity(bool disable, bool updateAnimTier /*= true*/, bool updatePlayHoverAnim /*= true*/)
13441{
13442 if (disable == IsGravityDisabled())
13443 return false;
13444
13445 if (disable)
13446 {
13449 }
13450 else
13452
13453 static OpcodeServer const gravityOpcodeTable[2][2] =
13454 {
13457 };
13458
13459 if (Player* playerMover = GetPlayerMovingMe())
13460 {
13461 WorldPackets::Movement::MoveSetFlag packet(gravityOpcodeTable[disable][1]);
13462 packet.MoverGUID = GetGUID();
13464 playerMover->SendDirectMessage(packet.Write());
13465
13467 moveUpdate.Status = &m_movementInfo;
13468 SendMessageToSet(moveUpdate.Write(), playerMover);
13469 }
13470 else
13471 {
13472 WorldPackets::Movement::MoveSplineSetFlag packet(gravityOpcodeTable[disable][0]);
13473 packet.MoverGUID = GetGUID();
13474 SendMessageToSet(packet.Write(), true);
13475 }
13476
13477 if (updatePlayHoverAnim && !GetVehicle())
13478 {
13479 if (IsAlive())
13480 {
13481 if (IsGravityDisabled() || IsHovering())
13482 SetPlayHoverAnim(true);
13483 else
13484 SetPlayHoverAnim(false);
13485 }
13486 else if (IsPlayer()) // To update player who dies while flying/hovering
13487 SetPlayHoverAnim(false, false);
13488 }
13489
13490 if (IsCreature() && updateAnimTier && !HasUnitState(UNIT_STATE_ROOT))
13491 {
13492 if (IsGravityDisabled())
13494 else if (IsHovering())
13496 else
13498 }
13499
13500 return true;
13501}
13502
13503bool Unit::SetFall(bool enable)
13504{
13506 return false;
13507
13508 if (enable)
13509 {
13512 }
13513 else
13515
13516 return true;
13517}
13518
13519bool Unit::SetSwim(bool enable)
13520{
13522 return false;
13523
13524 if (enable)
13526 else
13528
13529 static OpcodeServer const swimOpcodeTable[2] = { SMSG_MOVE_SPLINE_STOP_SWIM, SMSG_MOVE_SPLINE_START_SWIM};
13530
13531 WorldPackets::Movement::MoveSplineSetFlag packet(swimOpcodeTable[enable]);
13532 packet.MoverGUID = GetGUID();
13533 SendMessageToSet(packet.Write(), true);
13534
13535 return true;
13536}
13537
13538bool Unit::SetCanFly(bool enable)
13539{
13541 return false;
13542
13543 if (enable)
13544 {
13547 }
13548 else
13550
13551 static OpcodeServer const flyOpcodeTable[2][2] =
13552 {
13555 };
13556
13557 if (!enable && GetTypeId() == TYPEID_PLAYER)
13559
13560 if (Player* playerMover = GetPlayerMovingMe())
13561 {
13562 WorldPackets::Movement::MoveSetFlag packet(flyOpcodeTable[enable][1]);
13563 packet.MoverGUID = GetGUID();
13565 playerMover->SendDirectMessage(packet.Write());
13566
13568 moveUpdate.Status = &m_movementInfo;
13569 SendMessageToSet(moveUpdate.Write(), playerMover);
13570 }
13571 else
13572 {
13573 WorldPackets::Movement::MoveSplineSetFlag packet(flyOpcodeTable[enable][0]);
13574 packet.MoverGUID = GetGUID();
13575 SendMessageToSet(packet.Write(), true);
13576 }
13577
13578 return true;
13579}
13580
13581bool Unit::SetWaterWalking(bool enable)
13582{
13584 return false;
13585
13586 if (enable)
13588 else
13590
13591 static OpcodeServer const waterWalkingOpcodeTable[2][2] =
13592 {
13595 };
13596
13597 if (Player* playerMover = GetPlayerMovingMe())
13598 {
13599 WorldPackets::Movement::MoveSetFlag packet(waterWalkingOpcodeTable[enable][1]);
13600 packet.MoverGUID = GetGUID();
13602 playerMover->SendDirectMessage(packet.Write());
13603
13605 moveUpdate.Status = &m_movementInfo;
13606 SendMessageToSet(moveUpdate.Write(), playerMover);
13607 }
13608 else
13609 {
13610 WorldPackets::Movement::MoveSplineSetFlag packet(waterWalkingOpcodeTable[enable][0]);
13611 packet.MoverGUID = GetGUID();
13612 SendMessageToSet(packet.Write(), true);
13613 }
13614
13615 return true;
13616}
13617
13618bool Unit::SetFeatherFall(bool enable)
13619{
13620 // Temporarily disabled for short lived auras that unapply before client had time to ACK applying
13621 //if (enable == HasUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW))
13622 // return false;
13623
13624 if (enable)
13626 else
13628
13629 static OpcodeServer const featherFallOpcodeTable[2][2] =
13630 {
13633 };
13634
13635 if (Player* playerMover = GetPlayerMovingMe())
13636 {
13637 WorldPackets::Movement::MoveSetFlag packet(featherFallOpcodeTable[enable][1]);
13638 packet.MoverGUID = GetGUID();
13640 playerMover->SendDirectMessage(packet.Write());
13641
13643 moveUpdate.Status = &m_movementInfo;
13644 SendMessageToSet(moveUpdate.Write(), playerMover);
13645 }
13646 else
13647 {
13648 WorldPackets::Movement::MoveSplineSetFlag packet(featherFallOpcodeTable[enable][0]);
13649 packet.MoverGUID = GetGUID();
13650 SendMessageToSet(packet.Write(), true);
13651 }
13652
13653 return true;
13654}
13655
13656bool Unit::SetHover(bool enable, bool updateAnimTier /*= true*/)
13657{
13659 return false;
13660
13661 float hoverHeight = m_unitData->HoverHeight;
13662
13663 if (enable)
13664 {
13667 if (hoverHeight && GetPositionZ() - GetFloorZ() < hoverHeight)
13668 UpdateHeight(std::max(GetFloorZ() + hoverHeight, GetPositionZ()));
13669 }
13670 else
13671 {
13674 if (hoverHeight && (!isDying() || GetTypeId() != TYPEID_UNIT))
13675 {
13676 float newZ = std::max<float>(GetFloorZ(), GetPositionZ() - hoverHeight);
13678 UpdateHeight(newZ);
13679 }
13680 }
13681
13682 static OpcodeServer const hoverOpcodeTable[2][2] =
13683 {
13686 };
13687
13688 if (Player* playerMover = GetPlayerMovingMe())
13689 {
13690 WorldPackets::Movement::MoveSetFlag packet(hoverOpcodeTable[enable][1]);
13691 packet.MoverGUID = GetGUID();
13693 playerMover->SendDirectMessage(packet.Write());
13694
13696 moveUpdate.Status = &m_movementInfo;
13697 SendMessageToSet(moveUpdate.Write(), playerMover);
13698 }
13699 else
13700 {
13701 WorldPackets::Movement::MoveSplineSetFlag packet(hoverOpcodeTable[enable][0]);
13702 packet.MoverGUID = GetGUID();
13703 SendMessageToSet(packet.Write(), true);
13704 }
13705
13706 if (IsAlive())
13707 {
13708 if (IsGravityDisabled() || IsHovering())
13709 SetPlayHoverAnim(true);
13710 else
13711 SetPlayHoverAnim(false);
13712 }
13713 else if (IsPlayer()) // To update player who dies while flying/hovering
13714 SetPlayHoverAnim(false, false);
13715
13716 if (IsCreature() && updateAnimTier && !HasUnitState(UNIT_STATE_ROOT))
13717 {
13718 if (IsGravityDisabled())
13720 else if (IsHovering())
13722 else
13724 }
13725
13726 return true;
13727}
13728
13729bool Unit::SetCollision(bool disable)
13730{
13732 return false;
13733
13734 if (disable)
13736 else
13738
13739 static OpcodeServer const collisionOpcodeTable[2][2] =
13740 {
13743 };
13744
13745 if (Player* playerMover = GetPlayerMovingMe())
13746 {
13747 WorldPackets::Movement::MoveSetFlag packet(collisionOpcodeTable[disable][1]);
13748 packet.MoverGUID = GetGUID();
13750 playerMover->SendDirectMessage(packet.Write());
13751
13753 moveUpdate.Status = &m_movementInfo;
13754 SendMessageToSet(moveUpdate.Write(), playerMover);
13755 }
13756 else
13757 {
13758 WorldPackets::Movement::MoveSplineSetFlag packet(collisionOpcodeTable[disable][0]);
13759 packet.MoverGUID = GetGUID();
13760 SendMessageToSet(packet.Write(), true);
13761 }
13762
13763 return true;
13764}
13765
13767{
13769 return false;
13770
13771 if (disable)
13773 else
13775
13776 static OpcodeServer const disableStrafingOpcodeTable[2] =
13777 {
13780 };
13781
13782 if (Player* playerMover = GetPlayerMovingMe())
13783 {
13784 WorldPackets::Movement::MoveSetFlag packet(disableStrafingOpcodeTable[disable]);
13785 packet.MoverGUID = GetGUID();
13787 playerMover->SendDirectMessage(packet.Write());
13788
13790 moveUpdate.Status = &m_movementInfo;
13791 SendMessageToSet(moveUpdate.Write(), playerMover);
13792 }
13793
13794 return true;
13795}
13796
13798{
13800 return false;
13801
13802 if (disable)
13804 else
13806
13807 static OpcodeServer const disableJumpingOpcodeTable[2] =
13808 {
13811 };
13812
13813 if (Player* playerMover = GetPlayerMovingMe())
13814 {
13815 WorldPackets::Movement::MoveSetFlag packet(disableJumpingOpcodeTable[disable]);
13816 packet.MoverGUID = GetGUID();
13818 playerMover->SendDirectMessage(packet.Write());
13819
13821 moveUpdate.Status = &m_movementInfo;
13822 SendMessageToSet(moveUpdate.Write(), playerMover);
13823 }
13824
13825 return true;
13826}
13827
13829{
13831 return false;
13832
13833 if (enable)
13835 else
13837
13838 static constexpr OpcodeServer fullSpeedTurningOpcodeTable[2] =
13839 {
13842 };
13843
13844 if (Player* playerMover = GetPlayerMovingMe())
13845 {
13846 WorldPackets::Movement::MoveSetFlag packet(fullSpeedTurningOpcodeTable[enable]);
13847 packet.MoverGUID = GetGUID();
13849 playerMover->SendDirectMessage(packet.Write());
13850
13852 moveUpdate.Status = &m_movementInfo;
13853 SendMessageToSet(moveUpdate.Write(), playerMover);
13854 }
13855
13856 return true;
13857}
13858
13860{
13862 return false;
13863
13864 if (enable)
13866 else
13868
13869 static constexpr OpcodeServer fullSpeedPitchingOpcodeTable[2] =
13870 {
13873 };
13874
13875 if (Player* playerMover = GetPlayerMovingMe())
13876 {
13877 WorldPackets::Movement::MoveSetFlag packet(fullSpeedPitchingOpcodeTable[enable]);
13878 packet.MoverGUID = GetGUID();
13880 playerMover->SendDirectMessage(packet.Write());
13881
13883 moveUpdate.Status = &m_movementInfo;
13884 SendMessageToSet(moveUpdate.Write(), playerMover);
13885 }
13886
13887 return true;
13888}
13889
13891{
13893 return false;
13894
13895 if (enable)
13897 else
13899
13900 static constexpr OpcodeServer alwaysAllowPitchingOpcodeTable[2] =
13901 {
13904 };
13905
13906 if (Player* playerMover = GetPlayerMovingMe())
13907 {
13908 WorldPackets::Movement::MoveSetFlag packet(alwaysAllowPitchingOpcodeTable[enable]);
13909 packet.MoverGUID = GetGUID();
13911 playerMover->SendDirectMessage(packet.Write());
13912
13914 moveUpdate.Status = &m_movementInfo;
13915 SendMessageToSet(moveUpdate.Write(), playerMover);
13916 }
13917
13918 return true;
13919}
13920
13922{
13923 if (GetTypeId() != TYPEID_PLAYER)
13924 return false;
13925
13927 return false;
13928
13929 if (enable)
13931 else
13933
13934 static OpcodeServer const swimToFlyTransOpcodeTable[2] =
13935 {
13938 };
13939
13940 if (Player* playerMover = GetPlayerMovingMe())
13941 {
13942 WorldPackets::Movement::MoveSetFlag packet(swimToFlyTransOpcodeTable[enable]);
13943 packet.MoverGUID = GetGUID();
13945 playerMover->SendDirectMessage(packet.Write());
13946
13948 moveUpdate.Status = &m_movementInfo;
13949 SendMessageToSet(moveUpdate.Write(), playerMover);
13950 }
13951
13952 return true;
13953}
13954
13956{
13957 // Temporarily disabled for short lived auras that unapply before client had time to ACK applying
13958 //if (enable == HasUnitMovementFlag(MOVEMENTFLAG_CAN_TURN_WHILE_FALLING))
13959 // return false;
13960
13961 if (enable)
13963 else
13965
13966 static OpcodeServer const canTurnWhileFallingOpcodeTable[2] =
13967 {
13970 };
13971
13972 if (Player* playerMover = GetPlayerMovingMe())
13973 {
13974 WorldPackets::Movement::MoveSetFlag packet(canTurnWhileFallingOpcodeTable[enable]);
13975 packet.MoverGUID = GetGUID();
13977 playerMover->SendDirectMessage(packet.Write());
13978
13980 moveUpdate.Status = &m_movementInfo;
13981 SendMessageToSet(moveUpdate.Write(), playerMover);
13982 }
13983
13984 return true;
13985}
13986
13987bool Unit::SetCanDoubleJump(bool enable)
13988{
13990 return false;
13991
13992 if (enable)
13994 else
13996
13997 static OpcodeServer const doubleJumpOpcodeTable[2] =
13998 {
14001 };
14002
14003 if (Player* playerMover = GetPlayerMovingMe())
14004 {
14005 WorldPackets::Movement::MoveSetFlag packet(doubleJumpOpcodeTable[enable]);
14006 packet.MoverGUID = GetGUID();
14008 playerMover->SendDirectMessage(packet.Write());
14009
14011 moveUpdate.Status = &m_movementInfo;
14012 SendMessageToSet(moveUpdate.Write(), playerMover);
14013 }
14014
14015 return true;
14016}
14017
14018bool Unit::SetDisableInertia(bool disable)
14019{
14021 return false;
14022
14023 if (disable)
14025 else
14027
14028 static OpcodeServer const disableInertiaOpcodeTable[2] =
14029 {
14032 };
14033
14034 if (Player* playerMover = GetPlayerMovingMe())
14035 {
14036 WorldPackets::Movement::MoveSetFlag packet(disableInertiaOpcodeTable[disable]);
14037 packet.MoverGUID = GetGUID();
14039 playerMover->SendDirectMessage(packet.Write());
14040
14042 moveUpdate.Status = &m_movementInfo;
14043 SendMessageToSet(moveUpdate.Write(), playerMover);
14044 }
14045
14046 return true;
14047}
14048
14049bool Unit::SetCanAdvFly(bool enable)
14050{
14052 return false;
14053
14054 if (enable)
14056 else
14058
14059 static OpcodeServer const advFlyOpcodeTable[2] =
14060 {
14063 };
14064
14065 if (Player* playerMover = GetPlayerMovingMe())
14066 {
14067 WorldPackets::Movement::MoveSetFlag packet(advFlyOpcodeTable[enable]);
14068 packet.MoverGUID = GetGUID();
14070 playerMover->SendDirectMessage(packet.Write());
14071
14073 moveUpdate.Status = &m_movementInfo;
14074 SendMessageToSet(moveUpdate.Write(), playerMover);
14075 }
14076
14077 return true;
14078}
14079
14080bool Unit::SetMoveCantSwim(bool cantSwim)
14081{
14083 return false;
14084
14085 if (cantSwim)
14087 else
14089
14090 static OpcodeServer const cantSwimOpcodeTable[2] =
14091 {
14094 };
14095
14096 if (Player* playerMover = GetPlayerMovingMe())
14097 {
14098 WorldPackets::Movement::MoveSetFlag packet(cantSwimOpcodeTable[cantSwim]);
14099 packet.MoverGUID = GetGUID();
14101 playerMover->SendDirectMessage(packet.Write());
14102
14104 moveUpdate.Status = &m_movementInfo;
14105 SendMessageToSet(moveUpdate.Write(), playerMover);
14106 }
14107
14108 return true;
14109}
14110
14112{
14113 if (Player* player = ToPlayer())
14114 {
14116 moveSetVehicleRec.MoverGUID = GetGUID();
14117 moveSetVehicleRec.SequenceIndex = m_movementCounter++;
14118 moveSetVehicleRec.VehicleRecID = vehicleId;
14119 player->SendDirectMessage(moveSetVehicleRec.Write());
14120 }
14121
14123 setVehicleRec.VehicleGUID = GetGUID();
14124 setVehicleRec.VehicleRecID = vehicleId;
14125 SendMessageToSet(setVehicleRec.Write(), true);
14126}
14127
14128void Unit::ApplyMovementForce(ObjectGuid id, Position origin, float magnitude, MovementForceType type, Position direction /*= {}*/, ObjectGuid transportGuid /*= ObjectGuid::Empty*/)
14129{
14130 if (!_movementForces)
14131 _movementForces = std::make_unique<MovementForces>();
14132
14133 MovementForce force;
14134 force.ID = id;
14135 force.Origin = origin;
14136 force.Direction = direction;
14137 if (transportGuid.IsMOTransport())
14138 force.TransportID = transportGuid.GetCounter();
14139
14140 force.Magnitude = magnitude;
14141 force.Type = type;
14142
14143 if (_movementForces->Add(force))
14144 {
14145 if (Player const* movingPlayer = GetPlayerMovingMe())
14146 {
14148 applyMovementForce.MoverGUID = GetGUID();
14149 applyMovementForce.SequenceIndex = m_movementCounter++;
14150 applyMovementForce.Force = &force;
14151 movingPlayer->SendDirectMessage(applyMovementForce.Write());
14152 }
14153 else
14154 {
14156 updateApplyMovementForce.Status = &m_movementInfo;
14157 updateApplyMovementForce.Force = &force;
14158 SendMessageToSet(updateApplyMovementForce.Write(), true);
14159 }
14160 }
14161}
14162
14164{
14165 if (!_movementForces)
14166 return;
14167
14168 if (_movementForces->Remove(id))
14169 {
14170 if (Player const* movingPlayer = GetPlayerMovingMe())
14171 {
14173 moveRemoveMovementForce.MoverGUID = GetGUID();
14174 moveRemoveMovementForce.SequenceIndex = m_movementCounter++;
14175 moveRemoveMovementForce.ID = id;
14176 movingPlayer->SendDirectMessage(moveRemoveMovementForce.Write());
14177 }
14178 else
14179 {
14181 updateRemoveMovementForce.Status = &m_movementInfo;
14182 updateRemoveMovementForce.TriggerGUID = id;
14183 SendMessageToSet(updateRemoveMovementForce.Write(), true);
14184 }
14185 }
14186
14187 if (_movementForces->IsEmpty())
14188 _movementForces.reset();
14189}
14190
14192{
14194 return false;
14195
14196 if (ignore)
14198 else
14200
14201 static OpcodeServer const ignoreMovementForcesOpcodeTable[2] =
14202 {
14205 };
14206
14207 if (Player const* movingPlayer = GetPlayerMovingMe())
14208 {
14209 WorldPackets::Movement::MoveSetFlag packet(ignoreMovementForcesOpcodeTable[ignore]);
14210 packet.MoverGUID = GetGUID();
14212 movingPlayer->SendDirectMessage(packet.Write());
14213
14215 moveUpdate.Status = &m_movementInfo;
14216 SendMessageToSet(moveUpdate.Write(), movingPlayer);
14217 }
14218
14219 return true;
14220}
14221
14223{
14225
14226 if (Player* movingPlayer = GetPlayerMovingMe())
14227 {
14229 setModMovementForceMagnitude.MoverGUID = GetGUID();
14230 setModMovementForceMagnitude.SequenceIndex = m_movementCounter++;
14231 setModMovementForceMagnitude.Speed = modMagnitude;
14232 movingPlayer->SendDirectMessage(setModMovementForceMagnitude.Write());
14233 ++movingPlayer->m_movementForceModMagnitudeChanges;
14234 }
14235 else
14236 {
14238 updateModMovementForceMagnitude.Status = &m_movementInfo;
14239 updateModMovementForceMagnitude.Speed = modMagnitude;
14240 SendMessageToSet(updateModMovementForceMagnitude.Write(), true);
14241 }
14242
14243 if (modMagnitude != 1.0f && !_movementForces)
14244 _movementForces = std::make_unique<MovementForces>();
14245
14246 if (_movementForces)
14247 {
14248 _movementForces->SetModMagnitude(modMagnitude);
14249 if (_movementForces->IsEmpty())
14250 _movementForces.reset();
14251 }
14252}
14253
14255{
14256 MovementInfo::Inertia& inertia = m_movementInfo.inertia.emplace();
14257 inertia.id = id;
14258 inertia.lifetime = duration.count();
14259
14260 if (Player const* movingPlayer = GetPlayerMovingMe())
14261 {
14263 applyInertia.MoverGUID = GetGUID();
14264 applyInertia.SequenceIndex = m_movementCounter++;
14265 applyInertia.InertiaID = id;
14266 applyInertia.LifetimeMs = duration;
14267 movingPlayer->SendDirectMessage(applyInertia.Write());
14268 }
14269 else
14270 {
14272 updateApplyInertia.Status = &m_movementInfo;
14273 updateApplyInertia.InertiaID = id;
14274 updateApplyInertia.LifetimeMs = duration;
14275 SendMessageToSet(updateApplyInertia.Write(), true);
14276 }
14277}
14278
14280{
14281 if (!m_movementInfo.inertia || m_movementInfo.inertia->id != id)
14282 return;
14283
14284 m_movementInfo.inertia.reset();
14285
14286 if (Player const* movingPlayer = GetPlayerMovingMe())
14287 {
14289 moveRemoveInertia.MoverGUID = GetGUID();
14290 moveRemoveInertia.SequenceIndex = m_movementCounter++;
14291 moveRemoveInertia.InertiaID = id;
14292 movingPlayer->SendDirectMessage(moveRemoveInertia.Write());
14293 }
14294 else
14295 {
14297 updateRemoveInertia.Status = &m_movementInfo;
14298 updateRemoveInertia.InertiaID = id;
14299 SendMessageToSet(updateRemoveInertia.Write(), true);
14300 }
14301}
14302
14303void Unit::SetGravityModifier(float gravityModifier)
14304{
14305 if (Player const* movingPlayer = GetPlayerMovingMe())
14306 {
14308 setGravityModifier.MoverGUID = GetGUID();
14309 setGravityModifier.SequenceIndex = m_movementCounter++;
14310 setGravityModifier.GravityModifier = gravityModifier;
14311 movingPlayer->SendDirectMessage(setGravityModifier.Write());
14312 }
14313 else
14314 {
14316 updateSetGravityModifier.Status = &m_movementInfo;
14317 updateSetGravityModifier.GravityModifier = gravityModifier;
14318 SendMessageToSet(updateSetGravityModifier.Write(), true);
14319 }
14320}
14321
14322void Unit::SetPlayHoverAnim(bool enable, bool sendUpdate /*= true*/)
14323{
14324 if (IsPlayingHoverAnim() == enable)
14325 return;
14326
14327 m_updateFlag.PlayHoverAnim = enable;
14328
14329 if (!sendUpdate)
14330 return;
14331
14333 data.UnitGUID = GetGUID();
14334 data.PlayHoverAnim = enable;
14335
14336 SendMessageToSet(data.Write(), true);
14337}
14338
14340{
14341 float hoverHeight = DEFAULT_PLAYER_HOVER_HEIGHT;
14342 float displayScale = DEFAULT_PLAYER_DISPLAY_SCALE;
14343
14344 uint32 displayId = IsMounted() ? GetMountDisplayId() : GetDisplayId();
14345
14346 // Get DisplayScale for creatures
14347 if (IsCreature())
14348 if (CreatureModel const* model = ToCreature()->GetCreatureTemplate()->GetModelWithDisplayId(displayId))
14349 displayScale = model->DisplayScale;
14350
14351 if (CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(displayId))
14352 if (CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(displayInfo->ModelID))
14353 hoverHeight = modelData->HoverHeight * modelData->ModelScale * displayInfo->CreatureModelScale * displayScale;
14354
14355 SetHoverHeight(hoverHeight ? hoverHeight : DEFAULT_PLAYER_HOVER_HEIGHT);
14356}
14357
14359{
14360 return movespline->Initialized() && !movespline->Finalized();
14361}
14362
14364{
14366 if (target == this || GetOwnerGUID() == target->GetGUID())
14368
14372
14373 return flags;
14374}
14375
14376void Unit::DestroyForPlayer(Player const* target) const
14377{
14378 if (Battleground* bg = target->GetBattleground())
14379 {
14380 if (bg->isArena())
14381 {
14383 destroyArenaUnit.Guid = GetGUID();
14384 target->GetSession()->SendPacket(destroyArenaUnit.Write());
14385 }
14386 }
14387
14389}
14390
14396
14397SpellEffectValue Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const
14398{
14399 SpellEffectValue val = 0;
14400 SpellSpellGroupMapBounds spellGroup = sSpellMgr->GetSpellSpellGroupMapBounds(aurEff->GetSpellInfo()->GetFirstRankSpell()->Id);
14401 for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second ; ++itr)
14402 {
14403 if (sSpellMgr->GetSpellGroupStackRule(itr->second) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
14404 {
14405 AuraEffectList const& auraEffList = GetAuraEffectsByType(auraType);
14406 for (AuraEffectList::const_iterator auraItr = auraEffList.begin(); auraItr != auraEffList.end(); ++auraItr)
14407 {
14408 if (aurEff != (*auraItr) && (!checkMiscValue || (*auraItr)->GetMiscValue() == miscValue) &&
14409 sSpellMgr->IsSpellMemberOfSpellGroup((*auraItr)->GetSpellInfo()->Id, itr->second))
14410 {
14411 // absolute value only
14412 if (abs(val) < abs((*auraItr)->GetAmount()))
14413 val = (*auraItr)->GetAmount();
14414 }
14415 }
14416 }
14417 }
14418 return val;
14419}
14420
14421bool Unit::IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications /*= false*/)
14422{
14423 for (AuraEffect const* aurEff : aura->GetAuraEffects())
14424 if (!IsHighestExclusiveAuraEffect(aura->GetSpellInfo(), aurEff->GetAuraType(), aurEff->GetAmount(), aura->GetEffectMask(), removeOtherAuraApplications))
14425 return false;
14426
14427 return true;
14428}
14429
14430bool Unit::IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType auraType, SpellEffectValue effectAmount, uint32 auraEffectMask, bool removeOtherAuraApplications /*= false*/)
14431{
14432 AuraEffectList const& auras = GetAuraEffectsByType(auraType);
14433 for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();)
14434 {
14435 AuraEffect const* existingAurEff = (*itr);
14436 ++itr;
14437
14438 if (sSpellMgr->CheckSpellGroupStackRules(spellInfo, existingAurEff->GetSpellInfo()) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST)
14439 {
14440 SpellEffectValue diff = abs(effectAmount) - abs(existingAurEff->GetAmount());
14441 if (!diff)
14442 {
14443 // treat the aura with more effects as stronger
14444 diff = std::popcount(auraEffectMask) - std::popcount(existingAurEff->GetBase()->GetEffectMask());
14445 }
14446
14447 if (diff > 0)
14448 {
14449 Aura const* base = existingAurEff->GetBase();
14450 // no removing of area auras from the original owner, as that completely cancels them
14451 if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this))
14452 {
14453 if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID()))
14454 {
14455 bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType);
14456 uint32 removedAuras = m_removedAurasCount;
14457 RemoveAura(aurApp);
14458 if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1)
14459 itr = auras.begin();
14460 }
14461 }
14462 }
14463 else if (diff < 0)
14464 return false;
14465 }
14466 }
14467
14468 return true;
14469}
14470
14471void Unit::Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const* target)
14472{
14473 Trinity::CustomChatTextBuilder builder(this, msgType, text, language, target);
14476 Cell::VisitWorldObjects(this, worker, textRange);
14477}
14478
14479void Unit::Say(std::string_view text, Language language, WorldObject const* target /*= nullptr*/)
14480{
14481 Talk(text, CHAT_MSG_MONSTER_SAY, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
14482}
14483
14484void Unit::Yell(std::string_view text, Language language, WorldObject const* target /*= nullptr*/)
14485{
14486 Talk(text, CHAT_MSG_MONSTER_YELL, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target);
14487}
14488
14489void Unit::TextEmote(std::string_view text, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/)
14490{
14492}
14493
14494void Unit::Whisper(std::string_view text, Language language, Player* target, bool isBossWhisper /*= false*/)
14495{
14496 if (!target)
14497 return;
14498
14501 packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, language, this, target, text, 0, "", locale);
14502 target->SendDirectMessage(packet.Write());
14503}
14504
14506{
14507 if (slot >= MAX_EQUIPMENT_ITEMS)
14508 return 0;
14509
14510 return m_unitData->VirtualItems[slot].ItemID;
14511}
14512
14514{
14515 if (slot >= MAX_EQUIPMENT_ITEMS)
14516 return 0;
14517
14518 return m_unitData->VirtualItems[slot].ItemAppearanceModID;
14519}
14520
14521void Unit::SetVirtualItem(uint32 slot, uint32 itemId, uint16 appearanceModId /*= 0*/, uint16 itemVisual /*= 0*/)
14522{
14523 if (slot >= MAX_EQUIPMENT_ITEMS)
14524 return;
14525
14526 auto virtualItemField = m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::VirtualItems, slot);
14527 SetUpdateFieldValue(virtualItemField.ModifyValue(&UF::VisibleItem::ItemID), itemId);
14528 SetUpdateFieldValue(virtualItemField.ModifyValue(&UF::VisibleItem::ItemAppearanceModID), appearanceModId);
14529 SetUpdateFieldValue(virtualItemField.ModifyValue(&UF::VisibleItem::ItemVisual), itemVisual);
14530}
14531
14532void Unit::Talk(uint32 textId, ChatMsg msgType, float textRange, WorldObject const* target)
14533{
14534 if (!sBroadcastTextStore.LookupEntry(textId))
14535 {
14536 TC_LOG_ERROR("entities.unit", "WorldObject::MonsterText: `broadcast_text` (ID: {}) was not found", textId);
14537 return;
14538 }
14539
14540 Trinity::BroadcastTextBuilder builder(this, msgType, textId, GetGender(), target);
14543 Cell::VisitWorldObjects(this, worker, textRange);
14544}
14545
14546void Unit::Say(uint32 textId, WorldObject const* target /*= nullptr*/)
14547{
14548 Talk(textId, CHAT_MSG_MONSTER_SAY, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
14549}
14550
14551void Unit::Yell(uint32 textId, WorldObject const* target /*= nullptr*/)
14552{
14553 Talk(textId, CHAT_MSG_MONSTER_YELL, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target);
14554}
14555
14556void Unit::TextEmote(uint32 textId, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/)
14557{
14558 Talk(textId, isBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), target);
14559}
14560
14561void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/)
14562{
14563 if (!target)
14564 return;
14565
14566 BroadcastTextEntry const* bct = sBroadcastTextStore.LookupEntry(textId);
14567 if (!bct)
14568 {
14569 TC_LOG_ERROR("entities.unit", "WorldObject::Whisper: `broadcast_text` was not {} found", textId);
14570 return;
14571 }
14572
14575 packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, DB2Manager::GetBroadcastTextValue(bct, locale, GetGender()), 0, "", locale);
14576 target->SendDirectMessage(packet.Write());
14577}
14578
14579void Unit::ClearBossEmotes(Optional<uint32> zoneId, Player const* target) const
14580{
14582 clearBossEmotes.Write();
14583
14584 if (target)
14585 {
14586 target->SendDirectMessage(clearBossEmotes.GetRawPacket());
14587 return;
14588 }
14589
14590 for (MapReference const& ref : GetMap()->GetPlayers())
14591 if (!zoneId || DB2Manager::IsInArea(ref.GetSource()->GetAreaId(), *zoneId))
14592 ref.GetSource()->SendDirectMessage(clearBossEmotes.GetRawPacket());
14593}
14594
14596{
14597 for (uint32& slot : VisitedSpells)
14598 {
14599 if (slot == spellId)
14600 return false; // already exists
14601
14602 if (!slot)
14603 {
14604 slot = spellId;
14605 return true;
14606 }
14607 }
14608
14609 return false; // no free slots left
14610}
14611
14612SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo, TriggerCastFlags& triggerFlag, GetCastSpellInfoContext* context) const
14613{
14614 auto findMatchingAuraEffectIn = [this, spellInfo, &triggerFlag, context](AuraType type) -> SpellInfo const*
14615 {
14616 for (AuraEffect const* auraEffect : GetAuraEffectsByType(type))
14617 {
14618 bool matches = auraEffect->GetMiscValue() ? uint32(auraEffect->GetMiscValue()) == spellInfo->Id : auraEffect->IsAffectingSpell(spellInfo);
14619 if (matches && context->AddSpell(auraEffect->GetAmountAsInt()))
14620 {
14621 if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(auraEffect->GetAmountAsInt(), GetMap()->GetDifficultyID()))
14622 {
14623 if (auraEffect->GetSpellInfo()->HasAttribute(SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST))
14624 triggerFlag |= TRIGGERED_IGNORE_POWER_COST;
14625 else
14626 triggerFlag &= ~TRIGGERED_IGNORE_POWER_COST;
14627
14628 if (auraEffect->GetSpellInfo()->HasAttribute(SPELL_ATTR11_IGNORE_SPELLCAST_OVERRIDE_SHAPESHIFT_REQUIREMENTS))
14629 triggerFlag |= TRIGGERED_IGNORE_SHAPESHIFT;
14630 else
14631 triggerFlag &= ~TRIGGERED_IGNORE_SHAPESHIFT;
14632
14633 return newInfo;
14634 }
14635 }
14636 }
14637
14638 return nullptr;
14639 };
14640
14641 if (SpellInfo const* newInfo = findMatchingAuraEffectIn(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS))
14642 {
14643 triggerFlag &= ~TRIGGERED_IGNORE_CAST_TIME;
14644 return GetCastSpellInfo(newInfo, triggerFlag, context);
14645 }
14646
14647 if (SpellInfo const* newInfo = findMatchingAuraEffectIn(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_TRIGGERED))
14648 {
14649 triggerFlag |= TRIGGERED_IGNORE_CAST_TIME;
14650 return GetCastSpellInfo(newInfo, triggerFlag, context);
14651 }
14652
14653 return spellInfo;
14654}
14655
14657{
14659 for (AuraEffect const* effect : visualOverrides)
14660 {
14661 if (uint32(effect->GetMiscValue()) == spellInfo->Id)
14662 {
14663 if (SpellInfo const* visualSpell = sSpellMgr->GetSpellInfo(effect->GetMiscValueB(), GetMap()->GetDifficultyID()))
14664 {
14665 spellInfo = visualSpell;
14666 break;
14667 }
14668 }
14669 }
14670
14672}
14673
14675{
14676 return left->GetSlot() < right->GetSlot();
14677}
14678
14679// Returns collisionheight of the unit. If it is 0, it returns DEFAULT_COLLISION_HEIGHT.
14681{
14682 float scaleMod = GetObjectScale(); // 99% sure about this
14683
14684 if (IsMounted())
14685 {
14686 if (CreatureDisplayInfoEntry const* mountDisplayInfo = sCreatureDisplayInfoStore.LookupEntry(GetMountDisplayId()))
14687 {
14688 if (CreatureModelDataEntry const* mountModelData = sCreatureModelDataStore.LookupEntry(mountDisplayInfo->ModelID))
14689 {
14690 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId());
14691 CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelID);
14692 float const collisionHeight = scaleMod * ((mountModelData->MountHeight * mountDisplayInfo->CreatureModelScale) + (modelData->CollisionHeight * modelData->ModelScale * displayInfo->CreatureModelScale * 0.5f));
14693 return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
14694 }
14695 }
14696 }
14697
14699 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId());
14700 CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelID);
14701
14702 float const collisionHeight = scaleMod * modelData->CollisionHeight * modelData->ModelScale * displayInfo->CreatureModelScale;
14703 return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
14704}
14705
14706void Unit::AddWorldEffect(int32 worldEffectId)
14707{
14709}
14710
14712{
14713 int32 index = m_unitData->WorldEffects.FindIndex(worldEffectId);
14714 if (index >= 0)
14716}
14717
14722
14724{
14725 if (m_vignette)
14726 {
14727 if (m_vignette->Data->ID == vignetteId)
14728 return;
14729
14731 m_vignette = nullptr;
14732 }
14733
14734 if (VignetteEntry const* vignette = sVignetteStore.LookupEntry(vignetteId))
14735 m_vignette = Vignettes::Create(vignette, this);
14736}
14737
14738std::string Unit::GetDebugInfo() const
14739{
14740 std::stringstream sstr;
14741 sstr << WorldObject::GetDebugInfo() << "\n"
14742 << std::boolalpha
14743 << "IsAIEnabled: " << IsAIEnabled() << " DeathState: " << std::to_string(getDeathState())
14744 << " UnitMovementFlags: " << Movement::MovementFlags_ToString(GetUnitMovementFlags())
14745 << " Class: " << std::to_string(GetClass()) << "\n"
14746 << "" << (movespline ? movespline->ToString() : "Movespline: <none>\n")
14747 << "GetCharmedGUID(): " << GetCharmedGUID().ToString() << "\n"
14748 << "GetCharmerGUID(): " << GetCharmerGUID().ToString() << "\n"
14749 << "" << (GetVehicleKit() ? GetVehicleKit()->GetDebugInfo() : "No vehicle kit") << "\n"
14750 << "m_Controlled size: " << m_Controlled.size();
14751
14752 size_t controlledCount = 0;
14753 for (Unit* controlled : m_Controlled)
14754 {
14755 ++controlledCount;
14756 sstr << "\n" << "m_Controlled " << controlledCount << " : " << controlled->GetGUID().ToString();
14757 }
14758
14759 return sstr.str();
14760}
14761
14763{
14764 for (std::size_t i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
14765 name[i] = uf.Name[i];
14766}
#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:579
AreaMountFlags
Definition DBCEnums.h:163
@ AllowUnderwaterSwimmingMounts
@ AllowSurfaceSwimmingMounts
#define MAX_EFFECT_MASK
Definition DBCEnums.h:2451
@ ArmorItemLevelDiminishing
@ UnitsUseDefaultPowerOnInit
@ DIFFICULTY_NONE
Definition DBCEnums.h:936
@ MOUNT_CAPABILITY_FLAG_FLYING
Definition DBCEnums.h:2118
@ MOUNT_CAPABIILTY_FLAG_IGNORE_RESTRICTIONS
Definition DBCEnums.h:2121
@ MOUNT_CAPABILITY_FLAG_UNDERWATER
Definition DBCEnums.h:2120
@ MOUNT_CAPABILITY_FLAG_GROUND
Definition DBCEnums.h:2117
@ MOUNT_CAPABILITY_FLAG_FLOAT
Definition DBCEnums.h:2119
#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:80
#define ABORT
Definition Errors.h:79
#define ASSERT_NODEBUGINFO
Definition Errors.h:73
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:74
#define ASSERT
Definition Errors.h:72
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:173
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:182
#define TC_LOG_FATAL(filterType__, message__,...)
Definition Log.h:185
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:1036
@ 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
@ DISTRACT_MOTION_TYPE
@ IDLE_MOTION_TYPE
@ FLEEING_MOTION_TYPE
@ CONFUSED_MOTION_TYPE
@ POINT_MOTION_TYPE
@ FOLLOW_MOTION_TYPE
@ EFFECT_MOTION_TYPE
@ MOVEMENTFLAG_CAN_TURN_WHILE_FALLING
@ MOVEMENTFLAG_CAN_SWIM_TO_FLY_TRANS
@ MOVEMENTFLAG_FORWARD
@ MOVEMENTFLAG_WATERWALKING
@ MOVEMENTFLAG_MASK_MOVING
@ MOVEMENTFLAG_FULL_SPEED_PITCHING
@ MOVEMENTFLAG_DISABLE_GRAVITY
@ MOVEMENTFLAG_FALLING_SLOW
@ MOVEMENTFLAG_CAN_FLY
@ MOVEMENTFLAG_FULL_SPEED_TURNING
@ MOVEMENTFLAG_NO_STRAFE
@ MOVEMENTFLAG_ROOT
@ MOVEMENTFLAG_CANNOT_SWIM
@ MOVEMENTFLAG_MASK_TURNING
@ MOVEMENTFLAG_FALLING
@ MOVEMENTFLAG_IGNORE_MOVEMENT_FORCES
@ MOVEMENTFLAG_MASK_MOVING_FLY
@ MOVEMENTFLAG_NO_JUMPING
@ MOVEMENTFLAG_FALLING_FAR
@ MOVEMENTFLAG_SWIMMING
@ MOVEMENTFLAG_HOVER
@ MOVEMENTFLAG_SPLINE_ELEVATION
@ MOVEMENTFLAG_CAN_ADV_FLY
@ MOVEMENTFLAG_CAN_DOUBLE_JUMP
@ MOVEMENTFLAG_WALKING
@ MOVEMENTFLAG_ALWAYS_ALLOW_PITCHING
@ MOVEMENTFLAG_DISABLE_COLLISION
@ MOVEMENTFLAG_DISABLE_INERTIA
@ MOVEMENTFLAG_ADV_FLYING
MovementForceType
#define DEFAULT_PLAYER_HOVER_HEIGHT
#define DEFAULT_PLAYER_DISPLAY_SCALE
#define NOMINAL_MELEE_RANGE
#define MIN_MELEE_REACH
@ NOTIFY_VISIBILITY_CHANGED
@ TYPEID_UNIT
Definition ObjectGuid.h:43
@ TYPEID_PLAYER
Definition ObjectGuid.h:44
#define sObjectMgr
Definition ObjectMgr.h:1873
float const DEFAULT_COLLISION_HEIGHT
Definition Object.h:78
OpcodeServer
Definition Opcodes.h:1105
@ SMSG_MOVE_SPLINE_SET_PITCH_RATE
Definition Opcodes.h:1967
@ SMSG_MOVE_SET_ADV_FLYING_LAUNCH_SPEED_COEFFICIENT
Definition Opcodes.h:1920
@ SMSG_MOVE_SPLINE_SET_SWIM_SPEED
Definition Opcodes.h:1972
@ SMSG_MOVE_SET_FLIGHT_SPEED
Definition Opcodes.h:1938
@ SMSG_MOVE_SPLINE_SET_FLYING
Definition Opcodes.h:1963
@ SMSG_MOVE_SET_FLIGHT_BACK_SPEED
Definition Opcodes.h:1937
@ SMSG_MOVE_SET_ADV_FLYING_SURFACE_FRICTION
Definition Opcodes.h:1926
@ SMSG_MOVE_DISABLE_COLLISION
Definition Opcodes.h:1890
@ SMSG_MOVE_UPDATE_PITCH_RATE
Definition Opcodes.h:2001
@ SMSG_MOVE_SPLINE_SET_WALK_SPEED
Definition Opcodes.h:1975
@ SMSG_MOVE_ENABLE_DOUBLE_JUMP
Definition Opcodes.h:1900
@ SMSG_MOVE_ROOT
Definition Opcodes.h:1913
@ SMSG_MOVE_SPLINE_SET_RUN_MODE
Definition Opcodes.h:1969
@ SMSG_MOVE_DISABLE_GRAVITY
Definition Opcodes.h:1894
@ SMSG_MOVE_UNSET_CANNOT_SWIM
Definition Opcodes.h:1985
@ SMSG_MOVE_SPLINE_SET_SWIM_BACK_SPEED
Definition Opcodes.h:1971
@ SMSG_MOVE_SPLINE_DISABLE_COLLISION
Definition Opcodes.h:1955
@ SMSG_MOVE_ENABLE_TRANSITION_BETWEEN_SWIM_AND_FLY
Definition Opcodes.h:1907
@ SMSG_MOVE_UNROOT
Definition Opcodes.h:1983
@ SMSG_MOVE_SPLINE_UNROOT
Definition Opcodes.h:1979
@ SMSG_MOVE_SET_RUN_BACK_SPEED
Definition Opcodes.h:1946
@ SMSG_MOVE_SPLINE_SET_HOVER
Definition Opcodes.h:1964
@ SMSG_MOVE_SPLINE_SET_WATER_WALK
Definition Opcodes.h:1976
@ SMSG_MOVE_ENABLE_FULL_SPEED_PITCHING
Definition Opcodes.h:1901
@ SMSG_MOVE_SPLINE_SET_NORMAL_FALL
Definition Opcodes.h:1966
@ SMSG_MOVE_ENABLE_INERTIA
Definition Opcodes.h:1904
@ SMSG_MOVE_SET_ADV_FLYING_PITCHING_RATE_DOWN
Definition Opcodes.h:1924
@ SMSG_MOVE_SPLINE_SET_TURN_RATE
Definition Opcodes.h:1973
@ SMSG_MOVE_SET_NORMAL_FALL
Definition Opcodes.h:1944
@ SMSG_MOVE_SET_ADV_FLYING_BANKING_RATE
Definition Opcodes.h:1917
@ SMSG_MOVE_SET_ADV_FLYING_LIFT_COEFFICIENT
Definition Opcodes.h:1921
@ SMSG_MOVE_SPLINE_UNSET_HOVER
Definition Opcodes.h:1981
@ SMSG_MOVE_UPDATE_FLIGHT_SPEED
Definition Opcodes.h:1998
@ SMSG_MOVE_SET_PITCH_RATE
Definition Opcodes.h:1945
@ SMSG_MOVE_SPLINE_SET_LAND_WALK
Definition Opcodes.h:1965
@ SMSG_MOVE_UPDATE_FLIGHT_BACK_SPEED
Definition Opcodes.h:1997
@ SMSG_MOVE_UPDATE_WALK_SPEED
Definition Opcodes.h:2011
@ SMSG_MOVE_SET_CAN_TURN_WHILE_FALLING
Definition Opcodes.h:1933
@ SMSG_MOVE_SPLINE_DISABLE_GRAVITY
Definition Opcodes.h:1956
@ SMSG_MOVE_ENABLE_COLLISION
Definition Opcodes.h:1899
@ SMSG_MOVE_SET_IGNORE_MOVEMENT_FORCES
Definition Opcodes.h:1941
@ SMSG_MOVE_DISABLE_STRAFING
Definition Opcodes.h:1897
@ SMSG_MOVE_DISABLE_FULL_SPEED_TURNING
Definition Opcodes.h:1893
@ SMSG_MOVE_UNSET_IGNORE_MOVEMENT_FORCES
Definition Opcodes.h:1991
@ SMSG_MOVE_UPDATE_SWIM_SPEED
Definition Opcodes.h:2008
@ SMSG_MOVE_ENABLE_GRAVITY
Definition Opcodes.h:1903
@ SMSG_MOVE_UPDATE_MOD_MOVEMENT_FORCE_MAGNITUDE
Definition Opcodes.h:2000
@ SMSG_MOVE_SET_ADV_FLYING_PITCHING_RATE_UP
Definition Opcodes.h:1925
@ SMSG_MOVE_SET_ADV_FLYING_OVER_MAX_DECELERATION
Definition Opcodes.h:1923
@ SMSG_MOVE_SET_ADV_FLYING_MAX_VEL
Definition Opcodes.h:1922
@ SMSG_MOVE_UNSET_HOVERING
Definition Opcodes.h:1990
@ SMSG_MOVE_UNSET_CAN_ADV_FLY
Definition Opcodes.h:1986
@ SMSG_MOVE_UPDATE_TURN_RATE
Definition Opcodes.h:2010
@ SMSG_MOVE_SPLINE_SET_RUN_BACK_SPEED
Definition Opcodes.h:1968
@ SMSG_MOVE_SET_TURN_RATE
Definition Opcodes.h:1950
@ SMSG_MOVE_SET_WATER_WALK
Definition Opcodes.h:1953
@ SMSG_MOVE_SPLINE_ROOT
Definition Opcodes.h:1959
@ SMSG_MOVE_UNSET_ALWAYS_ALLOW_PITCHING
Definition Opcodes.h:1984
@ SMSG_MOVE_SET_CANNOT_SWIM
Definition Opcodes.h:1929
@ SMSG_MOVE_SET_ALWAYS_ALLOW_PITCHING
Definition Opcodes.h:1928
@ SMSG_MOVE_SET_SWIM_SPEED
Definition Opcodes.h:1949
@ SMSG_MOVE_UPDATE_RUN_SPEED
Definition Opcodes.h:2005
@ SMSG_MOVE_SET_WALK_SPEED
Definition Opcodes.h:1952
@ SMSG_MOVE_SET_HOVERING
Definition Opcodes.h:1940
@ SMSG_MOVE_SET_ADV_FLYING_ADD_IMPULSE_MAX_SPEED
Definition Opcodes.h:1915
@ SMSG_MOVE_ENABLE_FULL_SPEED_TURNING
Definition Opcodes.h:1902
@ SMSG_MOVE_SET_MOD_MOVEMENT_FORCE_MAGNITUDE
Definition Opcodes.h:1943
@ SMSG_MOVE_SET_ADV_FLYING_GLIDE_START_MIN_HEIGHT
Definition Opcodes.h:1919
@ SMSG_MOVE_SPLINE_ENABLE_GRAVITY
Definition Opcodes.h:1958
@ SMSG_MOVE_SET_CAN_FLY
Definition Opcodes.h:1932
@ SMSG_MOVE_SPLINE_SET_RUN_SPEED
Definition Opcodes.h:1970
@ SMSG_MOVE_DISABLE_INERTIA
Definition Opcodes.h:1895
@ SMSG_MOVE_SET_CAN_ADV_FLY
Definition Opcodes.h:1930
@ SMSG_MOVE_SPLINE_SET_FLIGHT_BACK_SPEED
Definition Opcodes.h:1961
@ SMSG_MOVE_UPDATE_SWIM_BACK_SPEED
Definition Opcodes.h:2007
@ SMSG_MOVE_DISABLE_DOUBLE_JUMP
Definition Opcodes.h:1891
@ SMSG_MOVE_DISABLE_FULL_SPEED_PITCHING
Definition Opcodes.h:1892
@ SMSG_MOVE_SET_ADV_FLYING_TURN_VELOCITY_THRESHOLD
Definition Opcodes.h:1927
@ SMSG_MOVE_UNSET_CAN_FLY
Definition Opcodes.h:1988
@ SMSG_MOVE_SET_ADV_FLYING_DOUBLE_JUMP_VEL_MOD
Definition Opcodes.h:1918
@ SMSG_MOVE_SPLINE_UNSET_FLYING
Definition Opcodes.h:1980
@ SMSG_MOVE_SPLINE_SET_FLIGHT_SPEED
Definition Opcodes.h:1962
@ SMSG_MOVE_SPLINE_STOP_SWIM
Definition Opcodes.h:1978
@ SMSG_MOVE_SPLINE_START_SWIM
Definition Opcodes.h:1977
@ SMSG_MOVE_UPDATE_RUN_BACK_SPEED
Definition Opcodes.h:2004
@ SMSG_MOVE_SET_SWIM_BACK_SPEED
Definition Opcodes.h:1948
@ SMSG_MOVE_UNSET_CAN_TURN_WHILE_FALLING
Definition Opcodes.h:1989
@ SMSG_MOVE_SET_RUN_SPEED
Definition Opcodes.h:1947
@ SMSG_MOVE_DISABLE_TRANSITION_BETWEEN_SWIM_AND_FLY
Definition Opcodes.h:1898
@ SMSG_MOVE_SPLINE_ENABLE_COLLISION
Definition Opcodes.h:1957
@ SMSG_MOVE_ENABLE_STRAFING
Definition Opcodes.h:1906
@ SMSG_MOVE_SET_ADV_FLYING_AIR_FRICTION
Definition Opcodes.h:1916
@ SMSG_MOVE_SET_LAND_WALK
Definition Opcodes.h:1942
@ SMSG_MOVE_DISABLE_JUMPING
Definition Opcodes.h:1896
@ SMSG_MOVE_SPLINE_SET_FEATHER_FALL
Definition Opcodes.h:1960
@ SMSG_MOVE_SPLINE_SET_WALK_MODE
Definition Opcodes.h:1974
@ SMSG_MOVE_SET_FEATHER_FALL
Definition Opcodes.h:1936
@ SMSG_MOVE_ENABLE_JUMPING
Definition Opcodes.h:1905
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
PetAction
Definition PetDefines.h:93
@ 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:713
@ EQUIPMENT_SLOT_END
Definition Player.h:734
@ EQUIPMENT_SLOT_OFFHAND
Definition Player.h:731
@ TELE_TO_SPELL
Definition Player.h:913
@ TELE_TO_NOT_LEAVE_COMBAT
Definition Player.h:911
@ TELE_TO_NONE
Definition Player.h:908
@ TELE_TO_NOT_LEAVE_TRANSPORT
Definition Player.h:910
std::unordered_map< uint32, PlayerSpell > PlayerSpellMap
Definition Player.h:351
constexpr uint8 INVENTORY_SLOT_BAG_0
Definition Player.h:706
@ CHEAT_GOD
Definition Player.h:1060
@ PLAYERSPELL_REMOVED
Definition Player.h:208
Trinity::IteratorPair< UF::ChrCustomizationChoice const * > MakeChrCustomizationChoiceRange(Container const &container)
Definition Player.h:3435
Races
Definition RaceMask.h:28
float rand_norm()
Definition Random.cpp:76
bool roll_chance(float chance, PseudoRandomDistributionState &state)
Definition Random.cpp:131
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:43
#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
@ SPELL_EFFECT_HEALTH_LEECH
@ SPELL_EFFECT_NORMALIZED_WEAPON_DMG
@ SPELL_EFFECT_SUMMON
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
@ 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
SpellAttr0
@ 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
@ SPELL_FAILED_INTERRUPTED
@ GHOST_VISIBILITY_ALIVE
@ SPELL_HIT_TYPE_CRIT
@ SPELL_HIT_TYPE_SPLIT
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
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_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_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_STAT_BONUS_PCT
@ 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_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
@ 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
#define MAX_MOVE_TYPE
#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
#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:4225
ProcFlagsHit createProcHitMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
Definition Unit.cpp:10475
static uint32 CalcMeleeAttackRageGain(Unit const *attacker, WeaponAttackType attType)
Definition Unit.cpp:2239
void ApplyPercentModFloatVar(float &var, float val, bool apply)
Definition Unit.cpp:9613
float playerBaseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:111
UnitModifierFlatType
Definition Unit.h:157
@ BASE_VALUE
Definition Unit.h:158
@ MODIFIER_TYPE_FLAT_END
Definition Unit.h:160
@ TOTAL_VALUE
Definition Unit.h:159
std::unordered_multimap< uint32, uint32 > SpellImmuneContainer
Definition Unit.h:154
@ UNIT_MASK_NONE
Definition Unit.h:369
@ UNIT_MASK_CONTROLABLE_GUARDIAN
Definition Unit.h:378
@ UNIT_MASK_ACCESSORY
Definition Unit.h:379
@ UNIT_MASK_VEHICLE
Definition Unit.h:375
@ UNIT_MASK_GUARDIAN
Definition Unit.h:372
@ UNIT_MASK_MINION
Definition Unit.h:371
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
AttackPowerModType
Definition Unit.h:257
WeaponDamageRange
Definition Unit.h:171
@ MINDAMAGE
Definition Unit.h:172
@ MAXDAMAGE
Definition Unit.h:173
UnitMods
Definition Unit.h:177
@ UNIT_MOD_DAMAGE_OFFHAND
Definition Unit.h:218
@ UNIT_MOD_COMBO_POINTS
Definition Unit.h:188
@ UNIT_MOD_STAT_INTELLECT
Definition Unit.h:181
@ UNIT_MOD_STAT_SPIRIT
Definition Unit.h:182
@ UNIT_MOD_ARMOR
Definition Unit.h:210
@ UNIT_MOD_RESISTANCE_SHADOW
Definition Unit.h:215
@ UNIT_MOD_RESISTANCE_FROST
Definition Unit.h:214
@ UNIT_MOD_END
Definition Unit.h:220
@ UNIT_MOD_RESISTANCE_HOLY
Definition Unit.h:211
@ UNIT_MOD_RESISTANCE_START
Definition Unit.h:224
@ UNIT_MOD_SOUL_SHARDS
Definition Unit.h:191
@ UNIT_MOD_RESISTANCE_ARCANE
Definition Unit.h:216
@ UNIT_MOD_ESSENCE
Definition Unit.h:203
@ UNIT_MOD_ARCANE_CHARGES
Definition Unit.h:200
@ UNIT_MOD_ENERGY
Definition Unit.h:187
@ UNIT_MOD_HEALTH
Definition Unit.h:183
@ UNIT_MOD_RUNES
Definition Unit.h:189
@ UNIT_MOD_DAMAGE_RANGED
Definition Unit.h:219
@ UNIT_MOD_HOLY_POWER
Definition Unit.h:193
@ UNIT_MOD_PAIN
Definition Unit.h:202
@ UNIT_MOD_BURNING_EMBERS
Definition Unit.h:198
@ UNIT_MOD_RUNE_UNHOLY
Definition Unit.h:206
@ UNIT_MOD_POWER_START
Definition Unit.h:226
@ UNIT_MOD_RUNE_BLOOD
Definition Unit.h:204
@ UNIT_MOD_CHI
Definition Unit.h:196
@ UNIT_MOD_RESISTANCE_FIRE
Definition Unit.h:212
@ UNIT_MOD_STAT_STRENGTH
Definition Unit.h:178
@ UNIT_MOD_RUNE_FROST
Definition Unit.h:205
@ UNIT_MOD_FURY
Definition Unit.h:201
@ UNIT_MOD_ALTERNATE
Definition Unit.h:194
@ UNIT_MOD_RESISTANCE_NATURE
Definition Unit.h:213
@ UNIT_MOD_ALTERNATE_ENCOUNTER
Definition Unit.h:208
@ UNIT_MOD_LUNAR_POWER
Definition Unit.h:192
@ UNIT_MOD_MAELSTROM
Definition Unit.h:195
@ UNIT_MOD_DEMONIC_FURY
Definition Unit.h:199
@ UNIT_MOD_ALTERNATE_QUEST
Definition Unit.h:207
@ UNIT_MOD_STAT_AGILITY
Definition Unit.h:179
@ UNIT_MOD_ALTERNATE_MOUNT
Definition Unit.h:209
@ UNIT_MOD_INSANITY
Definition Unit.h:197
@ UNIT_MOD_FOCUS
Definition Unit.h:186
@ UNIT_MOD_DAMAGE_MAINHAND
Definition Unit.h:217
@ UNIT_MOD_MANA
Definition Unit.h:184
@ UNIT_MOD_STAT_START
Definition Unit.h:222
@ UNIT_MOD_RAGE
Definition Unit.h:185
@ UNIT_MOD_STAT_STAMINA
Definition Unit.h:180
@ UNIT_MOD_RUNIC_POWER
Definition Unit.h:190
TC_GAME_API float playerBaseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:111
DeathState
Definition Unit.h:265
@ CORPSE
Definition Unit.h:268
@ DEAD
Definition Unit.h:269
@ ALIVE
Definition Unit.h:266
@ JUST_RESPAWNED
Definition Unit.h:270
@ JUST_DIED
Definition Unit.h:267
#define CURRENT_FIRST_NON_MELEE_SPELL
Definition Unit.h:615
CurrentSpellTypes
Definition Unit.h:608
@ CURRENT_CHANNELED_SPELL
Definition Unit.h:611
@ CURRENT_GENERIC_SPELL
Definition Unit.h:610
@ CURRENT_MELEE_SPELL
Definition Unit.h:609
@ CURRENT_AUTOREPEAT_SPELL
Definition Unit.h:612
UnitState
Definition Unit.h:274
@ UNIT_STATE_DISTRACTED
Definition Unit.h:287
@ UNIT_STATE_DIED
Definition Unit.h:275
@ UNIT_STATE_ATTACK_PLAYER
Definition Unit.h:289
@ UNIT_STATE_POSSESSED
Definition Unit.h:291
@ UNIT_STATE_UNATTACKABLE
Definition Unit.h:313
@ UNIT_STATE_LOST_CONTROL
Definition Unit.h:316
@ UNIT_STATE_CANNOT_AUTOATTACK
Definition Unit.h:317
@ UNIT_STATE_CONFUSED
Definition Unit.h:286
@ UNIT_STATE_ROOT
Definition Unit.h:285
@ UNIT_STATE_CHARGING
Definition Unit.h:292
@ UNIT_STATE_CONTROLLED
Definition Unit.h:315
@ UNIT_STATE_FLEEING
Definition Unit.h:282
@ UNIT_STATE_CANNOT_TURN
Definition Unit.h:319
@ UNIT_STATE_MOVING
Definition Unit.h:314
@ UNIT_STATE_MOVE
Definition Unit.h:295
@ UNIT_STATE_MELEE_ATTACKING
Definition Unit.h:276
@ UNIT_STATE_IN_FLIGHT
Definition Unit.h:283
@ UNIT_STATE_FOCUSING
Definition Unit.h:281
@ UNIT_STATE_CASTING
Definition Unit.h:290
@ UNIT_STATE_STUNNED
Definition Unit.h:278
@ UNIT_STATE_CHARMED
Definition Unit.h:277
MeleeHitOutcome
Definition Unit.h:399
@ MELEE_HIT_CRUSHING
Definition Unit.h:401
@ MELEE_HIT_BLOCK
Definition Unit.h:400
@ MELEE_HIT_CRIT
Definition Unit.h:401
@ MELEE_HIT_NORMAL
Definition Unit.h:401
@ MELEE_HIT_EVADE
Definition Unit.h:400
@ MELEE_HIT_DODGE
Definition Unit.h:400
@ MELEE_HIT_MISS
Definition Unit.h:400
@ MELEE_HIT_PARRY
Definition Unit.h:400
@ MELEE_HIT_GLANCING
Definition Unit.h:401
#define MAX_AGGRO_RESET_TIME
Definition Unit.h:44
AttackPowerModIndex
Definition Unit.h:250
#define SPELL_DAZED
Definition Unit.h:37
#define ATTACK_DISPLAY_DELAY
Definition Unit.h:643
std::vector< DispelableAura > DispelChargesList
Definition Unit.h:152
#define CURRENT_MAX_SPELL
Definition Unit.h:616
CombatRating
Definition Unit.h:330
@ CR_VERSATILITY_DAMAGE_TAKEN
Definition Unit.h:361
@ CR_ARMOR_PENETRATION
Definition Unit.h:355
@ CR_VERSATILITY_DAMAGE_DONE
Definition Unit.h:359
ReactiveType
Definition Unit.h:624
@ MAX_REACTIVE
Definition Unit.h:627
@ REACTIVE_DEFENSE
Definition Unit.h:625
@ REACTIVE_DEFENSE_2
Definition Unit.h:626
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:164
@ MODIFIER_TYPE_PCT_END
Definition Unit.h:167
@ TOTAL_PCT
Definition Unit.h:166
@ BASE_PCT
Definition Unit.h:165
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:242
bool isWorldBoss() const
CreatureDifficulty const * GetCreatureDifficulty() const
Definition Creature.h:276
uint16 GetLootMode() const
Definition Creature.h:325
std::unordered_map< ObjectGuid, std::unique_ptr< Loot > > m_personalLoot
Definition Creature.h:308
void SetLastDamagedTime(time_t val)
Definition Creature.h:450
bool IsEvadingAttacks() const
Definition Creature.h:225
void AllLootRemovedFromCorpse()
bool CanHaveLoot() const
Definition Creature.h:303
GuidUnorderedSet const & GetTapList() const
Definition Creature.h:312
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:274
uint32 GetLootId() const
bool CannotPenetrateWater() const
Definition Creature.h:156
bool CanEnterWater() const override
Definition Creature.h:166
void SetDisplayId(uint32 displayId, bool setNative=false) override
void LowerPlayerDamageReq(uint64 unDamage)
bool HasFlag(CreatureStaticFlags flag) const
Definition Creature.h:480
bool IsFullyLooted() const
void SendAIReaction(AiReaction reactionType)
bool IsAquatic() const
Definition Creature.h:136
void CallAssistance()
bool IsInEvadeMode() const
Definition Creature.h:224
CreatureAI * AI() const
Definition Creature.h:235
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:450
void ResistDamage(uint32 amount)
Definition Unit.cpp:220
void AbsorbDamage(uint32 amount)
Definition Unit.cpp:212
ProcFlagsHit m_hitMask
Definition Unit.h:449
uint32 m_resist
Definition Unit.h:447
void ModifyDamage(int32 amount)
Definition Unit.cpp:206
Unit * GetVictim() const
Definition Unit.h:461
Unit * GetAttacker() const
Definition Unit.h:460
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:467
uint32 m_block
Definition Unit.h:448
SpellInfo const * GetSpellInfo() const
Definition Unit.h:462
void BlockDamage(uint32 amount)
Definition Unit.cpp:232
DamageEffectType GetDamageType() const
Definition Unit.h:464
WeaponAttackType GetAttackType() const
Definition Unit.h:465
uint32 GetResist() const
Definition Unit.h:469
SpellSchoolMask GetSchoolMask() const
Definition Unit.h:463
uint32 m_absorb
Definition Unit.h:446
uint32 m_damage
Definition Unit.h:440
ProcFlagsHit GetHitMask() const
Definition Unit.cpp:245
uint32 GetDamage() const
Definition Unit.h:466
uint32 GetAbsorb() const
Definition Unit.h:468
uint8 GetRemovedCharges() const
Definition Unit.h:412
bool RollDispel() const
Definition Unit.cpp:131
int32 _chance
Definition Unit.h:149
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:251
uint32 GetSpellId() const
Definition GameObject.h:258
void SetOwnerGUID(ObjectGuid owner)
Definition GameObject.h:241
void SetRespawnTime(int32 respawn)
Definition Group.h:209
uint32 GetMembersCount() const
Definition Group.h:339
ObjectGuid GetLooterGuid() const
Definition Group.cpp:1638
GroupRefManager & GetMembers()
Definition Group.h:336
bool InitStatsForLevel(uint8 level)
Definition Pet.cpp:847
uint32 _heal
Definition Unit.h:480
Unit * GetHealer() const
Definition Unit.h:494
uint32 _effectiveHeal
Definition Unit.h:482
uint32 GetAbsorb() const
Definition Unit.h:499
uint32 GetEffectiveHeal() const
Definition Unit.h:498
SpellInfo const * GetSpellInfo() const
Definition Unit.h:500
uint32 _absorb
Definition Unit.h:483
uint32 GetHitMask() const
Definition Unit.cpp:265
uint32 GetOriginalHeal() const
Definition Unit.h:497
void SetEffectiveHeal(uint32 amount)
Definition Unit.h:492
SpellSchoolMask GetSchoolMask() const
Definition Unit.h:501
void AbsorbHeal(uint32 amount)
Definition Unit.cpp:255
Unit * GetTarget() const
Definition Unit.h:495
HealInfo(Unit *healer, Unit *target, uint32 heal, SpellInfo const *spellInfo, SpellSchoolMask schoolMask)
Definition Unit.cpp:250
uint32 GetHeal() const
Definition Unit.h:496
uint32 _hitMask
Definition Unit.h:486
Definition Item.h:185
ItemTemplate const * GetTemplate() const
Definition Item.cpp:1233
bool IsBroken() const
Definition Item.h:273
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:1090
bool IsDungeon() const
Definition Map.cpp:3303
void CreatureRelocation(Creature *creature, float x, float y, float z, float ang, bool respawnRelocationOnFail=true)
Definition Map.cpp:1058
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:1704
MapDifficultyEntry const * GetMapDifficulty() const
Definition Map.cpp:3283
float GetWaterOrGroundLevel(PhaseShift const &phaseShift, float x, float y, float z, float *ground=nullptr, bool swim=false, float collisionHeight=2.03128f)
Definition Map.cpp:1755
BattlegroundMap * ToBattlegroundMap()
Definition Map.h:498
Difficulty GetDifficultyID() const
Definition Map.h:363
MapEntry const * GetEntry() const
Definition Map.h:233
PlayerList const & GetPlayers() const
Definition Map.h:408
void PlayerRelocation(Player *, float x, float y, float z, float orientation)
Definition Map.cpp:1031
Creature * GetCreature(ObjectGuid const &guid)
Definition Map.cpp:3578
Transport * GetTransport(ObjectGuid const &guid)
Definition Map.cpp:3598
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 InterruptOnTeleport()
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 MoveFace(float orientation, uint32 id=EVENT_FACE)
void MoveTo(Vector3 const &destination, bool generatePath=true, bool forceDestination=false)
void Stop(bool force=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:1843
std::string GetDebugInfo() const override
Definition Pet.cpp:1952
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:1612
static void InheritPhaseShift(WorldObject *target, WorldObject const *source)
void StopCastingBindSight() const
Definition Player.cpp:26867
void SetClientControl(Unit *target, bool allowMove)
Definition Player.cpp:26441
bool IsInSameRaidWith(Player const *p) const
Definition Player.cpp:2060
void SendAttackSwingCancelAttack() const
Definition Player.cpp:21788
void AddPetToUpdateFields(PetStable::PetInfo const &pet, PetSaveMode slot, PetStableFlags flags)
Definition Player.cpp:29589
void SetGroupUpdateFlag(uint32 flag)
Definition Player.h:2789
void DuelComplete(DuelCompleteType type)
Definition Player.cpp:7683
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6193
uint16 GetSkillValue(uint32 skill) const
Definition Player.cpp:5920
UF::UpdateField< UF::ActivePlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_ACTIVE_PLAYER > m_activePlayerData
Definition Player.h:3048
void SendAutoRepeatCancel(Unit *target)
Definition Player.cpp:21801
PetStable & GetOrInitPetStable()
Definition Player.cpp:29581
float GetRatingBonusValue(CombatRating cr) const
Definition Player.cpp:5139
void CharmSpellInitialize()
Definition Player.cpp:22530
void UpdatePvPState(bool onlyFFA=false)
Definition Player.cpp:24013
bool InBattleground() const
Definition Player.h:2570
void DurabilityPointLossForEquipSlot(EquipmentSlots slot)
Definition Player.cpp:4564
void PetSpellInitialize()
Definition Player.cpp:22418
uint32 GetBaseSpellPowerBonus() const
Returns base spellpower bonus from spellpower stat on items, without spellpower from intellect stat.
Definition Player.h:2220
void SetFallInformation(uint32 time, float z)
Definition Player.cpp:27437
bool HaveAtClient(BaseEntity const *u) const
Definition Player.cpp:24425
void SendRemoveControlBar() const
Definition Player.cpp:22570
WorldSession * GetSession() const
Definition Player.h:2256
OutdoorPvP * GetOutdoorPvP() const
Definition Player.cpp:26147
void CastItemCombatSpell(DamageInfo const &damageInfo)
Definition Player.cpp:8591
PlayerSpellMap const & GetSpellMap() const
Definition Player.h:2056
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition Player.cpp:27532
void StopCastingCharm()
Definition Player.cpp:22216
Battleground * GetBattleground() const
Definition Player.cpp:25650
float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const
Definition Player.cpp:5200
bool IsGameMaster() const
Definition Player.h:1293
std::array< uint8, MAX_MOVE_TYPE > m_forced_speed_changes
Definition Player.h:2706
void PossessSpellInitialize()
Definition Player.cpp:22457
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition Player.cpp:9577
Group * GetGroup(Optional< uint8 > partyIndex)
Definition Player.h:2781
std::unique_ptr< DuelInfo > duel
Definition Player.h:2126
uint8 GetSubGroup() const
Definition Player.h:2787
void VehicleSpellInitialize()
Definition Player.cpp:22483
Team GetEffectiveTeam() const
Definition Player.h:2410
void SetFactionForRace(uint8 race)
Definition Player.cpp:6407
Stats GetPrimaryStat() const
void SetContestedPvP(Player *attackedPlayer=nullptr)
Definition Player.cpp:21933
void ResummonPetTemporaryUnSummonedIfAny()
Definition Player.cpp:27944
void UpdatePvP(bool state, bool override=false)
Definition Player.cpp:24056
bool IsInSameGroupWith(Player const *p) const
Definition Player.cpp:2053
DamageInfo * _damageInfo
Definition Unit.h:537
SpellSchoolMask GetSchoolMask() const
Definition Unit.cpp:292
HealInfo * _healInfo
Definition Unit.h:538
Spell const * GetProcSpell() const
Definition Unit.h:527
ProcEventInfo(Unit *actor, Unit *actionTarget, ProcFlagsInit const &typeMask, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition Unit.cpp:270
SpellInfo const * GetSpellInfo() const
Definition Unit.cpp:281
Spell * _spell
Definition Unit.h:536
Mechanics Mechanic
Definition SpellInfo.h:226
AuraType ApplyAuraName
Definition SpellInfo.h:216
float CalcValueMultiplier(WorldObject *caster, Spell *spell=nullptr) const
SpellEffects 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
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 IsAutoShot() 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
bool HasChannelInterruptFlag(SpellAuraInterruptFlags flag) const
Definition SpellInfo.h:481
bool IsPassiveStackableWithRanks() const
uint32 MaxAffectedTargets
Definition SpellInfo.h:413
int32 GetDuration() const
std::vector< SpellEffectInfo > const & GetEffects() const
Definition SpellInfo.h:589
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 HasEffect(SpellEffects effect) const
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:8970
bool IsInterruptable() const
Definition Spell.h:683
static Spell const * ExtractSpellFromEvent(BasicEvent *event)
Definition Spell.cpp:5737
void cancel(SpellCastResult result=SPELL_FAILED_INTERRUPTED, Optional< SpellCastResult > resultOther={}, ObjectGuid const &failedBy=ObjectGuid::Empty)
Definition Spell.cpp:3613
bool IsProcDisabled() const
Definition Spell.cpp:8303
int32 GetCastTime() const
Definition Spell.h:659
std::string GetDebugInfo() const
Definition Spell.cpp:9245
void SendChannelUpdate(uint32 time, Optional< SpellCastResult > result={}, ObjectGuid const &failedBy=ObjectGuid::Empty)
Definition Spell.cpp:5198
int32 GetProcChainLength() const
Definition Spell.h:679
void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const &damageInfo, uint32 &resistAmount, int32 &absorbAmount)
Definition Spell.cpp:9033
CurrentSpellTypes GetCurrentContainer() const
Definition Spell.cpp:8160
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition Spell.cpp:3432
void CallScriptCalcHealingHandlers(SpellEffectInfo const &spellEffectInfo, Unit *victim, int32 &healing, int32 &flatMod, float &pctMod)
Definition Spell.cpp:8982
Spell ** m_selfContainer
Definition Spell.h:714
void SetReferencedFromCurrent(bool yes)
Definition Spell.h:682
static void SendCastResult(Player const *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:4641
UsedSpellMods m_appliedMods
Definition Spell.h:654
void CallScriptCalcCritChanceHandlers(Unit const *victim, float &chance)
Definition Spell.cpp:8958
void finish(SpellCastResult result=SPELL_CAST_OK)
Definition Spell.cpp:4359
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:41
Definition Unit.h:647
float GetUnitMissChance() const
Definition Unit.cpp:2825
void EnterVehicle(Unit *base, int8 seatId=-1)
Definition Unit.cpp:12845
void SetCannotTurn(bool apply)
Definition Unit.cpp:8591
bool SetCanDoubleJump(bool enable)
Definition Unit.cpp:13987
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:825
float GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const
Definition Unit.cpp:9695
Unit * GetCharmed() const
Definition Unit.h:1232
void ClearUnitState(uint32 f)
Definition Unit.h:756
void OutDebugInfo() const
Definition Unit.cpp:13246
bool IsWithinMeleeRangeAt(Position const &pos, Unit const *obj) const
Definition Unit.cpp:691
void RemoveAreaTrigger(uint32 spellId)
Definition Unit.cpp:5504
bool IsStopped() const
Definition Unit.h:1754
void SetFlightCapabilityID(int32 flightCapabilityId, bool clientUpdate)
Definition Unit.cpp:9022
bool IsVehicle() const
Definition Unit.h:766
void ApplySpellImmune(uint32 spellId, SpellImmunity op, uint32 type, bool apply)
Definition Unit.cpp:8261
void SetMinion(Minion *minion, bool apply)
Definition Unit.cpp:6266
std::pair< AuraApplicationMap::iterator, AuraApplicationMap::iterator > AuraApplicationMapBoundsNonConst
Definition Unit.h:659
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition Unit.cpp:8716
void CastStop(uint32 except_spellid=0)
Definition Unit.cpp:1191
bool IsWithinMeleeRange(Unit const *obj) const
Definition Unit.h:722
void ApplyMovementForce(ObjectGuid id, Position origin, float magnitude, MovementForceType type, Position direction={}, ObjectGuid transportGuid=ObjectGuid::Empty)
Definition Unit.cpp:14128
void SetImmuneToAll(bool apply, bool keepCombat)
Definition Unit.cpp:8524
bool IsCharmed() const
Definition Unit.h:1256
void SetImmuneToPC(bool apply, bool keepCombat)
Definition Unit.cpp:8537
bool m_duringRemoveFromWorld
Definition Unit.h:2051
float GetBoundingRadius() const
Definition Unit.h:719
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:6830
void RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3769
Vehicle * GetVehicle() const
Definition Unit.h:1800
EnumFlag< SpellAuraInterruptFlags2 > m_interruptMask2
Definition Unit.h:1951
bool IsWithinBoundaryRadius(const Unit *obj) const
Definition Unit.cpp:712
void SetVisible(bool x)
Definition Unit.cpp:8787
virtual bool IsMovementPreventedByCasting() const
Definition Unit.cpp:3283
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3973
int32 SpellAbsorbBonusTaken(Unit *caster, SpellInfo const *spellProto, int32 absorbamount) const
Definition Unit.cpp:7727
bool SetAlwaysAllowPitching(bool enable)
Definition Unit.cpp:13890
virtual void UpdateResistances(uint32 school)
Definition Unit.cpp:9954
bool SetStrafingDisabled(bool disable)
Definition Unit.cpp:13766
void DeleteCharmInfo()
Definition Unit.cpp:10455
void RemoveGameObject(GameObject *gameObj, bool del)
Definition Unit.cpp:5436
bool isTargetableForAttack(bool checkFakeDeath=true) const
Definition Unit.cpp:8604
bool IsHunterPet() const
Definition Unit.h:764
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition Unit.h:1362
uint32 GetSchoolImmunityMask() const
Definition Unit.cpp:7834
std::unique_ptr< SpellHistory > _spellHistory
Definition Unit.h:2061
void UpdateAttackTimeField(WeaponAttackType att)
Definition Unit.cpp:11018
float GetHealthPct() const
Definition Unit.h:808
float m_baseSpellCritChance
Definition Unit.h:1540
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true, bool skipChanneledAllowingActions=false) const
Definition Unit.cpp:3219
SpellImmuneContainer m_spellImmune[MAX_SPELL_IMMUNITY]
Definition Unit.h:1616
void CombatStop(bool includingCast=false, bool mutualPvP=true, bool(*unitFilter)(Unit const *otherUnit)=nullptr)
Definition Unit.cpp:6031
int32 MeleeDamageBonusTaken(Unit *attacker, int32 pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const *spellProto=nullptr, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL)
Definition Unit.cpp:8152
void SetCreateStat(Stats stat, float val)
Definition Unit.cpp:5306
void AIUpdateTick(uint32 diff)
Definition Unit.cpp:10223
virtual void RecalculateObjectScale()
Definition Unit.cpp:10844
void SetHealth(uint64 val)
Definition Unit.cpp:10041
void HandleAttackPowerModifier(AttackPowerModIndex index, AttackPowerModType modifierType, float amount, bool apply)
Definition Unit.cpp:9766
void RemoveUnitMovementFlag(MovementFlags f)
Definition Unit.h:1760
Unit * m_unitMovedByMe
Definition Unit.h:1965
virtual MovementGeneratorType GetDefaultMovementType() const
Definition Unit.cpp:10748
bool HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag128 familyFlags) const
Definition Unit.cpp:766
AuraList m_removedAuras
Definition Unit.h:1942
void SetFacingToPoint(Position const &point, bool force=true)
Definition Unit.cpp:13403
bool SetCanAdvFly(bool enable)
Definition Unit.cpp:14049
LiquidTypeEntry const * _lastLiquid
Definition Unit.h:1981
float GetTotalAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition Unit.cpp:5107
static uint32 SpellCriticalHealingBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition Unit.cpp:7329
void _UpdateAutoRepeatSpell()
Definition Unit.cpp:3008
void SetVirtualItem(uint32 slot, uint32 itemId, uint16 appearanceModId=0, uint16 itemVisual=0)
Definition Unit.cpp:14521
void SendMoveKnockBack(Player *player, float speedXY, float speedZ, float vcos, float vsin)
Definition Unit.cpp:12576
float GetTotalAuraModValue(UnitMods unitMod) const
Definition Unit.cpp:9900
float GetMaxPositiveAuraModifier(AuraType auraType) const
Definition Unit.cpp:5097
AreaTriggerList m_areaTrigger
Definition Unit.h:1933
void AddUnitMovementFlag(MovementFlags f)
Definition Unit.h:1759
uint64 CountPctFromMaxHealth(float pct) const
Definition Unit.h:809
bool IsInteractionAllowedInCombat() const
Definition Unit.h:1082
void RestoreDisabledAI()
Definition Unit.cpp:10277
void Heartbeat() override
Definition Unit.cpp:507
int32 SpellHealingBonusTaken(Unit *caster, SpellInfo const *spellProto, int32 healamount, DamageEffectType damagetype) const
Definition Unit.cpp:7514
void RemoveAllControlled()
Definition Unit.cpp:6632
Pet * ToPet()
Definition Unit.h:1838
ObjectGuid GetDemonCreatorGUID() const
Definition Unit.h:1223
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Definition Unit.h:1045
void RemoveGameObjectImpl(GameObject *gameObj, bool del)
Definition Unit.cpp:5406
void RemoveAurasByShapeShift()
Definition Unit.cpp:4352
float GetTotalStatValue(Stats stat) const
Definition Unit.cpp:9884
void SetPlayHoverAnim(bool enable, bool sendUpdate=true)
Definition Unit.cpp:14322
std::unique_ptr< MotionMaster > i_motionMaster
Definition Unit.h:1972
void SetUnitFlag3(UnitFlags3 flags)
Definition Unit.h:871
void SetGender(Gender gender)
Definition Unit.h:780
float GetUnitCriticalChanceTaken(Unit const *attacker, WeaponAttackType attackType, float critDone) const
Definition Unit.cpp:2898
bool IsContestedGuard() const
Definition Unit.cpp:12328
std::unordered_map< ObjectGuid, uint32 > extraAttacksTargets
Definition Unit.h:2047
void UpdateUnitMod(UnitMods unitMod)
Definition Unit.cpp:9706
void UpdateDamagePctDoneMods(WeaponAttackType attackType)
Definition Unit.cpp:9837
float GetSpeed(UnitMoveType mtype) const
Definition Unit.cpp:8951
bool SetFall(bool enable)
Definition Unit.cpp:13503
void _UnregisterDynObject(DynamicObject *dynObj)
Definition Unit.cpp:5325
bool m_canModifyStats
Definition Unit.h:1957
float GetTotalAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:5187
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3846
void UpdateObjectVisibility(bool forced=true) override
Definition Unit.cpp:12563
int64 ModifyHealth(int64 val)
Definition Unit.cpp:8618
std::array< uint32, MAX_REACTIVE > m_reactiveTimer
Definition Unit.h:1974
std::shared_ptr< UnitAI > i_AI
Definition Unit.h:2041
uint32 GetCastSpellXSpellVisualId(SpellInfo const *spellInfo) const override
Definition Unit.cpp:14656
void SetCurrentCastSpell(Spell *pSpell)
Definition Unit.cpp:3068
bool _isCombatDisallowed
Definition Unit.h:2066
void SetFullHealth()
Definition Unit.h:814
void TriggerOnHealthChangeAuras(uint64 oldVal, uint64 newVal)
Definition Unit.cpp:8685
void SetMinionGUID(ObjectGuid guid)
Definition Unit.h:1216
float SpellDamagePctDone(Unit *victim, SpellInfo const *spellProto, DamageEffectType damagetype, SpellEffectInfo const &spellEffectInfo) const
Definition Unit.cpp:6921
void RestoreDisplayId(bool ignorePositiveAurasPreventingMounting=false)
Definition Unit.cpp:10876
Diminishing m_Diminishing
Definition Unit.h:2029
void SetHoverHeight(float hoverHeight)
Definition Unit.h:1162
void SetGravityModifier(float gravityModifier)
Definition Unit.cpp:14303
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition Unit.cpp:10804
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:6817
void SetInitialPowerValue(Powers powerType)
Definition Unit.cpp:5769
void SendPlaySpellVisual(Unit *target, uint32 spellVisualId, uint8 missReason, uint8 reflectStatus, float travelSpeed, bool speedAsTime=false, float launchDelay=0.0f)
Definition Unit.cpp:12400
void UpdateHeight(float newZ)
Only server-side height update, does not broadcast to client.
Definition Unit.cpp:13187
std::array< Spell *, CURRENT_MAX_SPELL > m_currentSpells
Definition Unit.h:1938
void _RemoveNoStackAurasDueToAura(Aura *aura, bool owned)
Definition Unit.cpp:3733
virtual void OnPhaseChange()
Definition Unit.cpp:12559
void SetConfused(bool apply)
Definition Unit.cpp:11834
void _UpdateSpells(uint32 time)
Definition Unit.cpp:2946
ThreatManager & GetThreatManager()
Definition Unit.h:1093
void ReplaceAllPvpFlags(UnitPVPStateFlags flags)
Definition Unit.h:898
void AddToWorld() override
Definition Unit.cpp:10301
virtual float GetArmorMultiplierForTarget(WorldObject const *) const
Definition Unit.h:821
void RestoreFaction()
Definition Unit.cpp:12143
float GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const *spellProto) const
Definition Unit.cpp:8289
virtual void AtExitCombat()
Definition Unit.cpp:9259
void _UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode)
Definition Unit.cpp:3620
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition Unit.cpp:4845
virtual ClassPowerTypes GetPowerTypes() const =0
void SetInCombatWith(Unit *enemy, bool addSecondUnitSuppressed=false)
Definition Unit.h:1075
float GetMaxPositiveAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:5207
virtual void Say(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition Unit.cpp:14479
void PropagateSpeedChange()
-------—End of Pet responses methods-------—
Definition Unit.cpp:10743
void DelayOwnedAuras(uint32 spellId, ObjectGuid caster, int32 delaytime)
Definition Unit.cpp:4591
void SetControlled(bool apply, UnitState state)
Definition Unit.cpp:11631
uint8 GetClass() const
Definition Unit.h:776
float GetMaxNegativeAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:5217
SpellSchools GetSpellSchoolByAuraGroup(UnitMods unitMod) const
Definition Unit.cpp:9916
void SetStunned(bool apply)
Definition Unit.cpp:11728
void ApplySpellHastePercentMod(float val, bool apply)
Definition Unit.cpp:11073
std::array< ObjectGuid, MAX_SUMMON_SLOT > m_SummonSlot
Definition Unit.h:1524
Stats GetStatByAuraGroup(UnitMods unitMod) const
Definition Unit.cpp:9936
uint32 m_state
Definition Unit.h:2027
void HandleSpellClick(Unit *clicker, int8 seatId=-1)
Definition Unit.cpp:12732
bool CanUseAttackType(uint8 attacktype) const
Definition Unit.cpp:2594
bool IsWithinCombatRange(Unit const *obj, float dist2compare) const
Definition Unit.cpp:675
Player * GetDemonCreatorPlayer() const
Definition Unit.cpp:6216
void SendPetAIReaction(ObjectGuid guid) const
Definition Unit.cpp:10729
void _RegisterAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5474
bool HasAuraTypeWithCaster(AuraType auraType, ObjectGuid caster) const
Definition Unit.cpp:4837
Spell * FindCurrentSpellBySpellId(uint32 spell_id) const
Definition Unit.cpp:3268
uint32 GetMountDisplayId() const
Definition Unit.h:928
void UpdateAllDamageDoneMods()
Definition Unit.cpp:9831
Vehicle * m_vehicle
Definition Unit.h:1977
void RemoveVisibleAura(AuraApplication *aurApp)
Definition Unit.cpp:729
Totem * ToTotem()
Definition Unit.h:1841
int64 GetHealthGain(int64 dVal)
Definition Unit.cpp:8660
Creature * GetVehicleCreatureBase() const
Definition Unit.cpp:12227
std::unique_ptr< CharmInfo > m_charmInfo
Definition Unit.h:1969
void UpdateDisplayPower()
Definition Unit.cpp:5827
float GetCollisionHeight() const override
Definition Unit.cpp:14680
void RemoveAllGameObjects()
Definition Unit.cpp:5463
static void DealHeal(HealInfo &healInfo)
Definition Unit.cpp:6543
bool isPossessedByPlayer() const
Definition Unit.cpp:6659
void SendClearTarget()
Definition Unit.cpp:13288
std::multimap< uint32, AuraApplication * > AuraApplicationMap
Definition Unit.h:657
void _RegisterDynObject(DynamicObject *dynObj)
Definition Unit.cpp:5318
void UpdateSpeed(UnitMoveType mtype)
Definition Unit.cpp:8797
void CancelAutoRepeatSpell()
Definition Unit.cpp:3201
static void DealDamageMods(Unit const *attacker, Unit const *victim, uint32 &damage, uint32 *absorb)
Definition Unit.cpp:804
bool IsPolymorphed() const
Definition Unit.cpp:10831
void CancelTravelShapeshiftForm(AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, bool force=false)
Definition Unit.h:1530
bool IsAreaSpiritHealer() const
Definition Unit.h:1032
void PlayOneShotAnimKitId(uint16 animKitId)
Definition Unit.cpp:11246
float m_weaponDamage[MAX_ATTACK][2]
Definition Unit.h:1956
ShapeshiftForm GetShapeshiftForm() const
Definition Unit.h:1527
void SetFaction(uint32 faction) override
Definition Unit.h:887
virtual void SetPvP(bool state)
Definition Unit.cpp:12336
ObjectGuid GetOwnerGUID() const override
Definition Unit.h:1211
uint64 GetMechanicImmunityMask() const
Definition Unit.cpp:7854
void CancelShapeshiftForm(bool onlyTravelShapeshiftForm=false, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, bool force=false)
Definition Unit.cpp:9527
Unit * SelectNearbyTarget(Unit *exclude=nullptr, float dist=NOMINAL_MELEE_RANGE) const
Definition Unit.cpp:10976
SpellEffectValue GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const *aurEff, AuraType auraType, bool checkMiscValue=false, int32 miscValue=0) const
Definition Unit.cpp:14397
bool isInBackInMap(Unit const *target, float distance, float arc=float(M_PI)) const
Definition Unit.cpp:3323
float GetCombatRatingReduction(CombatRating cr) const
Definition Unit.cpp:12617
void RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject *dispeller, uint8 chargesRemoved=1)
Definition Unit.cpp:4025
bool SetEnableFullSpeedTurning(bool enable)
Definition Unit.cpp:13828
virtual void UpdateAttackPowerAndDamage(bool ranged=false)=0
static void CalcHealAbsorb(HealInfo &healInfo)
Definition Unit.cpp:2099
virtual void Yell(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition Unit.cpp:14484
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:1198
void StopMoving(bool force=false)
Definition Unit.cpp:10753
virtual SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType=BASE_ATTACK) const =0
Unit * GetVehicleRoot() const
Definition Unit.cpp:12211
void SetCantProc(bool apply)
Definition Unit.cpp:11111
Unit * GetCharmer() const
Definition Unit.h:1229
void SetSpeed(UnitMoveType mtype, float newValue)
Definition Unit.cpp:8956
Aura * GetOwnedAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, Aura *except=nullptr) const
Definition Unit.cpp:3830
void ExitAllAreaTriggers()
Definition Unit.cpp:5552
int32 m_procChainLength
Definition Unit.h:1923
void SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
Definition Unit.cpp:9675
Unit * getAttackerForHelper() const
Definition Unit.cpp:5849
std::forward_list< AuraEffect * > AuraEffectList
Definition Unit.h:664
float GetUnitParryChance(WeaponAttackType attType, Unit const *victim) const
Definition Unit.cpp:2785
void SetPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition Unit.cpp:10114
void TriggerOnPowerChangeAuras(Powers power, int32 oldVal, int32 newVal)
Definition Unit.cpp:10176
void SendMeleeAttackStart(Unit *victim)
Definition Unit.cpp:2542
Pet * CreateTamedPetFrom(Creature *creatureTarget, uint32 spell_id=0)
Definition Unit.cpp:11160
void UpdateAdvFlyingSpeed(AdvFlyingRateTypeSingle speedType, bool clientUpdate)
Definition Unit.cpp:9044
Trinity::unique_trackable_ptr< Vehicle > m_vehicleKit
Definition Unit.h:1978
bool IsInDisallowedMountForm() const
Definition Unit.cpp:9565
void ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float amount)
Definition Unit.cpp:9642
std::vector< AreaTrigger * > AreaTriggerList
Definition Unit.h:1932
VisibleAuraContainer m_visibleAuras
Definition Unit.h:1959
UnitPVPStateFlags GetPvpFlags() const
Definition Unit.h:894
float m_attackPowerMods[uint32(AttackPowerModIndex::End)][uint32(AttackPowerModType::End)]
Definition Unit.h:1955
virtual void UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot=-1)
Definition Unit.cpp:9801
void _removeAttacker(Unit *pAttacker)
Definition Unit.cpp:5844
void SendAttackStateUpdate(CalcDamageInfo *damageInfo)
Definition Unit.cpp:5668
AuraApplication * GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition Unit.cpp:4736
std::forward_list< AuraApplication * > AuraApplicationList
Definition Unit.h:666
uint32 GetTransformSpell() const
Definition Unit.h:1644
void EnterAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5542
void RemoveAllAurasExceptType(AuraType type)
Definition Unit.cpp:4535
void DealSpellDamage(SpellNonMeleeDamage const *damageInfo, bool durabilityLoss)
Definition Unit.cpp:1308
uint64 GetRaceMask() const
Definition Unit.cpp:10036
uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const
Definition Unit.cpp:2490
uint32 _lastExtraAttackSpell
Definition Unit.h:2046
float GetMaxNegativeAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:5177
void SetAnimTier(AnimTier animTier, bool notifyClient=true)
Definition Unit.cpp:10818
static void CalcAbsorbResist(DamageInfo &damageInfo, Spell *spell=nullptr)
Definition Unit.cpp:1866
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:3253
virtual bool CanFly() const =0
void SetAuraStack(uint32 spellId, Unit *target, uint32 stack)
Definition Unit.cpp:12391
Unit * GetVehicleBase() const
Definition Unit.cpp:12206
bool haveOffhandWeapon() const
Definition Unit.cpp:530
MotionMaster * GetMotionMaster()
Definition Unit.h:1750
bool SetFeatherFall(bool enable)
Definition Unit.cpp:13618
bool IsPet() const
Definition Unit.h:763
Powers GetPowerType() const
Definition Unit.h:823
bool HasUnitFlag(UnitFlags flags) const
Definition Unit.h:860
static uint32 CalcArmorReducedDamage(Unit const *attacker, Unit *victim, uint32 damage, SpellInfo const *spellInfo, WeaponAttackType attackType=MAX_ATTACK, uint8 attackerLevel=0)
Definition Unit.cpp:1689
void _addAttacker(Unit *pAttacker)
Definition Unit.cpp:5839
bool SetEnableFullSpeedPitching(bool enable)
Definition Unit.cpp:13859
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed=true, bool withInstant=true, SpellCastResult result=SPELL_FAILED_INTERRUPTED, Optional< SpellCastResult > resultOther={}, ObjectGuid const &interrupter=ObjectGuid::Empty)
Definition Unit.cpp:3158
void ProcSkillsAndReactives(bool isVictim, Unit *procTarget, ProcFlagsInit const &typeMask, ProcFlagsHit hitMask, WeaponAttackType attType)
Definition Unit.cpp:10549
bool _instantCast
Definition Unit.h:2052
void Dismount()
Definition Unit.cpp:8336
std::array< ObjectGuid, MAX_GAMEOBJECT_SLOT > m_ObjectSlot
Definition Unit.h:1525
void SetCharm(Unit *target, bool apply)
Definition Unit.cpp:6462
void SetMovedUnit(Unit *target)
Definition Unit.cpp:10464
ObjectGuid GetCharmedGUID() const
Definition Unit.h:1231
void ClearWorldEffects()
Definition Unit.cpp:14718
void SetCreatedBySpell(int32 spellId)
Definition Unit.h:875
bool SetHover(bool enable, bool updateAnimTier=true)
Definition Unit.cpp:13656
bool CanDualWield() const
Definition Unit.h:715
void UpdateInterruptMask()
Definition Unit.cpp:746
void StartReactiveTimer(ReactiveType reactive)
Definition Unit.h:1781
void IncrDiminishing(SpellInfo const *auraSpellInfo)
Definition Unit.cpp:9363
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition Unit.cpp:10396
void AddChannelObject(ObjectGuid guid)
Definition Unit.cpp:3046
void ResumeMovement(uint32 timer=0, uint8 slot=0)
Definition Unit.cpp:10780
float GetMaxNegativeAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition Unit.cpp:5137
Aura * AddAura(uint32 spellId, Unit *target)
Definition Unit.cpp:12344
bool HasInterruptFlag(SpellAuraInterruptFlags flags) const
Definition Unit.h:1626
AuraEffect * GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition Unit.cpp:4622
bool isAttackingPlayer() const
Definition Unit.cpp:6067
void AtEndOfEncounter(EncounterType type)
Definition Unit.cpp:573
virtual void AtEnterCombat()
Definition Unit.cpp:9235
UnitAIStack i_AIs
Definition Unit.h:2040
uint32 GetBaseAttackTime(WeaponAttackType att) const
Definition Unit.cpp:11007
std::unique_ptr< MovementForces > _movementForces
Definition Unit.h:2063
MovementFlags GetUnitMovementFlags() const
Definition Unit.h:1762
void UpdateSplineMovement(uint32 t_diff)
Definition Unit.cpp:600
uint32 GetDamageReduction(uint32 damage) const
Definition Unit.h:983
std::array< float, MAX_STATS > m_floatStatPosBuff
Definition Unit.h:1914
void SetUnitFlag2(UnitFlags2 flags)
Definition Unit.h:866
bool HasUnitFlag2(UnitFlags2 flags) const
Definition Unit.h:865
bool CanFreeMove() const
Definition Unit.cpp:10013
std::string GetDebugInfo() const override
Definition Unit.cpp:14738
std::pair< AuraMap::const_iterator, AuraMap::const_iterator > AuraMapBounds
Definition Unit.h:654
virtual bool IsLoading() const
Definition Unit.h:1835
uint32 BuildAuraStateUpdateForTarget(Unit const *target) const
Definition Unit.cpp:6154
bool isInFrontInMap(Unit const *target, float distance, float arc=float(M_PI)) const
Definition Unit.cpp:3318
float m_auraFlatModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_FLAT_END]
Definition Unit.h:1953
void SetImmuneToNPC(bool apply, bool keepCombat)
Definition Unit.cpp:8560
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition Unit.cpp:10768
void SetPetNameTimestamp(uint32 timestamp)
Definition Unit.h:1266
bool IsSplineEnabled() const
Definition Unit.cpp:14358
std::array< uint32, MAX_ATTACK > m_baseAttackSpeed
Definition Unit.h:1542
void RemoveAllAurasRequiringDeadTarget()
Definition Unit.cpp:4514
void UpdateAuraForGroup()
Definition Unit.cpp:11096
void ApplyHasteRegenPercentMod(float val, bool apply)
Definition Unit.cpp:11081
Vignettes::VignetteData const * GetVignette() const
Definition Unit.h:1892
void UpdateReactives(uint32 p_time)
Definition Unit.cpp:10942
bool IsAlive() const
Definition Unit.h:1205
virtual bool CanApplyResilience() const
Definition Unit.cpp:12485
AuraEffect * IsScriptOverriden(SpellInfo const *spell, int32 script) const
Definition Unit.cpp:4934
float m_modRangedHitChance
Definition Unit.h:1538
float GetCombatReach() const override
Definition Unit.h:717
void AtTargetAttacked(Unit *target, bool canInitialAggro)
Definition Unit.cpp:9283
static uint32 CalcSpellResistedDamage(Unit const *attacker, Unit *victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const *spellInfo)
Definition Unit.cpp:1780
DeathState m_deathState
Definition Unit.h:1920
void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply)
Definition Unit.cpp:11034
void SetBonusResistanceMod(SpellSchools school, int32 val)
Definition Unit.h:797
int32 GetMaxPower(Powers power) const
Definition Unit.cpp:10105
uint32 m_unitTypeMask
Definition Unit.h:1980
std::pair< AuraApplicationMap::const_iterator, AuraApplicationMap::const_iterator > AuraApplicationMapBounds
Definition Unit.h:658
int32 HealBySpell(HealInfo &healInfo, bool critical=false)
Definition Unit.cpp:6795
void AddPlayerToVision(Player *player)
Definition Unit.cpp:6729
void RemoveNpcFlag(NPCFlags flags)
Definition Unit.h:1013
void SendHealSpellLog(HealInfo &healInfo, bool critical=false)
Definition Unit.cpp:6776
GameObject * GetGameObject(uint32 spellId) const
Definition Unit.cpp:5369
int32 GetFlightCapabilityID() const
Definition Unit.h:1738
virtual ~Unit()
Definition Unit.cpp:397
void _ExitVehicle(Position const *exitPosition=nullptr)
Definition Unit.cpp:12950
uint32 m_removedAurasCount
Definition Unit.h:1944
void RemoveAllAurasOnDeath()
Definition Unit.cpp:4491
uint32 m_movementCounter
Incrementing counter used in movement packets.
Definition Unit.h:2023
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const *log)
Definition Unit.cpp:5559
bool IsStandState() const
Definition Unit.cpp:10798
TempSummon * ToTempSummon()
Definition Unit.h:1844
bool IsGravityDisabled() const
Definition Unit.h:1164
CharmInfo * GetCharmInfo()
Definition Unit.h:1262
void AtStartOfEncounter(EncounterType type)
Definition Unit.cpp:548
bool SetCanTransitionBetweenSwimAndFly(bool enable)
Definition Unit.cpp:13921
bool SetDisableInertia(bool disable)
Definition Unit.cpp:14018
ControlList m_Controlled
Definition Unit.h:1252
bool IsInCombatWith(Unit const *who) const
Definition Unit.h:1074
void DisableSpline()
Definition Unit.cpp:664
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition Unit.h:1236
void RemoveUnitFlag3(UnitFlags3 flags)
Definition Unit.h:872
AuraMap::iterator m_auraUpdateIterator
Definition Unit.h:1943
UnitAI * GetAI() const
Definition Unit.h:680
Unit * GetMeleeHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:6601
ObjectGuid _lastDamagedTargetGuid
Definition Unit.h:2048
float SpellCritChanceDone(Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType=BASE_ATTACK) const
Definition Unit.cpp:7140
void CancelSpellMissiles(uint32 spellId, bool reverseMissile=false, bool abortSpell=false)
Definition Unit.cpp:12455
void FollowerRemoved(AbstractFollower *f)
Definition Unit.cpp:9169
void RemoveAllFollowers()
Definition Unit.cpp:9174
virtual void SetInteractionAllowedWhileHostile(bool interactionAllowed)
Definition Unit.cpp:9319
void UpdateMountCapability()
Definition Unit.cpp:8478
void FollowerAdded(AbstractFollower *f)
Definition Unit.cpp:9164
void _DeleteRemovedAuras()
Definition Unit.cpp:2935
Player * GetPlayerMovingMe() const
Definition Unit.h:1273
void CancelMountAura(bool force=false)
Definition Unit.cpp:8369
void _ApplyAura(AuraApplication *aurApp, uint32 effMask)
Definition Unit.cpp:3563
void SetUninteractible(bool apply)
Definition Unit.cpp:8583
Unit * GetNextRandomRaidMemberOrPet(float radius)
Definition Unit.cpp:6677
void SetBaseAttackTime(WeaponAttackType att, uint32 val)
Definition Unit.cpp:11012
virtual bool HasSpell(uint32) const
Definition Unit.h:1099
virtual bool IsAffectedByDiminishingReturns() const
Definition Unit.h:698
std::pair< AuraStateAurasMap::const_iterator, AuraStateAurasMap::const_iterator > AuraStateAurasMapBounds
Definition Unit.h:662
void AddUnitState(uint32 f)
Definition Unit.h:754
float GetMaxPositiveAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask, AuraEffect const *except=nullptr) const
Definition Unit.cpp:5127
static void ApplyResilience(Unit const *victim, int32 *damage)
Definition Unit.cpp:12490
float GetTotalAuraMultiplier(AuraType auraType) const
Definition Unit.cpp:5092
void Mount(uint32 mount, uint32 vehicleId=0, uint32 creatureEntry=0)
Definition Unit.cpp:8303
AreaTriggerList m_insideAreaTriggers
Definition Unit.h:1934
void SetSheath(SheathState sheathed)
Definition Unit.cpp:5832
bool IsOnVehicle(Unit const *vehicle) const
Definition Unit.cpp:12201
void SendSpellDamageResist(Unit *target, uint32 spellId)
Definition Unit.cpp:5649
bool isInAccessiblePlaceFor(Creature const *c) const
Definition Unit.cpp:3328
bool IsCharmedOwnedByPlayerOrPlayer() const
Definition Unit.h:1237
Gender GetGender() const
Definition Unit.h:779
int32 GetMinPower(Powers power) const
Definition Unit.h:830
virtual void SetInteractionAllowedInCombat(bool interactionAllowed)
Definition Unit.cpp:9329
Unit * EnsureVictim() const
Definition Unit.h:740
uint32 getAttackTimer(WeaponAttackType type) const
Definition Unit.h:712
void RefreshAI()
Definition Unit.cpp:10255
bool IsDuringRemoveFromWorld() const
Definition Unit.h:1836
bool m_ControlledByPlayer
Definition Unit.h:1912
void SetFeared(bool apply)
Definition Unit.cpp:11798
Unit * GetCharmerOrOwner() const
Definition Unit.h:1241
uint32 GetDiseasesByCaster(ObjectGuid casterGUID, bool remove=false)
Definition Unit.cpp:4946
void RemoveAurasDueToItemSpell(uint32 spellId, ObjectGuid castItemGuid)
Definition Unit.cpp:4131
virtual void UpdateDamagePhysical(WeaponAttackType attType)
void SetFacingToObject(WorldObject const *object, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13394
void ExitAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5547
bool IsPlayingHoverAnim() const
Definition Unit.h:1159
void _ApplyAllAuraStatMods()
Definition Unit.cpp:4616
bool SetMoveCantSwim(bool cantSwim)
Definition Unit.cpp:14080
void SetBattlePetCompanionNameTimestamp(uint32 timestamp)
Definition Unit.h:1287
uint32 GetCreatureType() const
Definition Unit.cpp:9478
int32 RewardRage(uint32 baseRage)
Definition Unit.cpp:13195
void AddGameObject(GameObject *gameObj)
Definition Unit.cpp:5385
void InterruptMovementBasedAuras()
Definition Unit.cpp:654
virtual bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7936
bool HasNegativeAuraWithInterruptFlag(InterruptFlags flag, ObjectGuid guid=ObjectGuid::Empty) const
Definition Unit.cpp:4881
bool IsThreatened() const
Definition Unit.cpp:8599
bool SetJumpingDisabled(bool disable)
Definition Unit.cpp:13797
void SendSetVehicleRecId(uint32 vehicleId)
Definition Unit.cpp:14111
bool SetSwim(bool enable)
Definition Unit.cpp:13519
void SetEmoteState(Emote emote)
Definition Unit.h:880
virtual bool UpdatePosition(float x, float y, float z, float ang, bool teleport=false)
Definition Unit.cpp:13123
DynObjectList m_dynObj
Definition Unit.h:1926
PositionUpdateInfo _positionUpdateInfo
Definition Unit.h:2064
void SetPvpFlag(UnitPVPStateFlags flags)
Definition Unit.h:896
virtual void UpdateNearbyPlayersInteractions()
Definition Unit.cpp:9340
AuraApplicationList m_interruptableAuras
Definition Unit.h:1948
void SetResistance(SpellSchools school, int32 val)
Definition Unit.h:796
float GetTotalAuraMultiplierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:5157
uint32 GetDisplayId() const
Definition Unit.h:1637
void SendCancelSpellVisualKit(uint32 id)
Definition Unit.cpp:12447
uint32 GetVirtualItemId(uint32 slot) const
Definition Unit.cpp:14505
static float CalculateAverageResistReduction(WorldObject const *caster, SpellSchoolMask schoolMask, Unit const *victim, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:1838
bool IsHighestExclusiveAuraEffect(SpellInfo const *spellInfo, AuraType auraType, SpellEffectValue effectAmount, uint32 auraEffectMask, bool removeOtherAuraApplications=false)
Definition Unit.cpp:14430
void SendSpellDamageImmune(Unit *target, uint32 spellId, bool isPeriodic)
Definition Unit.cpp:5658
void ModifyAuraState(AuraStateType flag, bool apply)
Definition Unit.cpp:6098
bool IsAIEnabled() const
Definition Unit.h:678
Unit * GetUnitBeingMoved() const
Definition Unit.h:1271
EnumFlag< SpellOtherImmunity > GetSpellOtherImmunityMask() const
Definition Unit.cpp:7864
uint32 GetAuraCount(uint32 spellId) const
Definition Unit.cpp:4806
UnitAI * GetTopAI() const
Definition Unit.h:686
void HandleProcExtraAttackFor(Unit *victim, uint32 count)
Definition Unit.cpp:2354
bool isPossessing() const
Definition Unit.cpp:6669
uint32 GetNativeDisplayId() const
Definition Unit.h:1640
float SpellCritChanceTaken(Unit const *caster, Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType=BASE_ATTACK) const
Definition Unit.cpp:7194
void RemoveAllGroupBuffsFromCaster(ObjectGuid casterGUID)
Definition Unit.cpp:4577
virtual void UpdateArmor()=0
void SetChannelObject(uint32 slot, ObjectGuid guid)
Definition Unit.cpp:3051
uint64 GetMaxHealth() const
Definition Unit.h:801
void UpdateCharmAI()
Definition Unit.cpp:10403
void ClearAllReactives()
Definition Unit.cpp:10931
void ApplyControlStatesIfNeeded()
Definition Unit.cpp:11712
void SetRooted(bool apply)
Definition Unit.cpp:11759
ThreatManager m_threatManager
Definition Unit.h:2035
uint32 _oldFactionId
faction before charm
Definition Unit.h:2054
bool Attack(Unit *victim, bool meleeAttack)
Definition Unit.cpp:5872
int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, bool npcCaster) const
Definition Unit.cpp:12512
float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type) const
Definition Unit.cpp:10005
bool IsHovering() const
Definition Unit.h:1166
std::forward_list< Aura * > AuraList
Definition Unit.h:665
float GetTotalAuraMultiplierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:5197
bool HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster=ObjectGuid::Empty) const
Definition Unit.cpp:4792
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4718
bool PopAI()
Definition Unit.cpp:10244
ObjectGuid GetMinionGUID() const
Definition Unit.h:1215
bool SetCanFly(bool enable)
Definition Unit.cpp:13538
virtual float GetDamageMultiplierForTarget(WorldObject const *) const
Definition Unit.h:820
bool SetCollision(bool disable)
Definition Unit.cpp:13729
bool isPossessed() const
Definition Unit.h:1257
uint16 GetMaxSkillValueForLevel(Unit const *target=nullptr) const
Definition Unit.h:947
Unit * m_charmed
Definition Unit.h:1968
virtual void UpdateMaxPower(Powers power)=0
uint64 GetHealth() const
Definition Unit.h:800
void _AddAura(UnitAura *aura, Unit *caster)
Definition Unit.cpp:3468
AttackerSet m_attackers
Definition Unit.h:1917
bool IsSummon() const
Definition Unit.h:761
bool IsInWater() const
Definition Unit.cpp:3349
TransportBase * GetDirectTransport() const
Returns the transport this unit is on directly (if on vehicle and transport, return vehicle)
Definition Unit.cpp:12246
uint32 GetFaction() const override
Definition Unit.h:886
virtual void TextEmote(std::string_view text, WorldObject const *target=nullptr, bool isBossEmote=false)
Definition Unit.cpp:14489
void RemoveDynObject(uint32 spellId)
Definition Unit.cpp:5348
void SendCancelSpellVisual(uint32 id)
Definition Unit.cpp:12429
void SendEnergizeSpellLog(Unit *victim, uint32 spellId, int32 damage, int32 overEnergize, Powers powerType)
Definition Unit.cpp:6804
Unit * m_attacking
Definition Unit.h:1918
bool HasAuraState(AuraStateType flag, SpellInfo const *spellProto=nullptr, Unit const *Caster=nullptr) const
Definition Unit.cpp:6165
void GetDispellableAuraList(WorldObject const *caster, uint32 dispelMask, DispelChargesList &dispelList, bool isReflect=false) const
Definition Unit.cpp:4754
AttackerSet const & getAttackers() const
Definition Unit.h:736
void RemoveUnitFlag2(UnitFlags2 flags)
Definition Unit.h:867
void RemovePvpFlag(UnitPVPStateFlags flags)
Definition Unit.h:897
void SetAI(UnitAI *newAI)
Definition Unit.cpp:10238
AuraEffect * GetAuraEffectOfRankedSpell(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition Unit.cpp:4636
void SendTeleportPacket(TeleportLocation const &teleportLocation)
Definition Unit.cpp:13073
float GetMechanicResistChance(SpellInfo const *spellInfo) const
Definition Unit.cpp:2571
bool SetCanTurnWhileFalling(bool enable)
Definition Unit.cpp:13955
std::multimap< uint32, Aura * > AuraMap
Definition Unit.h:653
float GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:5087
bool IsVisible() const
Definition Unit.cpp:8782
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4832
void RemoveInertia(int32 id)
Definition Unit.cpp:14279
std::unique_ptr< Vignettes::VignetteData > m_vignette
Definition Unit.h:1983
void RemoveOwnedAuras(std::function< bool(Aura const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3932
bool isMoving() const
Definition Unit.h:1820
bool SetWalk(bool enable)
Definition Unit.cpp:13422
float GetUnitBlockChance(WeaponAttackType attType, Unit const *victim) const
Definition Unit.cpp:2832
bool HasStrongerAuraWithDR(SpellInfo const *auraSpellInfo, Unit *caster) const
Definition Unit.cpp:4914
void SendPetActionSound(PetAction action) const
Definition Unit.cpp:10712
void EngageWithTarget(Unit *who)
Definition Unit.cpp:8513
void UpdateCreatureType()
Definition Unit.cpp:9502
void AddInterruptMask(SpellAuraInterruptFlags flags, SpellAuraInterruptFlags2 flags2)
Definition Unit.h:1628
void CalculateMeleeDamage(Unit *victim, CalcDamageInfo *damageInfo, WeaponAttackType attackType=BASE_ATTACK)
Definition Unit.cpp:1332
SpellMissInfo MeleeSpellHitResult(Unit *victim, SpellInfo const *spellInfo) const override
Definition Unit.cpp:2610
void setAttackTimer(WeaponAttackType type, uint32 time)
Definition Unit.h:710
virtual bool UpdateStats(Stats stat)=0
bool IsImmunedToSpell(SpellInfo const *spellInfo, uint32 effectMask, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7742
void RemoveAllDynObjects()
Definition Unit.cpp:5363
void ClearValuesChangesMask() override
Definition Unit.cpp:14391
bool HasNpcFlag(NPCFlags flags) const
Definition Unit.h:1011
void GetAllMinionsByEntry(std::list< TempSummon * > &Minions, uint32 entry)
Definition Unit.cpp:6439
uint32 GetArmor() const
Definition Unit.h:786
float m_modMeleeHitChance
Definition Unit.h:1537
virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType, AuraEffect const *) const
Definition Unit.h:1562
void RemoveArenaAuras()
Definition Unit.cpp:4447
void _RemoveAllAuraStatMods()
Definition Unit.cpp:4610
ObjectGuid GetCritterGUID() const
Definition Unit.h:1219
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, uint16 num=1)
Definition Unit.cpp:4008
uint8 GetLevelForTarget(WorldObject const *) const override
Definition Unit.h:771
void SetFullPower(Powers power)
Definition Unit.h:837
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition Unit.cpp:4259
void SetMovementAnimKitId(uint16 animKitId)
Definition Unit.cpp:11277
void StopAttackFaction(uint32 faction_id)
Definition Unit.cpp:13207
bool HasScheduledAIChange() const
Definition Unit.cpp:10293
void RemoveAreaAurasDueToLeaveWorld()
Definition Unit.cpp:4367
float GetAPMultiplier(WeaponAttackType attType, bool normalized) const
Definition Unit.cpp:11122
bool CanModifyStats() const
Definition Unit.h:1574
float GetUnitCriticalChanceDone(WeaponAttackType attackType) const
Definition Unit.cpp:2863
void RemoveCharmedBy(Unit *charmer)
Definition Unit.cpp:12033
void RemoveMovementForce(ObjectGuid id)
Definition Unit.cpp:14163
bool IsMounted() const
Definition Unit.h:927
Trinity::Containers::FlatSet< AuraApplication *, VisibleAuraSlotCompare > m_visibleAurasToUpdate
Definition Unit.h:1960
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:9570
void SetMaxHealth(uint64 val)
Definition Unit.cpp:10072
float GetMaxNegativeAuraModifier(AuraType auraType) const
Definition Unit.cpp:5102
float GetSpeedRate(UnitMoveType mtype) const
Definition Unit.h:1734
std::set< Unit * > AttackerSet
Definition Unit.h:649
virtual void SetTarget(ObjectGuid const &)=0
void RemoveAppliedAuras(std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3919
float GetTotalAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:5147
virtual uint32 GetPowerIndex(Powers power) const =0
void CleanupBeforeRemoveFromMap(bool finalCleanup)
Definition Unit.cpp:10367
bool IsGuardian() const
Definition Unit.h:762
void UpdateStatBuffModForClient(Stats stat)
Definition Unit.cpp:5300
Unit * GetVictim() const
Definition Unit.h:738
void UpdatePetCombatState()
Definition Unit.cpp:9301
std::vector< Unit * > UnitVector
Definition Unit.h:651
UF::UpdateField< UF::UnitData, int32(WowCS::EntityFragment::CGObject), TYPEID_UNIT > m_unitData
Definition Unit.h:1897
int32 GetPower(Powers power) const
Definition Unit.cpp:10096
void RemoveWorldEffect(int32 worldEffectId)
Definition Unit.cpp:14711
int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:7602
float GetTotalAttackPowerValue(WeaponAttackType attType, bool includeWeapon=true) const
Definition Unit.cpp:9975
void UpdateOrientation(float orientation)
Only server-side orientation update, does not broadcast to client.
Definition Unit.cpp:13179
bool IsUnderWater() const
Definition Unit.cpp:3354
void SetBattlePetCompanionGUID(ObjectGuid guid)
Definition Unit.h:1222
void SetSpeedRate(UnitMoveType mtype, float rate)
Definition Unit.cpp:8961
void AddExtraAttacks(uint32 count)
Definition Unit.cpp:2363
void RemovePlayerFromVision(Player *player)
Definition Unit.cpp:6740
void SendFlightSplineSyncUpdate()
Definition Unit.cpp:643
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
Definition Unit.cpp:7874
float GetCreateStat(Stats stat) const
Definition Unit.cpp:5312
bool IsImmunedToAuraPeriodicTick(WorldObject const *caster, AuraEffect const *auraEffect) const
Definition Unit.cpp:8005
bool IsHighestExclusiveAura(Aura const *aura, bool removeOtherAuraApplications=false)
Definition Unit.cpp:14421
void GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer &aurasTriggeringProc, AuraApplicationList *procAuras, ProcEventInfo &eventInfo)
Definition Unit.cpp:10591
void UpdateSplinePosition()
Definition Unit.cpp:619
AreaTriggerRemoveReason
Definition Unit.h:1668
void SetOwnerGUID(ObjectGuid owner)
Definition Unit.cpp:6190
DeathState getDeathState() const
Definition Unit.h:1208
bool SetIgnoreMovementForces(bool ignore)
Definition Unit.cpp:14191
Unit * GetFirstControlled() const
Definition Unit.cpp:6618
float GetTotalAuraMultiplierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition Unit.cpp:5117
ObjectGuid GetTransGUID() const override
Definition Unit.cpp:12236
bool m_aiLocked
Definition Unit.h:2042
void ApplyCastTimePercentMod(float val, bool apply)
Definition Unit.cpp:11060
std::vector< DynamicObject * > GetDynObjects(uint32 spellId) const
Definition Unit.cpp:5338
bool HealthAbovePct(float pct) const
Definition Unit.h:806
virtual float GetHealthMultiplierForTarget(WorldObject const *) const
Definition Unit.h:819
bool IsCritter() const
Definition Unit.h:1040
void DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
Definition Unit.cpp:1534
bool HealthBelowPct(float pct) const
Definition Unit.h:804
float GetAttackPowerModifierValue(AttackPowerModIndex index, AttackPowerModType modifierType) const
Definition Unit.cpp:9790
uint16 _movementAnimKitId
Definition Unit.h:2058
void NearTeleportTo(TeleportLocation const &target, bool casting=false)
Definition Unit.cpp:13054
bool CreateVehicleKit(uint32 id, uint32 creatureEntry, bool loading=false)
Definition Unit.cpp:12169
bool HasUnitState(const uint32 f) const
Definition Unit.h:755
bool IsMagnet() const
Definition Unit.cpp:6592
std::unordered_set< AbstractFollower * > m_followingMe
Definition Unit.h:2044
virtual void Update(uint32 time) override
Definition Unit.cpp:428
bool IsInRaidWith(Unit const *unit) const
Definition Unit.cpp:12272
void UnsummonAllTotems()
Definition Unit.cpp:6763
AuraApplication * _CreateAuraApplication(Aura *aura, uint32 effMask)
Definition Unit.cpp:3507
uint16 _meleeAnimKitId
Definition Unit.h:2059
void _UnregisterAreaTrigger(AreaTrigger *areaTrigger)
Definition Unit.cpp:5481
GameObjectList m_gameObj
Definition Unit.h:1930
int32 SpellDamageBonusTaken(Unit *caster, SpellInfo const *spellProto, int32 pdamage, DamageEffectType damagetype) const
Definition Unit.cpp:7013
AuraMap m_ownedAuras
Definition Unit.h:1940
void ProcessPositionDataChanged(PositionFullTerrainStatus const &data) override
Definition Unit.cpp:3364
Unit(bool isWorldObject)
Definition Unit.cpp:309
bool IsInFeralForm() const
Definition Unit.cpp:9559
DynamicObject * GetDynObject(uint32 spellId) const
Definition Unit.cpp:5332
void SetLevel(uint8 lvl, bool sendUpdate=true)
Definition Unit.cpp:10019
std::unique_ptr< Movement::MoveSpline > movespline
Definition Unit.h:1854
static uint32 SpellCriticalDamageBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition Unit.cpp:7299
void CalculateHoverHeight()
Definition Unit.cpp:14339
std::pair< AuraMap::iterator, AuraMap::iterator > AuraMapBoundsNonConst
Definition Unit.h:655
static std::vector< AuraEffect * > CopyAuraEffectList(AuraEffectList const &list)
Definition Unit.cpp:818
void RemoveBindSightAuras()
Definition Unit.cpp:6750
std::array< float, ADV_FLYING_MAX_SPEED_TYPE > m_advFlyingSpeed
Definition Unit.h:1963
void KnockbackFrom(Position const &origin, float speedXY, float speedZ, float angle=M_PI, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
Definition Unit.cpp:12587
void SendPlaySpellVisualKit(uint32 id, uint32 type, uint32 duration) const
Definition Unit.cpp:12437
AuraApplicationMap m_appliedAuras
Definition Unit.h:1941
CharmInfo * InitCharmInfo()
Definition Unit.cpp:10447
void RemoveAllAttackers()
Definition Unit.cpp:6085
int32 SpellBaseAbsorbBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:7640
void SetClass(uint8 classId)
Definition Unit.h:777
void SetFacingTo(float ori, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13385
virtual bool CanSwim() const
Definition Unit.cpp:13040
virtual float GetNativeObjectScale() const
Definition Unit.h:1635
uint32 GetDoTsByCaster(ObjectGuid casterGUID) const
Definition Unit.cpp:4978
void RemoveFromWorld() override
Definition Unit.cpp:10309
void AttackerStateUpdate(Unit *victim, WeaponAttackType attType=BASE_ATTACK, bool extra=false)
Definition Unit.cpp:2251
bool IsOnOceanFloor() const
Definition Unit.cpp:3359
bool HasUnitMovementFlag(MovementFlags f) const
Definition Unit.h:1761
void ScheduleAIChange()
Definition Unit.cpp:10264
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4822
Powers CalculateDisplayPowerType() const
Definition Unit.cpp:5781
virtual void UpdateMaxHealth()=0
uint32 HasUnitTypeMask(uint32 mask) const
Definition Unit.h:759
std::array< float, MAX_MOVE_TYPE > m_speed_rate
Definition Unit.h:1962
float GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const
Definition Unit.cpp:9684
void _RegisterAuraEffect(AuraEffect *aurEff, bool apply)
Definition Unit.cpp:3753
void SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo)
Definition Unit.cpp:5621
void _EnterVehicle(Vehicle *vehicle, int8 seatId, AuraApplication const *aurApp=nullptr)
Definition Unit.cpp:12852
float GetMeleeRange(Unit const *target) const
Definition Unit.cpp:706
bool isDying() const
Definition Unit.h:1206
void DoMeleeAttackIfReady()
Definition Unit.cpp:2166
float GetStat(Stats stat) const
Definition Unit.h:784
void RemoveAurasWithMechanic(uint64 mechanicMaskToRemove, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, uint32 exceptSpellId=0, bool withEffectMechanics=false)
Definition Unit.cpp:4320
void SendDurabilityLoss(Player *receiver, uint32 percent)
Definition Unit.cpp:11239
int32 SpellAbsorbBonusDone(Unit *victim, SpellInfo const *spellProto, int32 absorbamount, SpellEffectInfo const &spellEffectInfo, uint32 stack=1, AuraEffect const *aurEff=nullptr) const
Definition Unit.cpp:7645
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:8040
virtual float GetBlockPercent(uint8) const
Definition Unit.h:1003
void RemoveAllAuras()
Definition Unit.cpp:4400
SpellHistory * GetSpellHistory()
Definition Unit.h:1521
std::array< float, MAX_ATTACK > m_modAttackSpeedPct
Definition Unit.h:1543
bool IsBlockCritical() const
Definition Unit.cpp:2564
void HandleEmoteCommand(Emote emoteId, Player *target=nullptr, Trinity::IteratorPair< int32 const * > spellVisualKitIds={}, int32 sequenceVariation=0)
Definition Unit.cpp:1662
bool IsControlledByPlayer() const
Definition Unit.h:1234
Unit * m_charmer
Definition Unit.h:1967
void SetVisibleAura(AuraApplication *aurApp)
Definition Unit.cpp:722
DiminishingLevels GetDiminishing(DiminishingGroup group) const
Definition Unit.cpp:9350
bool m_canDualWield
Definition Unit.h:727
bool HasBreakableByDamageCrowdControlAura(Unit const *excludeCasterChannel=nullptr) const
Definition Unit.cpp:783
ObjectGuid GetCharmerGUID() const
Definition Unit.h:1228
void UpdateLiquidStatusOnPositionChange(Optional< LiquidData > const &newLiquidData)
Definition Unit.cpp:3371
bool HasAuraWithMechanic(uint64 mechanicMask) const
Definition Unit.cpp:4897
Minion * GetFirstMinion() const
Definition Unit.cpp:6234
UnitStandStateType GetStandState() const
Definition Unit.h:915
float SpellHealingPctDone(Unit *victim, SpellInfo const *spellProto) const
Definition Unit.cpp:7459
UnitAI * GetScheduledChangeAI()
Definition Unit.cpp:10285
uint16 _aiAnimKitId
Definition Unit.h:2057
bool HasAuraTypeWithValue(AuraType auraType, int32 value) const
Definition Unit.cpp:4863
void DestroyForPlayer(Player const *target) const override
Definition Unit.cpp:14376
bool HasBreakableByDamageAuraType(AuraType type, uint32 excludeAura=0) const
Definition Unit.cpp:774
bool SetCharmedBy(Unit *charmer, CharmType type, AuraApplication const *aurApp=nullptr)
Definition Unit.cpp:11859
bool IsAlwaysVisibleFor(WorldObject const *seer) const override
Definition Unit.cpp:8751
void SetPetGUID(ObjectGuid guid)
Definition Unit.h:1218
bool SetWaterWalking(bool enable)
Definition Unit.cpp:13581
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:10636
void SetMaxPower(Powers power, int32 val)
Definition Unit.cpp:10151
void ApplyInertia(int32 id, Milliseconds duration)
Definition Unit.cpp:14254
void RemoveAllAreaTriggers(AreaTriggerRemoveReason reason=AreaTriggerRemoveReason::Default)
Definition Unit.cpp:5531
std::vector< std::pair< uint32, AuraApplication * > > AuraApplicationProcContainer
Definition Unit.h:669
virtual void setDeathState(DeathState s)
Definition Unit.cpp:9180
void SetCreatorGUID(ObjectGuid creator)
Definition Unit.h:1214
void GetPartyMembers(std::list< Unit * > &units)
Definition Unit.cpp:12291
virtual void AtEngage(Unit *target)
Definition Unit.cpp:9277
void RemoveVehicleKit(bool onRemoveFromWorld=false)
Definition Unit.cpp:12185
ObjectGuid LastCharmerGUID
Definition Unit.h:1795
uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const
Definition Unit.cpp:12629
UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const *target) const override
Definition Unit.cpp:14363
float GetUnitDodgeChance(WeaponAttackType attType, Unit const *victim) const
Definition Unit.cpp:2749
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:1680
void HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
Definition Unit.cpp:9618
CombatManager & GetCombatManager()
Definition Unit.h:1053
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:861
MeleeHitOutcome RollMeleeOutcomeAgainst(Unit const *victim, WeaponAttackType attType) const
Definition Unit.cpp:2378
void UpdateMovementForcesModMagnitude()
Definition Unit.cpp:14222
uint32 GetCreatureTypeMask() const
Definition Unit.cpp:9496
bool InitTamedPet(Pet *pet, uint8 level, uint32 spell_id)
Definition Unit.cpp:11202
bool HasAuraTypeWithTriggerSpell(AuraType auratype, uint32 triggerSpell) const
Definition Unit.cpp:4872
bool HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4854
bool IsFlying() const
Definition Unit.h:1823
void SetCritterGUID(ObjectGuid guid)
Definition Unit.h:1220
AuraApplicationMap & GetAppliedAuras()
Definition Unit.h:1315
void ClearBossEmotes(Optional< uint32 > zoneId={}, Player const *target=nullptr) const
Clears boss emotes frame.
Definition Unit.cpp:14579
void RemoveMovementImpairingAuras(bool withRoot)
Definition Unit.cpp:4312
bool isAttackReady(WeaponAttackType type=BASE_ATTACK) const
Definition Unit.h:713
void SetVignette(uint32 vignetteId)
Definition Unit.cpp:14723
void InitStatBuffMods()
Definition Unit.cpp:5227
int32 m_procDeep
Definition Unit.h:1922
void ClearDiminishings()
Definition Unit.cpp:9472
bool ApplyDiminishingToDuration(SpellInfo const *auraSpellInfo, int32 &duration, WorldObject *caster, DiminishingLevels previousLevel) const
Definition Unit.cpp:9374
bool IsUninteractible() const
Definition Unit.h:1067
std::vector< AreaTrigger * > GetAreaTriggers(uint32 spellId) const
Definition Unit.cpp:5494
std::vector< GameObject * > GetGameObjects(uint32 spellId) const
Definition Unit.cpp:5375
std::array< uint32, MAX_ATTACK > m_attackTimer
Definition Unit.h:1544
bool IsServiceProvider() const
Definition Unit.cpp:8504
MountCapabilityEntry const * GetMountCapability(uint32 mountType) const
Definition Unit.cpp:8381
void SetVisibleAuraUpdate(AuraApplication *aurApp)
Definition Unit.cpp:736
bool IsTotem() const
Definition Unit.h:765
CombatManager m_combatManager
Definition Unit.h:2033
void ChangeSeat(int8 seatId, bool next=true)
Definition Unit.cpp:12899
void SetInFront(WorldObject const *target)
Definition Unit.cpp:13379
void ApplyDiminishingAura(DiminishingGroup group, bool apply)
Definition Unit.cpp:9455
AuraStateAurasMap m_auraStateAuras
Definition Unit.h:1949
int32 GetResistance(SpellSchools school) const
Definition Unit.h:793
AuraList & GetSingleCastAuras()
Definition Unit.h:1364
bool IsAlwaysDetectableFor(WorldObject const *seer) const override
Definition Unit.cpp:8771
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition Unit.cpp:4664
Vehicle * GetVehicleKit() const
Definition Unit.h:1798
bool CanCastSpellWhileMoving(SpellInfo const *spellInfo) const
Definition Unit.cpp:3300
void PushAI(UnitAI *newAI)
Definition Unit.cpp:10233
float m_modSpellHitChance
Definition Unit.h:1539
void ValidateAttackersAndOwnTarget()
Definition Unit.cpp:6013
Guardian * GetGuardianPet() const
Definition Unit.cpp:6250
void resetAttackTimer(WeaponAttackType type=BASE_ATTACK)
Definition Unit.cpp:670
Aura * GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4748
virtual void Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const *target)
Definition Unit.cpp:14471
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:5589
virtual bool IsEngaged() const
Definition Unit.h:1049
bool SetDisableGravity(bool disable, bool updateAnimTier=true, bool updatePlayHoverAnim=true)
Definition Unit.cpp:13440
void RemoveAurasWithFamily(SpellFamilyNames family, flag128 const &familyFlag, ObjectGuid casterGUID)
Definition Unit.cpp:4294
void _ApplyAuraEffect(Aura *aura, uint8 effIndex)
Definition Unit.cpp:3549
void DeMorph()
Definition Unit.cpp:3400
void RemoveAllMinionsByEntry(uint32 entry)
Definition Unit.cpp:6449
void SendPetActionFeedback(PetActionFeedback msg, uint32 spellId) const
-------—Pet responses methods--------------—
Definition Unit.cpp:10700
AuraMap & GetOwnedAuras()
Definition Unit.h:1305
void UpdateAllDamagePctDoneMods()
Definition Unit.cpp:9878
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:7103
virtual void Whisper(std::string_view text, Language language, Player *target, bool isBossWhisper=false)
Definition Unit.cpp:14494
void ClearChannelObjects()
Definition Unit.cpp:3063
bool IsFalling() const
Definition Unit.cpp:13035
bool AttackStop()
Definition Unit.cpp:5984
std::array< float, MAX_STATS > m_floatStatNegBuff
Definition Unit.h:1915
int32 GetCurrentSpellCastTime(uint32 spell_id) const
Definition Unit.cpp:3276
float MeleeSpellMissChance(Unit const *victim, WeaponAttackType attType, SpellInfo const *spellInfo) const override
Definition Unit.cpp:12523
void RemoveAurasOnEvade()
Definition Unit.cpp:4461
void SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
Definition Unit.cpp:9666
float SpellAbsorbPctDone(Unit *victim, SpellInfo const *spellProto) const
Definition Unit.cpp:7711
void SetShapeshiftForm(ShapeshiftForm form)
Definition Unit.cpp:9521
float GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const *victim) const
Definition Unit.cpp:2929
bool IsInPartyWith(Unit const *unit) const
Definition Unit.cpp:12253
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3992
static void Kill(Unit *attacker, Unit *victim, bool durabilityLoss=true, bool skipSettingDeathState=false)
Definition Unit.cpp:11311
bool m_cleanupDone
Definition Unit.h:2050
SharedVisionList m_sharedVision
Definition Unit.h:1970
void SetMeleeAnimKitId(uint16 animKitId)
Definition Unit.cpp:11294
float GetMaxPositiveAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:5167
void SendMeleeAttackStop(Unit const *victim=nullptr) const
Definition Unit.cpp:2550
EnumFlag< SpellAuraInterruptFlags > m_interruptMask
Definition Unit.h:1950
std::array< AuraEffectList, TOTAL_AURAS > m_modAuras
Definition Unit.h:1946
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:7347
ObjectGuid GetTarget() const
Definition Unit.h:1847
bool _isWalkingBeforeCharm
Are we walking before we were charmed?
Definition Unit.h:2055
void SetPowerType(Powers power, bool sendUpdate=true, bool onInit=false)
Definition Unit.cpp:5716
uint8 GetLevel() const
Definition Unit.h:769
void SetMountDisplayId(uint32 mountDisplayId)
Definition Unit.h:929
uint8 GetRace() const
Definition Unit.h:773
void RemoveNotOwnSingleTargetAuras(bool onPhaseChange=false)
Definition Unit.cpp:4177
virtual void SetDisplayId(uint32 displayId, bool setNative=false)
Definition Unit.cpp:10852
void TriggerAuraHeartbeat()
Definition Unit.cpp:522
void RemoveCharmAuras()
Definition Unit.cpp:6755
bool IsInCombat() const
Definition Unit.h:1073
bool IsWalking() const
Definition Unit.h:1165
void SetWildBattlePetLevel(uint32 wildBattlePetLevel)
Definition Unit.h:1291
bool IsSitState() const
Definition Unit.cpp:10789
void RemoveVisibleAuraUpdate(AuraApplication *aurApp)
Definition Unit.cpp:741
GetCastSpellInfoResult GetCastSpellInfo(SpellInfo const *spellInfo) const
Definition Unit.h:1503
uint32 GetModelForForm(ShapeshiftForm form, uint32 spellId) const
Definition Unit.cpp:12635
void AddWorldEffect(int32 worldEffectId)
Definition Unit.cpp:14706
void RemoveUnitFlag(UnitFlags flags)
Definition Unit.h:862
void SetAIAnimKitId(uint16 animKitId)
Definition Unit.cpp:11260
void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath=false, bool forceDestination=false)
Definition Unit.cpp:538
uint16 GetVirtualItemAppearanceMod(uint32 slot) const
Definition Unit.cpp:14513
Unit * GetDemonCreator() const
Definition Unit.cpp:6211
Player * m_playerMovingMe
Definition Unit.h:1966
void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject *stealer, int32 stolenCharges=1)
Definition Unit.cpp:4053
AreaTrigger * GetAreaTrigger(uint32 spellId) const
Definition Unit.cpp:5488
uint32 GetDamageImmunityMask() const
Definition Unit.cpp:7844
Player * GetControllingPlayer() const
Definition Unit.cpp:6221
float GetWeaponProcChance() const
Definition Unit.cpp:8278
Aura * _TryStackingOrRefreshingExistingAura(AuraCreateInfo &createInfo)
Definition Unit.cpp:3405
ObjectGuid GetPetGUID() const
Definition Unit.h:1217
void RemoveChannelObject(ObjectGuid guid)
Definition Unit.cpp:3056
void RemoveAurasWithAttribute(SpellAttr0 flags)
Definition Unit.cpp:4165
void UpdateStatBuffMod(Stats stat)
Definition Unit.cpp:5237
virtual void ExitVehicle(Position const *exitPosition=nullptr)
Definition Unit.cpp:12931
void SendPetDismissSound() const
Definition Unit.cpp:10720
float m_auraPctModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_PCT_END]
Definition Unit.h:1954
void CombatStopWithPets(bool includingCast=false)
Definition Unit.cpp:6059
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition Unit.h:1490
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:1000
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:983
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:474
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition Object.cpp:1099
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:709
void AddToWorld() override
Definition Object.cpp:363
virtual bool IsAlwaysVisibleFor(WorldObject const *seer) const
Definition Object.h:606
Unit * GetCharmerOrOwner() const
Definition Object.cpp:1608
void RemoveFromWorld() override
Definition Object.cpp:369
InstanceScript * GetInstanceScript() const
Definition Object.cpp:394
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
Definition Object.cpp:1996
Unit * GetCharmerOrOwnerOrSelf() const
Definition Object.cpp:1618
void SendCombatLogMessage(WorldPackets::CombatLog::CombatLogServerPacket *combatLog) const
Definition Object.cpp:1138
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2222
std::string GetDebugInfo() const override
Definition Object.cpp:3139
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2329
virtual bool IsAlwaysDetectableFor(WorldObject const *seer) const
Definition Object.h:609
bool IsHostileTo(WorldObject const *target) const
Definition Object.cpp:2186
PhaseShift & GetPhaseShift()
Definition Object.h:310
Unit * GetOwner() const
Definition Object.cpp:1603
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:1947
void setActive(bool isActiveObject)
Definition Object.cpp:274
float GetFloorZ() const
Definition Object.cpp:3109
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:533
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const &data)
Definition Object.cpp:351
Player * GetSpellModOwner() const
Definition Object.cpp:1646
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition Object.cpp:1626
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:499
void SetIsStoredInWorldObjectGridContainer(bool apply)
Definition Object.cpp:255
void AddToNotify(uint16 f)
Definition Object.h:519
EventProcessor m_Events
Definition Object.h:561
float GetVisibilityRange() const
Definition Object.cpp:785
virtual uint32 GetCastSpellXSpellVisualId(SpellInfo const *spellInfo) const
Definition Object.cpp:2637
float GetDistance(WorldObject const *obj) const
Definition Object.cpp:430
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:2191
bool IsInMap(WorldObject const *obj) const
Definition Object.cpp:467
virtual void Update(uint32 diff)
Definition Object.cpp:243
FactionTemplateEntry const * GetFactionTemplateEntry() const
Definition Object.cpp:2005
virtual void UpdateObjectVisibility(bool forced=true)
Definition Object.cpp:3050
virtual void CleanupsBeforeDelete(bool finalCleanup=true)
Definition Object.cpp:333
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
Duration< Milliseconds, uint32 > LifetimeMs
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
Duration< Milliseconds, uint32 > LifetimeMs
WorldPacket const * Write() override
std::span< MovementForce 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
TaggedPosition< Position::XYZ > ModelPosition
Definition PetPackets.h:270
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:919
@ CONFIG_CREATURE_FAMILY_FLEE_DELAY
Definition World.h:313
@ CONFIG_EXPANSION
Definition World.h:306
@ RATE_POWER_RAGE_INCOME
Definition World.h:454
@ RATE_DURABILITY_LOSS_DAMAGE
Definition World.h:524
@ RATE_DURABILITY_LOSS_ON_DEATH
Definition World.h:523
@ CONFIG_LISTEN_RANGE_YELL
Definition World.h:212
@ CONFIG_LISTEN_RANGE_SAY
Definition World.h:210
@ CONFIG_LISTEN_RANGE_TEXTEMOTE
Definition World.h:211
@ 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 std::string MovementFlags_ToString(MovementFlags flags)
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:558
ProcFlagsInit ProcAttacker
Definition Unit.h:559
uint32 DamageSchoolMask
Definition Unit.h:547
Unit * Target
Definition Unit.h:546
uint32 TargetState
Definition Unit.h:554
MeleeHitOutcome HitOutCome
Definition Unit.h:562
Unit * Attacker
Definition Unit.h:545
uint32 Damage
Definition Unit.h:548
uint32 RageGained
Definition Unit.h:555
uint32 Blocked
Definition Unit.h:552
uint32 Resist
Definition Unit.h:551
uint32 CleanDamage
Definition Unit.h:561
uint32 HitInfo
Definition Unit.h:553
uint32 Absorb
Definition Unit.h:550
uint32 OriginalDamage
Definition Unit.h:549
ProcFlagsInit ProcVictim
Definition Unit.h:560
CastSpellExtraArgs & AddSpellMod(SpellValueMod mod, int32 val)
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius)
Definition CellImpl.h:150
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius)
Definition CellImpl.h:160
void SaveStayPosition()
Definition Unit.cpp:13328
float _stayY
Definition CharmInfo.h:151
void SetIsCommandFollow(bool val)
Definition Unit.cpp:13318
bool IsCommandAttack()
Definition Unit.cpp:13313
bool _isAtStay
Definition CharmInfo.h:147
void InitPossessCreateSpells()
Definition CharmInfo.cpp:74
void SetIsAtStay(bool val)
Definition Unit.cpp:13349
bool IsFollowing()
Definition Unit.cpp:13364
float _stayX
Definition CharmInfo.h:150
void SetPetNumber(uint32 petnumber, bool statwindow)
float _stayZ
Definition CharmInfo.h:152
bool IsReturning()
Definition Unit.cpp:13374
void SetIsFollowing(bool val)
Definition Unit.cpp:13359
bool _isCommandFollow
Definition CharmInfo.h:146
void SetIsReturning(bool val)
Definition Unit.cpp:13369
void InitCharmCreateSpells()
bool IsAtStay()
Definition Unit.cpp:13354
bool _isFollowing
Definition CharmInfo.h:148
bool _isCommandAttack
Definition CharmInfo.h:145
void GetStayPosition(float &x, float &y, float &z)
Definition Unit.cpp:13342
bool IsCommandFollow()
Definition Unit.cpp:13323
void SetIsCommandAttack(bool val)
Definition Unit.cpp:13308
bool _isReturning
Definition CharmInfo.h:149
Unit * _unit
Definition CharmInfo.h:136
EnumFlag< ChrRacesFlag > GetFlags() const
uint32 absorbed_damage
Definition Unit.h:425
WeaponAttackType attackType
Definition Unit.h:428
EnumFlag< CreatureModelDataFlags > GetFlags() const
uint32 CreatureDisplayID
DeclinedName()=default
uint32 hitCount
Definition Unit.h:395
uint32 hitTime
Definition Unit.h:394
uint16 stack
Definition Unit.h:393
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
bool HasMovementFlag(MovementFlags flag) const
ObjectGuid guid
Optional< Inertia > inertia
void RemoveMovementFlag(MovementFlags flag)
void SetFallTime(uint32 fallTime)
struct MovementInfo::TransportInfo transport
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:572
uint32 preHitHealth
Definition Unit.h:587
SpellCastVisual SpellVisual
Definition Unit.h:574
Unit * attacker
Definition Unit.h:571
uint32 schoolMask
Definition Unit.h:577
SpellInfo const * Spell
Definition Unit.h:573
uint32 cleanDamage
Definition Unit.h:585
uint32 originalDamage
Definition Unit.h:576
uint32 reflectingSpellId
Definition Unit.h:582
AuraEffect const * auraEff
Definition Unit.h:595
EnumFlag< SpellShapeshiftFormFlags > GetFlags() const
EnumFlag< SummonPropertiesFlags > GetFlags() const
WorldLocation Location
Definition Player.h:1210
Optional< ObjectGuid > TransportGuid
Definition Player.h:1211
std::array< T, N > RawValue
Definition RaceMask.h:95
static constexpr RaceMask GetMaskForRace(uint32 raceId)
Definition RaceMask.h:156
UpdateFieldArray< std::string, 5, 0, 1 > Name
UpdateField< uint32, 32, 52 > AuraState
UpdateFieldArray< int32, 5, 187, 193 > StatPosBuff
UpdateField< int64, 32, 38 > Health
UpdateField< int32, 32, 59 > NativeDisplayID
UpdateField< uint32, 128, 134 > CurrentAreaID
UpdateField< int32, 32, 40 > Level
UpdateField< float, 64, 81 > ModHasteRegen
DynamicUpdateField< int32, 0, 4 > WorldEffects
UpdateField< float, 64, 78 > ModSpellHaste
UpdateFieldArray< uint32, 2, 184, 185 > AttackRoundBaseTime
DynamicUpdateField< ObjectGuid, 0, 5 > ChannelObjects
UpdateField< uint8, 64, 90 > ShapeshiftForm
UpdateField< uint8, 64, 71 > AnimTier
UpdateField< ObjectGuid, 0, 18 > SummonedBy
UpdateField< float, 64, 80 > ModRangedHaste
UpdateField< uint8, 64, 87 > SheatheState
UpdateField< float, 32, 60 > NativeXDisplayScale
UpdateField< float, 32, 56 > DisplayScale
UpdateFieldArray< int32, 10, 139, 140 > Power
UpdateField< uint8, 64, 68 > StandState
UpdateField< ObjectGuid, 0, 17 > CharmedBy
UpdateField< float, 64, 79 > ModHaste
UpdateField< uint8, 32, 35 > CreatureType
UpdateFieldArray< int32, 10, 139, 150 > MaxPower
UpdateField< uint8, 32, 36 > DisplayPower
UpdateField< int64, 32, 39 > MaxHealth
UpdateField< uint32, 0, 8 > NpcFlags2
UpdateField< int32, 0, 6 > DisplayID
UpdateField< uint32, 32, 53 > RangedAttackRoundBaseTime
UpdateFieldArray< int32, 5, 187, 198 > StatNegBuff
UpdateField< int32, 96, 127 > FlightCapabilityID
UpdateFieldArray< UF::VisibleItem, 3, 180, 181 > VirtualItems
UpdateField< ObjectGuid, 0, 14 > Charm
UpdateField< float, 64, 77 > ModCastingSpeedNeg
UpdateField< uint32, 0, 7 > NpcFlags
UpdateField< float, 64, 76 > ModCastingSpeed
UpdateField< uint16, 0, 7 > ItemVisual
UpdateField< int32, 0, 3 > ItemID
UpdateField< uint16, 0, 6 > ItemAppearanceModID
std::array< uint32, 5 > VisitedSpells
Definition Unit.h:1495
bool AddSpell(uint32 spellId)
Definition Unit.cpp:14595
bool operator()(AuraApplication *left, AuraApplication *right) const
Definition Unit.cpp:14674
VehicleExitParameters ExitParameter
Optional< Spells::ContentTuningParams > ContentTuning
void Add(EntityFragment fragment, bool update, void const *data=nullptr)