TrinityCore
Unit.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Unit.h"
19#include "AbstractFollower.h"
20#include "Battlefield.h"
21#include "BattlefieldMgr.h"
22#include "Battleground.h"
23#include "BattlegroundPackets.h"
24#include "BattlegroundScore.h"
25#include "BattlePetMgr.h"
26#include "CellImpl.h"
27#include "CharacterCache.h"
28#include "CharmInfo.h"
29#include "ChatPackets.h"
30#include "ChatTextBuilder.h"
31#include "CombatLogPackets.h"
32#include "CombatPackets.h"
33#include "Common.h"
34#include "ConditionMgr.h"
35#include "Containers.h"
36#include "Creature.h"
37#include "CreatureAI.h"
38#include "CreatureAIImpl.h"
39#include "CreatureAIFactory.h"
40#include "CreatureGroups.h"
41#include "DB2Stores.h"
42#include "Formulas.h"
43#include "GameObjectAI.h"
44#include "GameTime.h"
45#include "GridNotifiersImpl.h"
46#include "Group.h"
47#include "InstanceScript.h"
48#include "Item.h"
49#include "ItemBonusMgr.h"
50#include "KillRewarder.h"
51#include "ListUtils.h"
52#include "Log.h"
53#include "Loot.h"
54#include "LootMgr.h"
55#include "LootPackets.h"
56#include "MiscPackets.h"
57#include "MotionMaster.h"
58#include "MovementGenerator.h"
59#include "MovementPackets.h"
60#include "MoveSpline.h"
61#include "MoveSplineInit.h"
62#include "ObjectAccessor.h"
63#include "ObjectMgr.h"
64#include "Opcodes.h"
65#include "OutdoorPvP.h"
66#include "PartyPackets.h"
67#include "Pet.h"
68#include "PetPackets.h"
69#include "PhasingHandler.h"
70#include "Player.h"
71#include "PlayerAI.h"
72#include "QuestDef.h"
73#include "Spell.h"
74#include "ScheduledChangeAI.h"
75#include "SpellAuraEffects.h"
76#include "SpellAuras.h"
77#include "SpellHistory.h"
78#include "SpellInfo.h"
79#include "SpellMgr.h"
80#include "SpellPackets.h"
81#include "StringConvert.h"
82#include "TemporarySummon.h"
83#include "Totem.h"
84#include "Transport.h"
85#include "Util.h"
86#include "Vehicle.h"
87#include "VehiclePackets.h"
88#include "Vignette.h"
89#include "VignettePackets.h"
90#include "World.h"
91#include "WorldPacket.h"
92#include "WorldSession.h"
93#include <queue>
94#include <sstream>
95#include <cmath>
96
98{
99 2.5f, // MOVE_WALK
100 7.0f, // MOVE_RUN
101 4.5f, // MOVE_RUN_BACK
102 4.722222f, // MOVE_SWIM
103 2.5f, // MOVE_SWIM_BACK
104 3.141594f, // MOVE_TURN_RATE
105 7.0f, // MOVE_FLIGHT
106 4.5f, // MOVE_FLIGHT_BACK
107 3.14f // MOVE_PITCH_RATE
108};
109
111{
112 2.5f, // MOVE_WALK
113 7.0f, // MOVE_RUN
114 4.5f, // MOVE_RUN_BACK
115 4.722222f, // MOVE_SWIM
116 2.5f, // MOVE_SWIM_BACK
117 3.141594f, // MOVE_TURN_RATE
118 7.0f, // MOVE_FLIGHT
119 4.5f, // MOVE_FLIGHT_BACK
120 3.14f // MOVE_PITCH_RATE
121};
122
123DispelableAura::DispelableAura(Aura* aura, int32 dispelChance, uint8 dispelCharges) :
124 _aura(aura), _chance(dispelChance), _charges(dispelCharges)
125{
126}
127
129
131{
132 return roll_chance_i(_chance);
133}
134
135DamageInfo::DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType)
136 : m_attacker(attacker), m_victim(victim), m_damage(damage), m_originalDamage(damage), m_spellInfo(spellInfo), m_schoolMask(schoolMask), m_damageType(damageType), m_attackType(attackType),
137 m_absorb(0), m_resist(0), m_block(0), m_hitMask(PROC_HIT_NONE)
138{
139}
140
142 : m_attacker(dmgInfo.Attacker), m_victim(dmgInfo.Target), m_damage(dmgInfo.Damage), m_originalDamage(dmgInfo.Damage), m_spellInfo(nullptr), m_schoolMask(SpellSchoolMask(dmgInfo.DamageSchoolMask)),
143 m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.AttackType), m_absorb(dmgInfo.Absorb), m_resist(dmgInfo.Resist), m_block(dmgInfo.Blocked), m_hitMask(PROC_HIT_NONE)
144{
145 switch (dmgInfo.TargetState)
146 {
149 break;
152 break;
153 }
154
157
158 if (dmgInfo.HitInfo & HITINFO_FULL_RESIST)
160
161 if (m_block)
163
164 bool const damageNullified = (dmgInfo.HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 ||
166 switch (dmgInfo.HitOutCome)
167 {
168 case MELEE_HIT_MISS:
170 break;
171 case MELEE_HIT_DODGE:
173 break;
174 case MELEE_HIT_PARRY:
176 break;
177 case MELEE_HIT_EVADE:
179 break;
180 case MELEE_HIT_BLOCK:
183 case MELEE_HIT_NORMAL:
184 if (!damageNullified)
186 break;
187 case MELEE_HIT_CRIT:
188 if (!damageNullified)
190 break;
191 }
192}
193
194DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, ProcFlagsHit hitMask)
195 : m_attacker(spellNonMeleeDamage.attacker), m_victim(spellNonMeleeDamage.target), m_damage(spellNonMeleeDamage.damage), m_originalDamage(spellNonMeleeDamage.originalDamage),
196 m_spellInfo(spellNonMeleeDamage.Spell), m_schoolMask(SpellSchoolMask(spellNonMeleeDamage.schoolMask)), m_damageType(damageType),
197 m_attackType(attackType), m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), m_hitMask(hitMask)
198{
199 if (spellNonMeleeDamage.blocked)
201 if (spellNonMeleeDamage.absorb)
203}
204
206{
207 amount = std::max(amount, -static_cast<int32>(GetDamage()));
208 m_damage += amount;
209}
210
212{
213 amount = std::min(amount, GetDamage());
214 m_absorb += amount;
215 m_damage -= amount;
217}
218
220{
221 amount = std::min(amount, GetDamage());
222 m_resist += amount;
223 m_damage -= amount;
224 if (!m_damage)
225 {
228 }
229}
230
232{
233 amount = std::min(amount, GetDamage());
234 m_block += amount;
235 m_damage -= amount;
237 if (!m_damage)
238 {
241 }
242}
243
245{
246 return m_hitMask;
247}
248
249HealInfo::HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask)
250 : _healer(healer), _target(target), _heal(heal), _originalHeal(heal), _effectiveHeal(0), _absorb(0), _spellInfo(spellInfo), _schoolMask(schoolMask), _hitMask(0)
251{
252}
253
255{
256 amount = std::min(amount, GetHeal());
257 _absorb += amount;
258 _heal -= amount;
259 amount = std::min(amount, GetEffectiveHeal());
260 _effectiveHeal -= amount;
262}
263
265{
266 return _hitMask;
267}
268
269ProcEventInfo::ProcEventInfo(Unit* actor, Unit* actionTarget, Unit* procTarget,
270 ProcFlagsInit const& typeMask, ProcFlagsSpellType spellTypeMask,
271 ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask,
272 Spell* spell, DamageInfo* damageInfo,
273 HealInfo* healInfo) :
274 _actor(actor), _actionTarget(actionTarget), _procTarget(procTarget),
275 _typeMask(typeMask), _spellTypeMask(spellTypeMask),
276 _spellPhaseMask(spellPhaseMask), _hitMask(hitMask), _spell(spell),
277 _damageInfo(damageInfo), _healInfo(healInfo)
278{ }
279
281{
282 if (_spell)
283 return _spell->GetSpellInfo();
284 if (_damageInfo)
285 return _damageInfo->GetSpellInfo();
286 if (_healInfo)
287 return _healInfo->GetSpellInfo();
288 return nullptr;
289}
290
292{
293 if (_spell)
294 return _spell->GetSpellInfo()->GetSchoolMask();
295 if (_damageInfo)
296 return _damageInfo->GetSchoolMask();
297 if (_healInfo)
298 return _healInfo->GetSchoolMask();
300}
301
302SpellNonMeleeDamage::SpellNonMeleeDamage(Unit* _attacker, Unit* _target, SpellInfo const* _spellInfo, SpellCastVisual spellVisual, uint32 _schoolMask, ObjectGuid _castId)
303 : target(_target), attacker(_attacker), castId(_castId), Spell(_spellInfo), SpellVisual(spellVisual), damage(0), originalDamage(0),
304 schoolMask(_schoolMask), absorb(0), resist(0), periodicLog(false), blocked(0), HitInfo(0), cleanDamage(0), fullBlock(false), preHitHealth(_target->GetHealth())
305{
306}
307
308Unit::Unit(bool isWorldObject) :
309 WorldObject(isWorldObject), m_lastSanctuaryTime(0), LastCharmerGUID(), movespline(std::make_unique<Movement::MoveSpline>()),
310 m_ControlledByPlayer(false), m_procDeep(0), m_procChainLength(0), m_transformSpell(0),
311 m_removedAurasCount(0), m_interruptMask(SpellAuraInterruptFlags::None), m_interruptMask2(SpellAuraInterruptFlags2::None),
312 m_unitMovedByMe(nullptr), m_playerMovingMe(nullptr), m_charmer(nullptr), m_charmed(nullptr),
313 i_motionMaster(std::make_unique<MotionMaster>(this)), m_regenTimer(0), m_vehicle(nullptr),
314 m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this),
315 m_threatManager(this), m_aiLocked(false), _playHoverAnim(false), _aiAnimKitId(0), _movementAnimKitId(0), _meleeAnimKitId(0),
316 _spellHistory(std::make_unique<SpellHistory>(this))
317{
320
322
323 m_baseAttackSpeed = { };
324 m_attackTimer = { };
325 m_modAttackSpeedPct.fill(1.0f);
326
327 m_canDualWield = false;
328
330
331 m_state = 0;
333
334 m_currentSpells = { };
335
337
338 m_canModifyStats = false;
339
340 for (uint8 i = 0; i < UNIT_MOD_END; ++i)
341 {
347 }
348 // implement 50% base damage from offhand
350
351 for (uint8 i = 0; i < MAX_ATTACK; ++i)
352 {
355 }
356
357 m_createStats = { };
358 m_floatStatPosBuff = { };
359 m_floatStatNegBuff = { };
360
361 m_attacking = nullptr;
362 m_modMeleeHitChance = 0.0f;
364 m_modSpellHitChance = 0.0f;
366
367 m_speed_rate.fill(1.0f);
368
369 // remove aurastates allowing special moves
370 m_reactiveTimer = { };
371
372 m_cleanupDone = false;
374
376
377 _lastLiquid = nullptr;
378
379 _oldFactionId = 0;
380 _isWalkingBeforeCharm = false;
381 _instantCast = false;
382 _isCombatDisallowed = false;
383
385}
386
388// Methods of class Unit
390{
391 // set current spells as deletable
392 for (size_t i = 0; i < m_currentSpells.size(); ++i)
393 {
394 if (m_currentSpells[i])
395 {
396 m_currentSpells[i]->SetReferencedFromCurrent(false);
397 m_currentSpells[i] = nullptr;
398 }
399 }
400
402
404
407 ASSERT(m_attackers.empty());
408 ASSERT(m_sharedVision.empty());
409 ASSERT(m_Controlled.empty());
410 ASSERT(m_appliedAuras.empty());
411 ASSERT(m_ownedAuras.empty());
412 ASSERT(m_removedAuras.empty());
413 ASSERT(m_dynObj.empty());
414 ASSERT(m_gameObj.empty());
415 ASSERT(m_areaTrigger.empty());
418}
419
421{
422 // WARNING! Order of execution here is important, do not change.
423 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
424 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
425 WorldObject::Update(p_time);
426
427 if (!IsInWorld())
428 return;
429
430 _UpdateSpells(p_time);
431
432 // If this is set during update SetCantProc(false) call is missing somewhere in the code
433 // Having this would prevent spells from being proced, so let's crash
435
436 m_combatManager.Update(p_time);
437
440 {
441 while (!extraAttacksTargets.empty())
442 {
443 auto itr = extraAttacksTargets.begin();
444 ObjectGuid targetGuid = itr->first;
445 uint32 count = itr->second;
446 extraAttacksTargets.erase(itr);
447 if (Unit* victim = ObjectAccessor::GetUnit(*this, targetGuid))
448 HandleProcExtraAttackFor(victim, count);
449 }
451 }
452
453 auto spellPausesCombatTimer = [&](CurrentSpellTypes type)
454 {
456 };
457
458 if (!spellPausesCombatTimer(CURRENT_GENERIC_SPELL) && !spellPausesCombatTimer(CURRENT_CHANNELED_SPELL))
459 {
460 if (uint32 base_att = getAttackTimer(BASE_ATTACK))
461 setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time));
462 if (uint32 off_att = getAttackTimer(OFF_ATTACK))
463 setAttackTimer(OFF_ATTACK, (p_time >= off_att ? 0 : off_att - p_time));
464 if (uint32 ranged_att = getAttackTimer(RANGED_ATTACK))
465 setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time));
466 }
467
468 // update abilities available only for fraction of time
469 UpdateReactives(p_time);
470
471 if (IsAlive())
472 {
479 }
480
481 UpdateSplineMovement(p_time);
482 i_motionMaster->Update(p_time);
483
484 // Wait with the aura interrupts until we have updated our movement generators and position
485 if (GetTypeId() == TYPEID_PLAYER)
487 else if (!movespline->Finalized())
489
490 // All position info based actions have been executed, reset info
492
495 RefreshAI();
496}
497
499{
500 if (Player const* player = ToPlayer())
501 return player->GetWeaponForAttack(OFF_ATTACK, true) != nullptr;
502
503 return CanDualWield();
504}
505
506void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath, bool forceDestination)
507{
508 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
509 {
510 init.MoveTo(x, y, z, generatePath, forceDestination);
511 init.SetVelocity(speed);
512 };
514}
515
517{
519
520 switch (type)
521 {
524 break;
527 break;
528 default:
529 break;
530 }
531
532 if (IsAlive())
534}
535
537{
539
540 switch (type)
541 {
544 break;
545 default:
546 break;
547 }
548
549 GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr)
550 {
551 SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first, DIFFICULTY_NONE);
552
554 }, true);
555}
556
558{
559 if (movespline->Finalized())
560 return;
561
562 movespline->updateState(t_diff);
563 bool arrived = movespline->Finalized();
564
565 if (movespline->isCyclic())
566 {
569 {
570 m_splineSyncTimer.Reset(5000); // Retail value, do not change
571
573 flightSplineSync.Guid = GetGUID();
574 flightSplineSync.SplineDist = movespline->timePassed() / movespline->Duration();
575 SendMessageToSet(flightSplineSync.Write(), true);
576 }
577 }
578
579 if (arrived)
580 {
582
583 if (Optional<AnimTier> animTier = movespline->GetAnimation())
584 SetAnimTier(*animTier);
585 }
586
588}
589
591{
592 Movement::Location loc = movespline->ComputePosition();
593
594 if (movespline->onTransport)
595 {
597 pos.m_positionX = loc.x;
598 pos.m_positionY = loc.y;
599 pos.m_positionZ = loc.z;
601
602 if (TransportBase* transport = GetDirectTransport())
603 transport->CalculatePassengerPosition(loc.x, loc.y, loc.z, &loc.orientation);
604 else
605 return;
606 }
607
610
611 UpdatePosition(loc.x, loc.y, loc.z, loc.orientation);
612}
613
615{
616 // TODO: Check if orientation transport offset changed instead of only global orientation
619
622}
623
625{
627 movespline->_Interrupt();
628}
629
631{
633}
634
635bool Unit::IsWithinCombatRange(Unit const* obj, float dist2compare) const
636{
637 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
638 return false;
639
640 float dx = GetPositionX() - obj->GetPositionX();
641 float dy = GetPositionY() - obj->GetPositionY();
642 float dz = GetPositionZ() - obj->GetPositionZ();
643 float distsq = dx * dx + dy * dy + dz * dz;
644
645 float sizefactor = GetCombatReach() + obj->GetCombatReach();
646 float maxdist = dist2compare + sizefactor;
647
648 return distsq < maxdist * maxdist;
649}
650
651bool Unit::IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const
652{
653 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
654 return false;
655
656 float dx = pos.GetPositionX() - obj->GetPositionX();
657 float dy = pos.GetPositionY() - obj->GetPositionY();
658 float dz = pos.GetPositionZ() - obj->GetPositionZ();
659 float distsq = dx*dx + dy*dy + dz*dz;
660
662
663 return distsq <= maxdist * maxdist;
664}
665
666float Unit::GetMeleeRange(Unit const* target) const
667{
668 float range = GetCombatReach() + target->GetCombatReach() + 4.0f / 3.0f;
669 return std::max(range, NOMINAL_MELEE_RANGE);
670}
671
672bool Unit::IsWithinBoundaryRadius(const Unit* obj) const
673{
674 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
675 return false;
676
677 float objBoundaryRadius = std::max(obj->GetBoundingRadius(), MIN_MELEE_REACH);
678
679 return IsInDist(obj, objBoundaryRadius);
680}
681
683{
684 m_visibleAuras.insert(aurApp);
685 m_visibleAurasToUpdate.insert(aurApp);
687}
688
690{
691 m_visibleAuras.erase(aurApp);
692 m_visibleAurasToUpdate.erase(aurApp);
694}
695
697{
700 for (AuraApplication const* aurApp : m_interruptableAuras)
701 {
702 m_interruptMask |= aurApp->GetBase()->GetSpellInfo()->AuraInterruptFlags;
703 m_interruptMask2 |= aurApp->GetBase()->GetSpellInfo()->AuraInterruptFlags2;
704 }
705
707 {
708 if (spell->getState() == SPELL_STATE_CASTING)
709 {
710 m_interruptMask |= spell->m_spellInfo->ChannelInterruptFlags;
711 m_interruptMask2 |= spell->m_spellInfo->ChannelInterruptFlags2;
712 }
713 }
714}
715
716bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag128 familyFlags) const
717{
718 for (AuraEffect const* aura : GetAuraEffectsByType(auraType))
719 if (aura->GetSpellInfo()->SpellFamilyName == familyName && aura->GetSpellInfo()->SpellFamilyFlags & familyFlags)
720 return true;
721 return false;
722}
723
725{
726 AuraEffectList const& auras = GetAuraEffectsByType(type);
727 for (AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
728 if ((!excludeAura || excludeAura != (*itr)->GetSpellInfo()->Id) && //Avoid self interrupt of channeled Crowd Control spells like Seduction
729 (*itr)->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::Damage))
730 return true;
731 return false;
732}
733
734bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) const
735{
736 uint32 excludeAura = 0;
737 if (Spell* currentChanneledSpell = excludeCasterChannel ? excludeCasterChannel->GetCurrentSpell(CURRENT_CHANNELED_SPELL) : nullptr)
738 excludeAura = currentChanneledSpell->GetSpellInfo()->Id; //Avoid self interrupt of channeled Crowd Control spells like Seduction
739
746}
747
748/*static*/ void Unit::DealDamageMods(Unit const* attacker, Unit const* victim, uint32& damage, uint32* absorb)
749{
750 if (!victim || !victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
751 {
752 if (absorb)
753 *absorb += damage;
754 damage = 0;
755 return;
756 }
757
758 if (attacker)
759 damage *= attacker->GetDamageMultiplierForTarget(victim);
760}
761
763{
764 AuraEffectVector effects;
765 std::copy(list.begin(), list.end(), std::back_inserter(effects));
766 return effects;
767}
768
769/*static*/ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
770{
771 uint32 damageDone = damage;
772 uint32 damageTaken = damage;
773 if (attacker)
774 damageTaken = damage / victim->GetHealthMultiplierForTarget(attacker);
775
776 // call script hooks
777 {
778 uint32 tmpDamage = damageTaken;
779
780 // sparring
781 if (Creature* victimCreature = victim->ToCreature())
782 tmpDamage = victimCreature->CalculateDamageForSparring(attacker, tmpDamage);
783
784 if (UnitAI* victimAI = victim->GetAI())
785 victimAI->DamageTaken(attacker, tmpDamage, damagetype, spellProto);
786
787 if (UnitAI* attackerAI = attacker ? attacker->GetAI() : nullptr)
788 attackerAI->DamageDealt(victim, tmpDamage, damagetype);
789
790 // Hook for OnDamage Event
791 sScriptMgr->OnDamage(attacker, victim, tmpDamage);
792
793 // if any script modified damage, we need to also apply the same modification to unscaled damage value
794 if (tmpDamage != damageTaken)
795 {
796 if (attacker)
797 damageDone = tmpDamage * victim->GetHealthMultiplierForTarget(attacker);
798 else
799 damageDone = tmpDamage;
800
801 damageTaken = tmpDamage;
802 }
803 }
804
805 // Signal to pets that their owner was attacked - except when DOT.
806 if (attacker != victim && damagetype != DOT)
807 {
808 for (Unit* controlled : victim->m_Controlled)
809 if (Creature* cControlled = controlled->ToCreature())
810 if (CreatureAI* controlledAI = cControlled->AI())
811 controlledAI->OwnerAttackedBy(attacker);
812 }
813
814 if (Player* player = victim->ToPlayer())
815 if (player->GetCommandStatus(CHEAT_GOD))
816 return 0;
817
818 if (damagetype != NODAMAGE)
819 {
820 // interrupting auras with SpellAuraInterruptFlags::Damage before checking !damage (absorbed damage breaks that type of auras)
821 if (spellProto)
822 {
825 }
826 else
828
829 if (!damageTaken && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage)
830 if (victim != attacker && victim->GetTypeId() == TYPEID_PLAYER)
831 if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
832 if (spell->getState() == SPELL_STATE_PREPARING && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageAbsorb))
833 victim->InterruptNonMeleeSpells(false);
834
835 // We're going to call functions which can modify content of the list during iteration over it's elements
836 // Let's copy the list so we can prevent iterator invalidation
838 // copy damage to casters of this aura
839 for (auto i = vCopyDamageCopy.begin(); i != vCopyDamageCopy.end(); ++i)
840 {
841 // Check if aura was removed during iteration - we don't need to work on such auras
842 if (!((*i)->GetBase()->IsAppliedOnTarget(victim->GetGUID())))
843 continue;
844 // check damage school mask
845 if (((*i)->GetMiscValue() & damageSchoolMask) == 0)
846 continue;
847
848 Unit* shareDamageTarget = (*i)->GetCaster();
849 if (!shareDamageTarget)
850 continue;
851 SpellInfo const* spell = (*i)->GetSpellInfo();
852
853 uint32 share = CalculatePct(damageDone, (*i)->GetAmount());
854
856 Unit::DealDamageMods(attacker, shareDamageTarget, share, nullptr);
857 Unit::DealDamage(attacker, shareDamageTarget, share, nullptr, NODAMAGE, spell->GetSchoolMask(), spell, false);
858 }
859 }
860
861 // Rage from Damage made (only from direct weapon damage)
862 if (attacker && cleanDamage && (cleanDamage->attackType == BASE_ATTACK || cleanDamage->attackType == OFF_ATTACK) && damagetype == DIRECT_DAMAGE && attacker != victim && attacker->GetPowerType() == POWER_RAGE)
863 {
864 uint32 rage = uint32(attacker->GetBaseAttackTime(cleanDamage->attackType) / 1000.f * 1.75f);
865 if (cleanDamage->attackType == OFF_ATTACK)
866 rage /= 2;
867 attacker->RewardRage(rage);
868 }
869
870 if (!damageDone)
871 return 0;
872
873 uint32 health = victim->GetHealth();
874
875 // duel ends when player has 1 or less hp
876 bool duel_hasEnded = false;
877 bool duel_wasMounted = false;
878 if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damageTaken >= (health-1))
879 {
880 if (!attacker)
881 return 0;
882
883 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
884 if (victim->ToPlayer()->duel->Opponent == attacker->GetControllingPlayer())
885 damageTaken = health - 1;
886
887 duel_hasEnded = true;
888 }
889 else if (victim->IsCreature() && victim != attacker && damageTaken >= health && victim->ToCreature()->HasFlag(CREATURE_STATIC_FLAG_UNKILLABLE))
890 {
891 damageTaken = health - 1;
892
893 // If we had damage (aka health was not 1 already) trigger OnHealthDepleted
894 if (damageTaken > 0)
895 {
896 if (CreatureAI* victimAI = victim->ToCreature()->AI())
897 victimAI->OnHealthDepleted(attacker, false);
898 }
899 }
900 else if (victim->IsVehicle() && damageTaken >= (health-1) && victim->GetCharmer() && victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER)
901 {
902 Player* victimRider = victim->GetCharmer()->ToPlayer();
903
904 if (victimRider && victimRider->duel && victimRider->duel->IsMounted)
905 {
906 if (!attacker)
907 return 0;
908
909 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
910 if (victimRider->duel->Opponent == attacker->GetControllingPlayer())
911 damageTaken = health - 1;
912
913 duel_wasMounted = true;
914 duel_hasEnded = true;
915 }
916 }
917
918 if (attacker && attacker != victim)
919 {
920 if (Player* killer = attacker->ToPlayer())
921 {
922 // in bg, count dmg if victim is also a player
923 if (victim->GetTypeId() == TYPEID_PLAYER && !(spellProto && spellProto->HasAttribute(SPELL_ATTR7_DO_NOT_COUNT_FOR_PVP_SCOREBOARD)))
924 if (Battleground* bg = killer->GetBattleground())
925 bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damageDone);
926
927 killer->UpdateCriteria(CriteriaType::DamageDealt, health > damageDone ? damageDone : health, 0, 0, victim);
928 killer->UpdateCriteria(CriteriaType::HighestDamageDone, damageDone);
929 }
930 }
931
932 if (victim->GetTypeId() == TYPEID_PLAYER)
934
935 if (victim->GetTypeId() != TYPEID_PLAYER && (!victim->IsControlledByPlayer() || victim->IsVehicle()))
936 {
937 victim->ToCreature()->SetTappedBy(attacker);
938
939 if (!attacker || attacker->IsControlledByPlayer())
940 victim->ToCreature()->LowerPlayerDamageReq(health < damageTaken ? health : damageTaken);
941 }
942
943 bool killed = false;
944 bool skipSettingDeathState = false;
945
946 if (health <= damageTaken)
947 {
948 killed = true;
949
950 if (victim->GetTypeId() == TYPEID_PLAYER && victim != attacker)
952
953 if (damagetype != NODAMAGE && damagetype != SELF_DAMAGE && victim->HasAuraType(SPELL_AURA_SCHOOL_ABSORB_OVERKILL))
954 {
956 DamageInfo damageInfo = DamageInfo(attacker, victim, damageTaken, spellProto, damageSchoolMask, damagetype,
957 cleanDamage ? cleanDamage->attackType : BASE_ATTACK);
958 for (AuraEffect* absorbAurEff : vAbsorbOverkill)
959 {
960 Aura* base = absorbAurEff->GetBase();
961 AuraApplication const* aurApp = base->GetApplicationOfTarget(victim->GetGUID());
962 if (!aurApp)
963 continue;
964
965 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
966 continue;
967
968 // cannot absorb over limit
969 if (damageTaken >= victim->CountPctFromMaxHealth(100 + absorbAurEff->GetMiscValueB()))
970 continue;
971
972 // absorb all damage by default
973 uint32 currentAbsorb = damageInfo.GetDamage();
974
975 // This aura type is used both by Spirit of Redemption (death not really prevented, must grant all credit immediately) and Cheat Death (death prevented)
976 // repurpose PreventDefaultAction for this
977 bool deathFullyPrevented = false;
978
979 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, currentAbsorb, deathFullyPrevented);
980
981 // absorb must be smaller than the damage itself
982 currentAbsorb = std::min(currentAbsorb, damageInfo.GetDamage());
983
984 // if nothing is absorbed (for example because of a scripted cooldown) then skip this aura and proceed with dying
985 if (!currentAbsorb)
986 continue;
987
988 damageInfo.AbsorbDamage(currentAbsorb);
989
990 if (deathFullyPrevented)
991 killed = false;
992
993 skipSettingDeathState = true;
994
995 if (currentAbsorb)
996 {
998 absorbLog.Attacker = attacker ? attacker->GetGUID() : ObjectGuid::Empty;
999 absorbLog.Victim = victim->GetGUID();
1000 absorbLog.Caster = base->GetCasterGUID();
1001 absorbLog.AbsorbedSpellID = spellProto ? spellProto->Id : 0;
1002 absorbLog.AbsorbSpellID = base->GetId();
1003 absorbLog.Absorbed = currentAbsorb;
1004 absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
1005 absorbLog.LogData.Initialize(victim);
1006 victim->SendCombatLogMessage(&absorbLog);
1007 }
1008 }
1009
1010 damageTaken = damageInfo.GetDamage();
1011 }
1012 }
1013
1014 if (spellProto && spellProto->HasAttribute(SPELL_ATTR3_NO_DURABILITY_LOSS))
1015 durabilityLoss = false;
1016
1017 if (killed)
1018 Unit::Kill(attacker, victim, durabilityLoss, skipSettingDeathState);
1019 else
1020 {
1021 if (victim->GetTypeId() == TYPEID_PLAYER)
1023
1024 victim->ModifyHealth(-(int32)damageTaken);
1025
1026 if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
1029 if (victim->GetTypeId() != TYPEID_PLAYER)
1030 {
1031 // Part of Evade mechanics. DoT's and Thorns / Retribution Aura do not contribute to this
1032 if (damagetype != DOT && damageTaken > 0 && !victim->GetOwnerGUID().IsPlayer() && (!spellProto || !spellProto->HasAura(SPELL_AURA_DAMAGE_SHIELD)))
1035 if (attacker && (!spellProto || !spellProto->HasAttribute(SPELL_ATTR4_NO_HARMFUL_THREAT)))
1036 victim->GetThreatManager().AddThreat(attacker, float(damageTaken), spellProto);
1037 }
1038 else // victim is a player
1039 {
1040 // random durability for items (HIT TAKEN)
1041 if (durabilityLoss && roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE)))
1042 {
1045 }
1046 }
1047
1048 if (attacker && attacker->GetTypeId() == TYPEID_PLAYER)
1049 {
1050 // random durability for items (HIT DONE)
1051 if (durabilityLoss && roll_chance_f(sWorld->getRate(RATE_DURABILITY_LOSS_DAMAGE)))
1052 {
1054 attacker->ToPlayer()->DurabilityPointLossForEquipSlot(slot);
1055 }
1056 }
1057
1058 if (damagetype != NODAMAGE && damagetype != DOT)
1059 {
1060 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))))
1061 {
1062 if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
1063 {
1064 if (spell->getState() == SPELL_STATE_PREPARING)
1065 {
1066 auto isCastInterrupted = [&]()
1067 {
1068 if (!damageTaken)
1069 return spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::ZeroDamageCancels);
1070
1071 if ((victim->IsPlayer() && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancelsPlayerOnly)))
1072 return true;
1073
1074 if (spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancels))
1075 return true;
1076
1077 return false;
1078 };
1079
1080 auto isCastDelayed = [&]()
1081 {
1082 if (!damageTaken)
1083 return false;
1084
1085 if ((victim->IsPlayer() && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamagePushbackPlayerOnly)))
1086 return true;
1087
1088 if (spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamagePushback))
1089 return true;
1090
1091 return false;
1092 };
1093
1094 if (isCastInterrupted())
1095 victim->InterruptNonMeleeSpells(false);
1096 else if (isCastDelayed())
1097 spell->Delayed();
1098 }
1099 }
1100
1101 if (damageTaken && victim->IsPlayer())
1102 if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL])
1103 if (spell->getState() == SPELL_STATE_CASTING && spell->m_spellInfo->HasChannelInterruptFlag(SpellAuraInterruptFlags::DamageChannelDuration))
1104 spell->DelayedChannel();
1105 }
1106 }
1107
1108 // last damage from duel opponent
1109 if (duel_hasEnded)
1110 {
1111 Player* he = duel_wasMounted ? victim->GetCharmer()->ToPlayer() : victim->ToPlayer();
1112
1113 ASSERT_NODEBUGINFO(he && he->duel);
1114
1115 if (duel_wasMounted) // In this case victim == mount
1116 victim->SetHealth(1);
1117 else
1118 he->SetHealth(1);
1119
1120 he->duel->Opponent->CombatStopWithPets(true);
1121 he->CombatStopWithPets(true);
1122
1123 he->CastSpell(he, 7267, true); // beg
1125 }
1126 }
1127
1128 // make player victims stand up automatically
1129 if (victim->GetStandState() && victim->IsPlayer())
1131
1132 return damageTaken;
1133}
1134
1135void Unit::CastStop(uint32 except_spellid)
1136{
1138 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id != except_spellid)
1140}
1141
1142void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit /*= false*/, bool blocked /*= false*/, Spell* spell /*= nullptr*/)
1143{
1144 if (damage < 0)
1145 return;
1146
1147 Unit* victim = damageInfo->target;
1148 if (!victim || !victim->IsAlive())
1149 return;
1150
1151 SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
1152
1153 // Spells with SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS ignore resilience because their damage is based off another spell's damage.
1155 {
1156 if (Unit::IsDamageReducedByArmor(damageSchoolMask, spellInfo))
1157 damage = Unit::CalcArmorReducedDamage(damageInfo->attacker, victim, damage, spellInfo, attackType);
1158
1159 // Per-school calc
1160 switch (spellInfo->DmgClass)
1161 {
1162 // Melee and Ranged Spells
1165 {
1166 if (crit)
1167 {
1168 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1169
1170 // Calculate crit bonus
1171 uint32 crit_bonus = damage;
1172 // Apply crit_damage bonus for melee spells
1173 if (Player* modOwner = GetSpellModOwner())
1174 modOwner->ApplySpellMod(spellInfo, SpellModOp::CritDamageAndHealing, crit_bonus);
1175 damage += crit_bonus;
1176
1177 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
1178 float critPctDamageMod = (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellInfo->GetSchoolMask()) - 1.0f) * 100;
1179
1180 if (critPctDamageMod != 0)
1181 AddPct(damage, critPctDamageMod);
1182 }
1183
1184 // Spell weapon based damage CAN BE crit & blocked at same time
1185 if (blocked)
1186 {
1187 // double blocked amount if block is critical
1188 uint32 value = victim->GetBlockPercent(GetLevel());
1189 if (victim->IsBlockCritical())
1190 value *= 2; // double blocked percent
1191 damageInfo->blocked = CalculatePct(damage, value);
1192 if (damage <= int32(damageInfo->blocked))
1193 {
1194 damageInfo->blocked = uint32(damage);
1195 damageInfo->fullBlock = true;
1196 }
1197 damage -= damageInfo->blocked;
1198 }
1199
1200 if (CanApplyResilience())
1201 Unit::ApplyResilience(victim, &damage);
1202 break;
1203 }
1204 // Magical Attacks
1207 {
1208 // If crit add critical bonus
1209 if (crit)
1210 {
1211 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1212 damage = Unit::SpellCriticalDamageBonus(this, spellInfo, damage, victim);
1213 }
1214
1215 if (CanApplyResilience())
1216 Unit::ApplyResilience(victim, &damage);
1217 break;
1218
1219 }
1220 default:
1221 break;
1222 }
1223 }
1224
1225 // Script Hook For CalculateSpellDamageTaken -- Allow scripts to change the Damage post class mitigation calculations
1226 sScriptMgr->ModifySpellDamageTaken(damageInfo->target, damageInfo->attacker, damage, spellInfo);
1227
1228 // Calculate absorb resist
1229 if (damage < 0)
1230 damage = 0;
1231
1232 damageInfo->damage = damage;
1233 damageInfo->originalDamage = damage;
1235 Unit::CalcAbsorbResist(dmgInfo, spell);
1236 damageInfo->absorb = dmgInfo.GetAbsorb();
1237 damageInfo->resist = dmgInfo.GetResist();
1238
1239 if (damageInfo->absorb)
1240 damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
1241
1242 if (damageInfo->resist)
1243 damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
1244
1245 damageInfo->damage = dmgInfo.GetDamage();
1246}
1247
1248void Unit::DealSpellDamage(SpellNonMeleeDamage const* damageInfo, bool durabilityLoss)
1249{
1250 if (!damageInfo)
1251 return;
1252
1253 Unit* victim = damageInfo->target;
1254 if (!victim)
1255 return;
1256
1257 if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
1258 return;
1259
1260 if (!damageInfo->Spell)
1261 {
1262 TC_LOG_DEBUG("entities.unit", "Unit::DealSpellDamage has no spell");
1263 return;
1264 }
1265
1266 // Call default DealDamage
1267 CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
1268 Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), damageInfo->Spell, durabilityLoss);
1269}
1270
1272void Unit::CalculateMeleeDamage(Unit* victim, CalcDamageInfo* damageInfo, WeaponAttackType attackType /*= BASE_ATTACK*/)
1273{
1274 damageInfo->Attacker = this;
1275 damageInfo->Target = victim;
1276
1277 damageInfo->DamageSchoolMask = GetMeleeDamageSchoolMask(attackType);
1278 damageInfo->Damage = 0;
1279 damageInfo->OriginalDamage = 0;
1280 damageInfo->Absorb = 0;
1281 damageInfo->Resist = 0;
1282
1283 damageInfo->Blocked = 0;
1284 damageInfo->HitInfo = 0;
1285 damageInfo->TargetState = 0;
1286
1287 damageInfo->AttackType = attackType;
1288 damageInfo->ProcAttacker = PROC_FLAG_NONE;
1289 damageInfo->ProcVictim = PROC_FLAG_NONE;
1290 damageInfo->CleanDamage = 0;
1291 damageInfo->HitOutCome = MELEE_HIT_EVADE;
1292
1293 if (!victim)
1294 return;
1295
1296 if (!IsAlive() || !victim->IsAlive())
1297 return;
1298
1299 // Select HitInfo/procAttacker/procVictim flag based on attack type
1300 switch (attackType)
1301 {
1302 case BASE_ATTACK:
1305 break;
1306 case OFF_ATTACK:
1309 damageInfo->HitInfo = HITINFO_OFFHAND;
1310 break;
1311 default:
1312 return;
1313 }
1314
1315 // Physical Immune check
1316 if (damageInfo->Target->IsImmunedToDamage(SpellSchoolMask(damageInfo->DamageSchoolMask)))
1317 {
1318 damageInfo->HitInfo |= HITINFO_NORMALSWING;
1319 damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
1320
1321 damageInfo->Damage = 0;
1322 damageInfo->CleanDamage = 0;
1323 return;
1324 }
1325
1326 uint32 damage = 0;
1327 damage += CalculateDamage(damageInfo->AttackType, false, true);
1328 // Add melee damage bonus
1329 damage = MeleeDamageBonusDone(damageInfo->Target, damage, damageInfo->AttackType, DIRECT_DAMAGE, nullptr, MECHANIC_NONE, SpellSchoolMask(damageInfo->DamageSchoolMask));
1330 damage = damageInfo->Target->MeleeDamageBonusTaken(this, damage, damageInfo->AttackType, DIRECT_DAMAGE, nullptr, SpellSchoolMask(damageInfo->DamageSchoolMask));
1331
1332 // Script Hook For CalculateMeleeDamage -- Allow scripts to change the Damage pre class mitigation calculations
1333 sScriptMgr->ModifyMeleeDamage(damageInfo->Target, damageInfo->Attacker, damage);
1334
1335 // Calculate armor reduction
1337 {
1338 damageInfo->Damage = Unit::CalcArmorReducedDamage(damageInfo->Attacker, damageInfo->Target, damage, nullptr, damageInfo->AttackType);
1339 damageInfo->CleanDamage += damage - damageInfo->Damage;
1340 }
1341 else
1342 damageInfo->Damage = damage;
1343
1344 damageInfo->HitOutCome = RollMeleeOutcomeAgainst(damageInfo->Target, damageInfo->AttackType);
1345
1346 switch (damageInfo->HitOutCome)
1347 {
1348 case MELEE_HIT_EVADE:
1350 damageInfo->TargetState = VICTIMSTATE_EVADES;
1351 damageInfo->OriginalDamage = damageInfo->Damage;
1352
1353 damageInfo->Damage = 0;
1354 damageInfo->CleanDamage = 0;
1355 return;
1356 case MELEE_HIT_MISS:
1357 damageInfo->HitInfo |= HITINFO_MISS;
1358 damageInfo->TargetState = VICTIMSTATE_INTACT;
1359 damageInfo->OriginalDamage = damageInfo->Damage;
1360
1361 damageInfo->Damage = 0;
1362 damageInfo->CleanDamage = 0;
1363 break;
1364 case MELEE_HIT_NORMAL:
1365 damageInfo->TargetState = VICTIMSTATE_HIT;
1366 damageInfo->OriginalDamage = damageInfo->Damage;
1367 break;
1368 case MELEE_HIT_CRIT:
1369 {
1370 damageInfo->HitInfo |= HITINFO_CRITICALHIT;
1371 damageInfo->TargetState = VICTIMSTATE_HIT;
1372
1373 // Crit bonus calc
1374 damageInfo->Damage *= 2;
1375
1376 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
1378
1379 if (mod != 0)
1380 AddPct(damageInfo->Damage, mod);
1381
1382 damageInfo->OriginalDamage = damageInfo->Damage;
1383 break;
1384 }
1385 case MELEE_HIT_PARRY:
1386 damageInfo->TargetState = VICTIMSTATE_PARRY;
1387 damageInfo->CleanDamage += damageInfo->Damage;
1388
1389 damageInfo->OriginalDamage = damageInfo->Damage;
1390 damageInfo->Damage = 0;
1391 break;
1392 case MELEE_HIT_DODGE:
1393 damageInfo->TargetState = VICTIMSTATE_DODGE;
1394 damageInfo->CleanDamage += damageInfo->Damage;
1395
1396 damageInfo->OriginalDamage = damageInfo->Damage;
1397 damageInfo->Damage = 0;
1398 break;
1399 case MELEE_HIT_BLOCK:
1400 damageInfo->TargetState = VICTIMSTATE_HIT;
1401 damageInfo->HitInfo |= HITINFO_BLOCK;
1402 // 30% damage blocked, double blocked amount if block is critical
1403 damageInfo->Blocked = CalculatePct(damageInfo->Damage, damageInfo->Target->GetBlockPercent(GetLevel()));
1404 if (damageInfo->Target->IsBlockCritical())
1405 damageInfo->Blocked *= 2;
1406
1407 damageInfo->OriginalDamage = damageInfo->Damage;
1408 damageInfo->Damage -= damageInfo->Blocked;
1409 damageInfo->CleanDamage += damageInfo->Blocked;
1410 break;
1411 case MELEE_HIT_GLANCING:
1412 {
1413 damageInfo->HitInfo |= HITINFO_GLANCING;
1414 damageInfo->TargetState = VICTIMSTATE_HIT;
1415 int32 leveldif = int32(victim->GetLevel()) - int32(GetLevel());
1416 if (leveldif > 3)
1417 leveldif = 3;
1418
1419 damageInfo->OriginalDamage = damageInfo->Damage;
1420 float reducePercent = 1.f - leveldif * 0.1f;
1421 damageInfo->CleanDamage += damageInfo->Damage - uint32(reducePercent * damageInfo->Damage);
1422 damageInfo->Damage = uint32(reducePercent * damageInfo->Damage);
1423 break;
1424 }
1425 case MELEE_HIT_CRUSHING:
1426 damageInfo->HitInfo |= HITINFO_CRUSHING;
1427 damageInfo->TargetState = VICTIMSTATE_HIT;
1428 // 150% normal damage
1429 damageInfo->Damage += (damageInfo->Damage / 2);
1430 damageInfo->OriginalDamage = damageInfo->Damage;
1431 break;
1432 default:
1433 break;
1434 }
1435
1436 // Always apply HITINFO_AFFECTS_VICTIM in case its not a miss
1437 if (!(damageInfo->HitInfo & HITINFO_MISS))
1438 damageInfo->HitInfo |= HITINFO_AFFECTS_VICTIM;
1439
1440 int32 resilienceReduction = damageInfo->Damage;
1442 Unit::ApplyResilience(victim, &resilienceReduction);
1443 resilienceReduction = damageInfo->Damage - resilienceReduction;
1444 damageInfo->Damage -= resilienceReduction;
1445 damageInfo->CleanDamage += resilienceReduction;
1446 damageInfo->OriginalDamage -= resilienceReduction;
1447
1448 // Calculate absorb resist
1449 if (int32(damageInfo->Damage) > 0)
1450 {
1452 // Calculate absorb & resists
1453 DamageInfo dmgInfo(*damageInfo);
1454 Unit::CalcAbsorbResist(dmgInfo);
1455 damageInfo->Absorb = dmgInfo.GetAbsorb();
1456 damageInfo->Resist = dmgInfo.GetResist();
1457
1458 if (damageInfo->Absorb)
1459 damageInfo->HitInfo |= (damageInfo->Damage - damageInfo->Absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
1460
1461 if (damageInfo->Resist)
1462 damageInfo->HitInfo |= (damageInfo->Damage - damageInfo->Resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
1463
1464 damageInfo->Damage = dmgInfo.GetDamage();
1465 }
1466 else // Impossible get negative result but....
1467 damageInfo->Damage = 0;
1468}
1469
1470void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
1471{
1472 Unit* victim = damageInfo->Target;
1473
1474 if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
1475 return;
1476
1477 if (damageInfo->TargetState == VICTIMSTATE_PARRY &&
1479 {
1480 // Get attack timers
1481 float offtime = float(victim->getAttackTimer(OFF_ATTACK));
1482 float basetime = float(victim->getAttackTimer(BASE_ATTACK));
1483 // Reduce attack time
1484 if (victim->haveOffhandWeapon() && offtime < basetime)
1485 {
1486 float percent20 = victim->GetBaseAttackTime(OFF_ATTACK) * 0.20f;
1487 float percent60 = 3.0f * percent20;
1488 if (offtime > percent20 && offtime <= percent60)
1489 victim->setAttackTimer(OFF_ATTACK, uint32(percent20));
1490 else if (offtime > percent60)
1491 {
1492 offtime -= 2.0f * percent20;
1493 victim->setAttackTimer(OFF_ATTACK, uint32(offtime));
1494 }
1495 }
1496 else
1497 {
1498 float percent20 = victim->GetBaseAttackTime(BASE_ATTACK) * 0.20f;
1499 float percent60 = 3.0f * percent20;
1500 if (basetime > percent20 && basetime <= percent60)
1501 victim->setAttackTimer(BASE_ATTACK, uint32(percent20));
1502 else if (basetime > percent60)
1503 {
1504 basetime -= 2.0f * percent20;
1505 victim->setAttackTimer(BASE_ATTACK, uint32(basetime));
1506 }
1507 }
1508 }
1509
1510 // Call default DealDamage
1511 CleanDamage cleanDamage(damageInfo->CleanDamage, damageInfo->Absorb, damageInfo->AttackType, damageInfo->HitOutCome);
1512 Unit::DealDamage(this, victim, damageInfo->Damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->DamageSchoolMask), nullptr, durabilityLoss);
1513
1514 // If this is a creature and it attacks from behind it has a probability to daze it's victim
1515 if ((damageInfo->HitOutCome == MELEE_HIT_CRIT || damageInfo->HitOutCome == MELEE_HIT_CRUSHING || damageInfo->HitOutCome == MELEE_HIT_NORMAL || damageInfo->HitOutCome == MELEE_HIT_GLANCING) &&
1516 GetTypeId() != TYPEID_PLAYER && !ToCreature()->IsControlledByPlayer() && !victim->HasInArc(float(M_PI), this)
1517 && (victim->GetTypeId() == TYPEID_PLAYER || !victim->ToCreature()->isWorldBoss())&& !victim->IsVehicle())
1518 {
1519 // 20% base chance
1520 float chance = 20.0f;
1521
1522 // there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1523 if (victim->GetLevel() < 30)
1524 chance = 0.65f * victim->GetLevelForTarget(this) + 0.5f;
1525
1526 uint32 const victimDefense = victim->GetMaxSkillValueForLevel(this);
1527 uint32 const attackerMeleeSkill = GetMaxSkillValueForLevel();
1528
1529 chance *= attackerMeleeSkill / float(victimDefense) * 0.16f;
1530
1531 // -probability is between 0% and 40%
1532 RoundToInterval(chance, 0.0f, 40.0f);
1533 if (roll_chance_f(chance))
1534 CastSpell(victim, 1604 /*SPELL_DAZED*/, true);
1535 }
1536
1537 if (GetTypeId() == TYPEID_PLAYER)
1538 {
1539 DamageInfo dmgInfo(*damageInfo);
1540 ToPlayer()->CastItemCombatSpell(dmgInfo);
1541 }
1542
1543 // Do effect if any damage done to target
1544 if (damageInfo->Damage)
1545 {
1546 // We're going to call functions which can modify content of the list during iteration over it's elements
1547 // Let's copy the list so we can prevent iterator invalidation
1549 for (AuraEffect const* aurEff : vDamageShieldsCopy)
1550 {
1551 SpellInfo const* spellInfo = aurEff->GetSpellInfo();
1552
1553 // Damage shield can be resisted...
1554 SpellMissInfo missInfo = victim->SpellHitResult(this, spellInfo, false);
1555 if (missInfo != SPELL_MISS_NONE)
1556 {
1557 victim->SendSpellMiss(this, spellInfo->Id, missInfo);
1558 continue;
1559 }
1560
1561 // ...or immuned
1562 if (IsImmunedToDamage(spellInfo))
1563 {
1564 victim->SendSpellDamageImmune(this, spellInfo->Id, false);
1565 continue;
1566 }
1567
1568 uint32 damage = aurEff->GetAmount();
1569 if (Unit* caster = aurEff->GetCaster())
1570 {
1571 damage = caster->SpellDamageBonusDone(this, spellInfo, damage, SPELL_DIRECT_DAMAGE, aurEff->GetSpellEffectInfo());
1572 damage = SpellDamageBonusTaken(caster, spellInfo, damage, SPELL_DIRECT_DAMAGE);
1573 }
1574
1575 DamageInfo damageInfo(this, victim, damage, spellInfo, spellInfo->GetSchoolMask(), SPELL_DIRECT_DAMAGE, BASE_ATTACK);
1576 victim->CalcAbsorbResist(damageInfo);
1577 damage = damageInfo.GetDamage();
1578 Unit::DealDamageMods(victim, this, damage, nullptr);
1579
1581 damageShield.Attacker = victim->GetGUID();
1582 damageShield.Defender = GetGUID();
1583 damageShield.SpellID = spellInfo->Id;
1584 damageShield.TotalDamage = damage;
1585 damageShield.OriginalDamage = damageInfo.GetOriginalDamage();
1586 damageShield.OverKill = std::max(int32(damage) - int32(GetHealth()), 0);
1587 damageShield.SchoolMask = spellInfo->SchoolMask;
1588 damageShield.LogAbsorbed = damageInfo.GetAbsorb();
1589
1590 Unit::DealDamage(victim, this, damage, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true);
1591
1592 damageShield.LogData.Initialize(this);
1593 victim->SendCombatLogMessage(&damageShield);
1594 }
1595 }
1596}
1597
1598void Unit::HandleEmoteCommand(Emote emoteId, Player* target /*=nullptr*/, Trinity::IteratorPair<int32 const*> spellVisualKitIds /*= {}*/, int32 sequenceVariation /*= 0*/)
1599{
1601 packet.Guid = GetGUID();
1602 packet.EmoteID = emoteId;
1603
1604 if (EmotesEntry const* emotesEntry = sEmotesStore.LookupEntry(emoteId))
1605 if (emotesEntry->AnimID == ANIM_MOUNT_SPECIAL || emotesEntry->AnimID == ANIM_MOUNT_SELF_SPECIAL)
1606 std::copy(spellVisualKitIds.begin(), spellVisualKitIds.end(), std::back_inserter(packet.SpellVisualKitIDs));
1607
1608 packet.SequenceVariation = sequenceVariation;
1609
1610 if (target)
1611 target->SendDirectMessage(packet.Write());
1612 else
1613 SendMessageToSet(packet.Write(), true);
1614}
1615
1616/*static*/ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* spellInfo /*= nullptr*/)
1617{
1618 // only physical spells damage gets reduced by armor
1619 if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
1620 return false;
1621
1622 return !spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_ARMOR);
1623}
1624
1625/*static*/ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, WeaponAttackType /*attackType*/ /*= MAX_ATTACK*/, uint8 attackerLevel /*= 0*/)
1626{
1627 float armor = float(victim->GetArmor());
1628
1629 if (attacker)
1630 {
1631 armor *= victim->GetArmorMultiplierForTarget(attacker);
1632
1633 // bypass enemy armor by SPELL_AURA_BYPASS_ARMOR_FOR_CASTER
1634 int32 armorBypassPct = 0;
1636 for (AuraEffectList::const_iterator i = reductionAuras.begin(); i != reductionAuras.end(); ++i)
1637 if ((*i)->GetCasterGUID() == attacker->GetGUID())
1638 armorBypassPct += (*i)->GetAmount();
1639 armor = CalculatePct(armor, 100 - std::min(armorBypassPct, 100));
1640
1641 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1643
1644 if (spellInfo)
1645 if (Player* modOwner = attacker->GetSpellModOwner())
1646 modOwner->ApplySpellMod(spellInfo, SpellModOp::TargetResistance, armor);
1647
1649 for (AuraEffect const* aurEff : resIgnoreAuras)
1650 {
1651 if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL && aurEff->IsAffectingSpell(spellInfo))
1652 armor = std::floor(AddPct(armor, -aurEff->GetAmount()));
1653 }
1654
1655 // Apply Player CR_ARMOR_PENETRATION rating
1656 if (attacker->GetTypeId() == TYPEID_PLAYER)
1657 {
1658 float arpPct = attacker->ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION);
1659
1660 // no more than 100%
1661 RoundToInterval(arpPct, 0.f, 100.f);
1662
1663 float maxArmorPen = 0.f;
1664 if (victim->GetLevelForTarget(attacker) < 60)
1665 maxArmorPen = float(400 + 85 * victim->GetLevelForTarget(attacker));
1666 else
1667 maxArmorPen = 400 + 85 * victim->GetLevelForTarget(attacker) + 4.5f * 85 * (victim->GetLevelForTarget(attacker) - 59);
1668
1669 // Cap armor penetration to this number
1670 maxArmorPen = std::min((armor + maxArmorPen) / 3.f, armor);
1671 // Figure out how much armor do we ignore
1672 armor -= CalculatePct(maxArmorPen, arpPct);
1673 }
1674 }
1675
1676 if (G3D::fuzzyLe(armor, 0.0f))
1677 return damage;
1678
1679 Classes attackerClass = CLASS_WARRIOR;
1680 if (attacker)
1681 {
1682 attackerLevel = attacker->GetLevelForTarget(victim);
1683 attackerClass = Classes(attacker->GetClass());
1684 }
1685
1686 // Expansion and ContentTuningID necessary? Does Player get a ContentTuningID too ?
1687 float armorConstant = sDB2Manager.EvaluateExpectedStat(ExpectedStatType::ArmorConstant, attackerLevel, -2, 0, attackerClass, 0);
1688
1689 if (!(armor + armorConstant))
1690 return damage;
1691
1692 float mitigation = std::min(armor / (armor + armorConstant), 0.85f);
1693 return uint32(std::max(damage * (1.0f - mitigation), 0.0f));
1694}
1695
1696/*static*/ uint32 Unit::CalcSpellResistedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo)
1697{
1698 // Magic damage, check for resists
1699 if (!(schoolMask & SPELL_SCHOOL_MASK_MAGIC))
1700 return 0;
1701
1702 // Npcs can have holy resistance
1703 if ((schoolMask & SPELL_SCHOOL_MASK_HOLY) && victim->GetTypeId() != TYPEID_UNIT)
1704 return 0;
1705
1706 float const averageResist = Unit::CalculateAverageResistReduction(attacker, schoolMask, victim, spellInfo);
1707 float discreteResistProbability[11] = { };
1708 if (averageResist <= 0.1f)
1709 {
1710 discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
1711 discreteResistProbability[1] = 5.0f * averageResist;
1712 discreteResistProbability[2] = 2.5f * averageResist;
1713 }
1714 else
1715 {
1716 for (uint32 i = 0; i < 11; ++i)
1717 discreteResistProbability[i] = std::max(0.5f - 2.5f * std::fabs(0.1f * i - averageResist), 0.0f);
1718 }
1719
1720 float roll = rand_norm();
1721 float probabilitySum = 0.0f;
1722
1723 uint32 resistance = 0;
1724 for (; resistance < 11; ++resistance)
1725 if (roll < (probabilitySum += discreteResistProbability[resistance]))
1726 break;
1727
1728 float damageResisted = damage * resistance / 10.f;
1729 if (damageResisted > 0.0f) // if any damage was resisted
1730 {
1731 int32 ignoredResistance = 0;
1732
1733 if (attacker)
1734 ignoredResistance += attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask);
1735
1736 ignoredResistance = std::min<int32>(ignoredResistance, 100);
1737 ApplyPct(damageResisted, 100 - ignoredResistance);
1738
1739 // Spells with melee and magic school mask, decide whether resistance or armor absorb is higher
1740 if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC))
1741 {
1742 uint32 damageAfterArmor = Unit::CalcArmorReducedDamage(attacker, victim, damage, spellInfo, spellInfo->GetAttackType());
1743 float armorReduction = damage - damageAfterArmor;
1744
1745 // pick the lower one, the weakest resistance counts
1746 damageResisted = std::min(damageResisted, armorReduction);
1747 }
1748 }
1749
1750 damageResisted = std::max(damageResisted, 0.f);
1751 return uint32(damageResisted);
1752}
1753
1754/*static*/ float Unit::CalculateAverageResistReduction(WorldObject const* caster, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo /*= nullptr*/)
1755{
1756 float victimResistance = float(victim->GetResistance(schoolMask));
1757 if (caster)
1758 {
1759 // pets inherit 100% of masters penetration
1760 if (Player const* player = caster->GetSpellModOwner())
1761 {
1762 victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
1763 victimResistance -= float(player->GetSpellPenetrationItemMod());
1764 }
1765 else if (Unit const* unitCaster = caster->ToUnit())
1766 victimResistance += float(unitCaster->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
1767 }
1768
1769 // holy resistance exists in pve and comes from level difference, ignore template values
1770 if (schoolMask & SPELL_SCHOOL_MASK_HOLY)
1771 victimResistance = 0.0f;
1772
1773 // Chaos Bolt exception, ignore all target resistances (unknown attribute?)
1774 if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && spellInfo->Id == 116858)
1775 victimResistance = 0.0f;
1776
1777 victimResistance = std::max(victimResistance, 0.0f);
1778
1779 // level-based resistance does not apply to binary spells, and cannot be overcome by spell penetration
1780 // gameobject caster -- should it have level based resistance?
1781 if (caster && caster->GetTypeId() != TYPEID_GAMEOBJECT && (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL)))
1782 victimResistance += std::max((float(victim->GetLevelForTarget(caster)) - float(caster->GetLevelForTarget(victim))) * 5.0f, 0.0f);
1783
1784 static uint32 const bossLevel = 83;
1785 static float const bossResistanceConstant = 510.0f;
1786 uint32 level = caster ? victim->GetLevelForTarget(caster) : victim->GetLevel();
1787 float resistanceConstant = 0.0f;
1788
1789 if (level == bossLevel)
1790 resistanceConstant = bossResistanceConstant;
1791 else
1792 resistanceConstant = level * 5.0f;
1793
1794 return victimResistance / (victimResistance + resistanceConstant);
1795}
1796
1797/*static*/ void Unit::CalcAbsorbResist(DamageInfo& damageInfo, Spell* spell /*= nullptr*/)
1798{
1799 if (!damageInfo.GetVictim() || !damageInfo.GetVictim()->IsAlive() || !damageInfo.GetDamage())
1800 return;
1801
1802 uint32 resistedDamage = Unit::CalcSpellResistedDamage(damageInfo.GetAttacker(), damageInfo.GetVictim(), damageInfo.GetDamage(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo());
1803
1804 // Ignore Absorption Auras
1805 float auraAbsorbMod = 0.f;
1806 if (Unit* attacker = damageInfo.GetAttacker())
1808
1809 RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
1810
1811 int32 absorbIgnoringDamage = CalculatePct(damageInfo.GetDamage(), auraAbsorbMod);
1812
1813 if (spell)
1814 spell->CallScriptOnResistAbsorbCalculateHandlers(damageInfo, resistedDamage, absorbIgnoringDamage);
1815
1816 damageInfo.ResistDamage(resistedDamage);
1817
1818 // We're going to call functions which can modify content of the list during iteration over it's elements
1819 // Let's copy the list so we can prevent iterator invalidation
1821 std::sort(vSchoolAbsorbCopy.begin(), vSchoolAbsorbCopy.end(), Trinity::AbsorbAuraOrderPred());
1822
1823 // absorb without mana cost
1824 for (auto itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1825 {
1826 AuraEffect* absorbAurEff = *itr;
1827 // Check if aura was removed during iteration - we don't need to work on such auras
1828 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1829 if (!aurApp)
1830 continue;
1831 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1832 continue;
1833
1834 // get amount which can be still absorbed by the aura
1835 int32 currentAbsorb = absorbAurEff->GetAmount();
1836 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1837 if (currentAbsorb < 0)
1838 currentAbsorb = 0;
1839
1841 damageInfo.ModifyDamage(-absorbIgnoringDamage);
1842
1843 uint32 tempAbsorb = uint32(currentAbsorb);
1844
1845 bool defaultPrevented = false;
1846
1847 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
1848 currentAbsorb = tempAbsorb;
1849
1850 if (!defaultPrevented)
1851 {
1852 // absorb must be smaller than the damage itself
1853 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
1854
1855 damageInfo.AbsorbDamage(currentAbsorb);
1856
1857 tempAbsorb = currentAbsorb;
1858 absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
1859
1860 // Check if our aura is using amount to count damage
1861 if (absorbAurEff->GetAmount() >= 0)
1862 {
1863 // Reduce shield amount
1864 absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
1865 // Aura cannot absorb anything more - remove it
1866 if (absorbAurEff->GetAmount() <= 0)
1867 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
1868 }
1869 }
1870
1872 damageInfo.ModifyDamage(absorbIgnoringDamage);
1873
1874 if (currentAbsorb)
1875 {
1877 absorbLog.Attacker = damageInfo.GetAttacker() ? damageInfo.GetAttacker()->GetGUID() : ObjectGuid::Empty;
1878 absorbLog.Victim = damageInfo.GetVictim()->GetGUID();
1879 absorbLog.Caster = absorbAurEff->GetBase()->GetCasterGUID();
1880 absorbLog.AbsorbedSpellID = damageInfo.GetSpellInfo() ? damageInfo.GetSpellInfo()->Id : 0;
1881 absorbLog.AbsorbSpellID = absorbAurEff->GetId();
1882 absorbLog.Absorbed = currentAbsorb;
1883 absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
1884 absorbLog.LogData.Initialize(damageInfo.GetVictim());
1885 damageInfo.GetVictim()->SendCombatLogMessage(&absorbLog);
1886 }
1887 }
1888
1889 // absorb by mana cost
1891 for (auto itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1892 {
1893 AuraEffect* absorbAurEff = *itr;
1894 // Check if aura was removed during iteration - we don't need to work on such auras
1895 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1896 if (!aurApp)
1897 continue;
1898 // check damage school mask
1899 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1900 continue;
1901
1902 // get amount which can be still absorbed by the aura
1903 int32 currentAbsorb = absorbAurEff->GetAmount();
1904 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1905 if (currentAbsorb < 0)
1906 currentAbsorb = 0;
1907
1909 damageInfo.ModifyDamage(-absorbIgnoringDamage);
1910
1911 uint32 tempAbsorb = currentAbsorb;
1912
1913 bool defaultPrevented = false;
1914
1915 absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
1916 currentAbsorb = tempAbsorb;
1917
1918 if (!defaultPrevented)
1919 {
1920 // absorb must be smaller than the damage itself
1921 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
1922
1923 int32 manaReduction = currentAbsorb;
1924
1925 // lower absorb amount by talents
1926 if (float manaMultiplier = absorbAurEff->GetSpellEffectInfo().CalcValueMultiplier(absorbAurEff->GetCaster()))
1927 manaReduction = int32(float(manaReduction) * manaMultiplier);
1928
1929 int32 manaTaken = -damageInfo.GetVictim()->ModifyPower(POWER_MANA, -manaReduction);
1930
1931 // take case when mana has ended up into account
1932 currentAbsorb = currentAbsorb ? int32(float(currentAbsorb) * (float(manaTaken) / float(manaReduction))) : 0;
1933
1934 damageInfo.AbsorbDamage(currentAbsorb);
1935
1936 tempAbsorb = currentAbsorb;
1937 absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
1938
1939 // Check if our aura is using amount to count damage
1940 if (absorbAurEff->GetAmount() >= 0)
1941 {
1942 absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
1943 if ((absorbAurEff->GetAmount() <= 0))
1944 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
1945 }
1946 }
1947
1949 damageInfo.ModifyDamage(absorbIgnoringDamage);
1950
1951 if (currentAbsorb)
1952 {
1954 absorbLog.Attacker = damageInfo.GetAttacker() ? damageInfo.GetAttacker()->GetGUID() : ObjectGuid::Empty;
1955 absorbLog.Victim = damageInfo.GetVictim()->GetGUID();
1956 absorbLog.Caster = absorbAurEff->GetBase()->GetCasterGUID();
1957 absorbLog.AbsorbedSpellID = damageInfo.GetSpellInfo() ? damageInfo.GetSpellInfo()->Id : 0;
1958 absorbLog.AbsorbSpellID = absorbAurEff->GetId();
1959 absorbLog.Absorbed = currentAbsorb;
1960 absorbLog.OriginalDamage = damageInfo.GetOriginalDamage();
1961 absorbLog.LogData.Initialize(damageInfo.GetVictim());
1962 damageInfo.GetVictim()->SendCombatLogMessage(&absorbLog);
1963 }
1964 }
1965
1966 // split damage auras - only when not damaging self
1967 if (damageInfo.GetVictim() != damageInfo.GetAttacker())
1968 {
1969 // We're going to call functions which can modify content of the list during iteration over it's elements
1970 // Let's copy the list so we can prevent iterator invalidation
1972 for (auto itr = vSplitDamagePctCopy.begin(); itr != vSplitDamagePctCopy.end() && damageInfo.GetDamage() > 0; ++itr)
1973 {
1974 // Check if aura was removed during iteration - we don't need to work on such auras
1975 AuraApplication const* aurApp = (*itr)->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1976 if (!aurApp)
1977 continue;
1978
1979 // check damage school mask
1980 if (!((*itr)->GetMiscValue() & damageInfo.GetSchoolMask()))
1981 continue;
1982
1983 // Damage can be splitted only if aura has an alive caster
1984 Unit* caster = (*itr)->GetCaster();
1985 if (!caster || (caster == damageInfo.GetVictim()) || !caster->IsInWorld() || !caster->IsAlive())
1986 continue;
1987
1988 uint32 splitDamage = CalculatePct(damageInfo.GetDamage(), (*itr)->GetAmount());
1989
1990 (*itr)->GetBase()->CallScriptEffectSplitHandlers((*itr), aurApp, damageInfo, splitDamage);
1991
1992 // absorb must be smaller than the damage itself
1993 splitDamage = RoundToInterval(splitDamage, uint32(0), uint32(damageInfo.GetDamage()));
1994
1995 damageInfo.AbsorbDamage(splitDamage);
1996
1997 // check if caster is immune to damage
1998 if (caster->IsImmunedToDamage(damageInfo.GetSchoolMask()))
1999 {
2000 damageInfo.GetVictim()->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
2001 continue;
2002 }
2003
2004 uint32 split_absorb = 0;
2005 Unit::DealDamageMods(damageInfo.GetAttacker(), caster, splitDamage, &split_absorb);
2006
2007 // sparring
2008 if (Creature* victimCreature = damageInfo.GetVictim()->ToCreature())
2009 {
2010 if (victimCreature->ShouldFakeDamageFrom(damageInfo.GetAttacker()))
2011 damageInfo.ModifyDamage(damageInfo.GetDamage() * -1);
2012 }
2013
2014 SpellNonMeleeDamage log(damageInfo.GetAttacker(), caster, (*itr)->GetSpellInfo(), (*itr)->GetBase()->GetSpellVisual(), damageInfo.GetSchoolMask(), (*itr)->GetBase()->GetCastId());
2015 CleanDamage cleanDamage = CleanDamage(splitDamage, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
2016 Unit::DealDamage(damageInfo.GetAttacker(), caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
2017 log.damage = splitDamage;
2018 log.originalDamage = splitDamage;
2019 log.absorb = split_absorb;
2020 caster->SendSpellNonMeleeDamageLog(&log);
2021
2022 // break 'Fear' and similar auras
2024 }
2025 }
2026}
2027
2028/*static*/ void Unit::CalcHealAbsorb(HealInfo& healInfo)
2029{
2030 if (!healInfo.GetHeal())
2031 return;
2032
2034 for (auto i = vHealAbsorb.begin(); i != vHealAbsorb.end() && healInfo.GetHeal() > 0; ++i)
2035 {
2036 AuraEffect* absorbAurEff = *i;
2037 // Check if aura was removed during iteration - we don't need to work on such auras
2038 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(healInfo.GetTarget()->GetGUID());
2039 if (!aurApp)
2040 continue;
2041 if (!(absorbAurEff->GetMiscValue() & healInfo.GetSchoolMask()))
2042 continue;
2043
2044 // get amount which can be still absorbed by the aura
2045 int32 currentAbsorb = absorbAurEff->GetAmount();
2046 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
2047 if (currentAbsorb < 0)
2048 currentAbsorb = 0;
2049
2050 uint32 tempAbsorb = uint32(currentAbsorb);
2051
2052 bool defaultPrevented = false;
2053
2054 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, healInfo, tempAbsorb, defaultPrevented);
2055 currentAbsorb = tempAbsorb;
2056
2057 if (!defaultPrevented)
2058 {
2059 // absorb must be smaller than the heal itself
2060 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(healInfo.GetHeal()));
2061
2062 healInfo.AbsorbHeal(currentAbsorb);
2063
2064 tempAbsorb = currentAbsorb;
2065 absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, healInfo, tempAbsorb);
2066
2067 // Check if our aura is using amount to count heal
2068 if (absorbAurEff->GetAmount() >= 0)
2069 {
2070 // Reduce shield amount
2071 absorbAurEff->ChangeAmount(absorbAurEff->GetAmount() - currentAbsorb);
2072 // Aura cannot absorb anything more - remove it
2073 if (absorbAurEff->GetAmount() <= 0)
2074 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
2075 }
2076 }
2077
2078 if (currentAbsorb)
2079 {
2081 absorbLog.Healer = healInfo.GetHealer() ? healInfo.GetHealer()->GetGUID() : ObjectGuid::Empty;
2082 absorbLog.Target = healInfo.GetTarget()->GetGUID();
2083 absorbLog.AbsorbCaster = absorbAurEff->GetBase()->GetCasterGUID();
2084 absorbLog.AbsorbedSpellID = healInfo.GetSpellInfo() ? healInfo.GetSpellInfo()->Id : 0;
2085 absorbLog.AbsorbSpellID = absorbAurEff->GetId();
2086 absorbLog.Absorbed = currentAbsorb;
2087 absorbLog.OriginalHeal = healInfo.GetOriginalHeal();
2088 healInfo.GetTarget()->SendMessageToSet(absorbLog.Write(), true);
2089 }
2090 }
2091}
2092
2094{
2096 return;
2097
2099 return;
2100
2101 if (IsCreature() && !ToCreature()->CanMelee())
2102 return;
2103
2105 {
2107 if (!channeledSpell || !channeledSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_ALLOW_ACTIONS_DURING_CHANNEL))
2108 return;
2109 }
2110
2111 Unit* victim = GetVictim();
2112 if (!victim)
2113 return;
2114
2115 auto getAutoAttackError = [&]() -> Optional<AttackSwingErr>
2116 {
2117 if (!IsWithinMeleeRange(victim))
2119
2120 //120 degrees of radiant range, if player is not in boundary radius
2121 if (!IsWithinBoundaryRadius(victim) && !HasInArc(2 * float(M_PI) / 3, victim))
2123
2124 return {};
2125 };
2126
2128 {
2129 Optional<AttackSwingErr> autoAttackError = getAutoAttackError();
2130 if (!autoAttackError)
2131 {
2132 // prevent base and off attack in same time, delay attack at 0.2 sec
2133 if (haveOffhandWeapon())
2136
2137 // do attack
2140 }
2141 else
2143
2144 if (Player* attackerPlayer = ToPlayer())
2145 attackerPlayer->SetAttackSwingError(autoAttackError);
2146 }
2147
2149 {
2150 Optional<AttackSwingErr> autoAttackError = getAutoAttackError();
2151 if (!autoAttackError)
2152 {
2153 // prevent base and off attack in same time, delay attack at 0.2 sec
2156
2157 // do attack
2160 }
2161 else
2163 }
2164}
2165
2166void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra)
2167{
2169 return;
2170
2172 return;
2173
2175 return;
2176
2177 if (!victim->IsAlive())
2178 return;
2179
2180 if ((attType == BASE_ATTACK || attType == OFF_ATTACK) && !IsWithinLOSInMap(victim))
2181 return;
2182
2183 AtTargetAttacked(victim, true);
2185
2186 if (attType != BASE_ATTACK && attType != OFF_ATTACK)
2187 return; // ignore ranged case
2188
2189 if (!extra && _lastExtraAttackSpell)
2191
2192 // melee attack spell cast at main hand attack only - no normal melee dmg dealt
2193 if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL] && !extra)
2195 else
2196 {
2197 // attack can be redirected to another target
2198 victim = GetMeleeHitRedirectTarget(victim);
2199
2201 uint32 meleeAttackSpellId = 0;
2202 if (attType == BASE_ATTACK)
2203 {
2204 if (!meleeAttackOverrides.empty())
2205 meleeAttackSpellId = meleeAttackOverrides.front()->GetSpellEffectInfo().TriggerSpell;
2206 }
2207 else
2208 {
2209 auto itr = std::find_if(meleeAttackOverrides.begin(), meleeAttackOverrides.end(), [&](AuraEffect const* aurEff)
2210 {
2211 return aurEff->GetSpellEffectInfo().MiscValue != 0;
2212 });
2213 if (itr != meleeAttackOverrides.end())
2214 meleeAttackSpellId = (*itr)->GetSpellEffectInfo().MiscValue;
2215 }
2216
2217 if (!meleeAttackSpellId)
2218 {
2219 CalcDamageInfo damageInfo;
2220 CalculateMeleeDamage(victim, &damageInfo, attType);
2221 // Send log damage message to client
2222 Unit::DealDamageMods(damageInfo.Attacker, victim, damageInfo.Damage, &damageInfo.Absorb);
2223
2224 // sparring
2225 if (Creature* victimCreature = victim->ToCreature())
2226 {
2227 if (victimCreature->ShouldFakeDamageFrom(damageInfo.Attacker))
2228 damageInfo.HitInfo |= HITINFO_FAKE_DAMAGE;
2229 }
2230
2231 SendAttackStateUpdate(&damageInfo);
2232
2233 _lastDamagedTargetGuid = victim->GetGUID();
2234
2235 DealMeleeDamage(&damageInfo, true);
2236
2237 DamageInfo dmgInfo(damageInfo);
2238 Unit::ProcSkillsAndAuras(damageInfo.Attacker, damageInfo.Target, damageInfo.ProcAttacker, damageInfo.ProcVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr);
2239
2240 TC_LOG_DEBUG("entities.unit", "AttackerStateUpdate: {} attacked {} for {} dmg, absorbed {}, blocked {}, resisted {}.",
2241 GetGUID().ToString(), victim->GetGUID().ToString(), damageInfo.Damage, damageInfo.Absorb, damageInfo.Blocked, damageInfo.Resist);
2242 }
2243 else
2244 {
2245 CastSpell(victim, meleeAttackSpellId, true);
2246
2248 if (attType == OFF_ATTACK)
2249 hitInfo |= HITINFO_OFFHAND;
2250
2251 SendAttackStateUpdate(hitInfo, victim, 0, GetMeleeDamageSchoolMask(), 0, 0, 0, VICTIMSTATE_HIT, 0);
2252 }
2253 }
2254}
2255
2257{
2258 while (count)
2259 {
2260 --count;
2261 AttackerStateUpdate(victim, BASE_ATTACK, true);
2262 }
2263}
2264
2266{
2268 if (!targetGUID)
2269 {
2270 ObjectGuid selection = GetTarget();
2271 if (!selection.IsEmpty())
2272 targetGUID = selection; // Spell was cast directly (not triggered by aura)
2273 else
2274 return;
2275 }
2276
2277 extraAttacksTargets[targetGUID] += count;
2278}
2279
2281{
2282 if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks())
2283 return MELEE_HIT_EVADE;
2284
2285 // Miss chance based on melee
2286 int32 miss_chance = int32(MeleeSpellMissChance(victim, attType, nullptr) * 100.0f);
2287
2288 // Critical hit chance
2290
2291 int32 dodge_chance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
2292 int32 block_chance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
2293 int32 parry_chance = int32(GetUnitParryChance(attType, victim) * 100.0f);
2294
2295 // melee attack table implementation
2296 // outcome priority:
2297 // 1. > 2. > 3. > 4. > 5. > 6. > 7. > 8.
2298 // MISS > DODGE > PARRY > GLANCING > BLOCK > CRIT > CRUSHING > HIT
2299
2300 int32 sum = 0, tmp = 0;
2301 int32 roll = urand(0, 9999);
2302
2303 int32 attackerLevel = GetLevelForTarget(victim);
2304 int32 victimLevel = GetLevelForTarget(this);
2305
2306 // check if attack comes from behind, nobody can parry or block if attacker is behind
2307 bool canParryOrBlock = victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION);
2308
2309 // only creatures can dodge if attacker is behind
2310 bool canDodge = victim->GetTypeId() != TYPEID_PLAYER || canParryOrBlock;
2311
2312 // if victim is casting or cc'd it can't avoid attacks
2313 if (victim->IsNonMeleeSpellCast(false, false, true) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
2314 {
2315 canDodge = false;
2316 canParryOrBlock = false;
2317 }
2318
2319 // 1. MISS
2320 tmp = miss_chance;
2321 if (tmp > 0 && roll < (sum += tmp))
2322 return MELEE_HIT_MISS;
2323
2324 // always crit against a sitting target (except 0 crit chance)
2325 if (victim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !victim->IsStandState())
2326 return MELEE_HIT_CRIT;
2327
2328 // 2. DODGE
2329 if (canDodge)
2330 {
2331 tmp = dodge_chance;
2332 if (tmp > 0 // check if unit _can_ dodge
2333 && roll < (sum += tmp))
2334 return MELEE_HIT_DODGE;
2335 }
2336
2337 // 3. PARRY
2338 if (canParryOrBlock)
2339 {
2340 tmp = parry_chance;
2341 if (tmp > 0 // check if unit _can_ parry
2342 && roll < (sum += tmp))
2343 return MELEE_HIT_PARRY;
2344 }
2345
2346 // 4. GLANCING
2347 // 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)
2348 if ((GetTypeId() == TYPEID_PLAYER || IsPet()) &&
2349 victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet() &&
2350 attackerLevel + 3 < victimLevel)
2351 {
2352 // cap possible value (with bonuses > max skill)
2353 tmp = (10 + 10 * (victimLevel - attackerLevel)) * 100;
2354 if (tmp > 0 && roll < (sum += tmp))
2355 return MELEE_HIT_GLANCING;
2356 }
2357
2358 // 5. BLOCK
2359 if (canParryOrBlock)
2360 {
2361 tmp = block_chance;
2362 if (tmp > 0 // check if unit _can_ block
2363 && roll < (sum += tmp))
2364 return MELEE_HIT_BLOCK;
2365 }
2366
2367 // 6.CRIT
2368 tmp = crit_chance;
2369 if (tmp > 0 && roll < (sum += tmp))
2370 return MELEE_HIT_CRIT;
2371
2372 // 7. CRUSHING
2373 // mobs can score crushing blows if they're 4 or more levels above victim
2374 if (attackerLevel >= victimLevel + 4 &&
2375 // can be from by creature (if can) or from controlled player that considered as creature
2378 {
2379 // add 2% chance per level, min. is 15%
2380 tmp = attackerLevel - victimLevel * 1000 - 1500;
2381 if (roll < (sum += tmp))
2382 {
2383 TC_LOG_DEBUG("entities.unit", "RollMeleeOutcomeAgainst: CRUSHING <{}, {})", sum-tmp, sum);
2384 return MELEE_HIT_CRUSHING;
2385 }
2386 }
2387
2388 // 8. HIT
2389 return MELEE_HIT_NORMAL;
2390}
2391
2392uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const
2393{
2394 float minDamage = 0.0f;
2395 float maxDamage = 0.0f;
2396
2397 if (normalized || !addTotalPct)
2398 {
2399 CalculateMinMaxDamage(attType, normalized, addTotalPct, minDamage, maxDamage);
2400 if (IsInFeralForm() && attType == BASE_ATTACK)
2401 {
2402 float minOffhandDamage = 0.0f;
2403 float maxOffhandDamage = 0.0f;
2404 CalculateMinMaxDamage(OFF_ATTACK, normalized, addTotalPct, minOffhandDamage, maxOffhandDamage);
2405 minDamage += minOffhandDamage;
2406 maxDamage += maxOffhandDamage;
2407 }
2408 }
2409 else
2410 {
2411 switch (attType)
2412 {
2413 case RANGED_ATTACK:
2414 minDamage = m_unitData->MinRangedDamage;
2415 maxDamage = m_unitData->MaxRangedDamage;
2416 break;
2417 case BASE_ATTACK:
2418 minDamage = m_unitData->MinDamage;
2419 maxDamage = m_unitData->MaxDamage;
2420 if (IsInFeralForm())
2421 {
2422 minDamage += m_unitData->MinOffHandDamage;
2423 maxDamage += m_unitData->MaxOffHandDamage;
2424 }
2425 break;
2426 case OFF_ATTACK:
2427 minDamage = m_unitData->MinOffHandDamage;
2428 maxDamage = m_unitData->MaxOffHandDamage;
2429 break;
2430 default:
2431 break;
2432 }
2433 }
2434
2435 minDamage = std::max(0.f, minDamage);
2436 maxDamage = std::max(0.f, maxDamage);
2437
2438 if (minDamage > maxDamage)
2439 std::swap(minDamage, maxDamage);
2440
2441 return urand(uint32(minDamage), uint32(maxDamage));
2442}
2443
2445{
2447 packet.Attacker = GetGUID();
2448 packet.Victim = victim->GetGUID();
2449 SendMessageToSet(packet.Write(), true);
2450}
2451
2453{
2454 SendMessageToSet(WorldPackets::Combat::SAttackStop(this, victim).Write(), true);
2455
2456 if (victim)
2457 TC_LOG_DEBUG("entities.unit", "{} stopped attacking {}", GetGUID().ToString(), victim->GetGUID().ToString());
2458 else
2459 TC_LOG_DEBUG("entities.unit", "{} stopped attacking", GetGUID().ToString());
2460}
2461
2463{
2465 return true;
2466 return false;
2467}
2468
2470{
2471 if (!spellInfo)
2472 return 0;
2473
2474 int32 resistMech = 0;
2475 for (SpellEffectInfo const& effect : spellInfo->GetEffects())
2476 {
2477 if (!effect.IsEffect())
2478 break;
2479
2480 int32 effectMech = spellInfo->GetEffectMechanic(effect.EffectIndex);
2481 if (effectMech)
2482 {
2484 if (resistMech < temp)
2485 resistMech = temp;
2486 }
2487 }
2488
2489 return std::max(resistMech, 0);
2490}
2491
2492bool Unit::CanUseAttackType(uint8 attacktype) const
2493{
2494 switch (attacktype)
2495 {
2496 case BASE_ATTACK:
2498 case OFF_ATTACK:
2500 case RANGED_ATTACK:
2502 default:
2503 return true;
2504 }
2505}
2506
2507// Melee based spells hit result calculations
2509{
2510 if (spellInfo->HasAttribute(SPELL_ATTR3_NO_AVOIDANCE))
2511 return SPELL_MISS_NONE;
2512
2513 WeaponAttackType attType = BASE_ATTACK;
2514
2515 // Check damage class instead of attack type to correctly handle judgements
2516 // - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
2517 if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2518 attType = RANGED_ATTACK;
2519
2520 uint32 roll = urand(0, 9999);
2521
2522 uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, spellInfo) * 100.0f);
2523
2524 // Roll miss
2525 uint32 tmp = missChance;
2526 if (roll < tmp)
2527 return SPELL_MISS_MISS;
2528
2529 // Chance resist mechanic
2530 int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100;
2531 tmp += resist_chance;
2532 if (roll < tmp)
2533 return SPELL_MISS_RESIST;
2534
2535 // Same spells cannot be parried/dodged
2537 return SPELL_MISS_NONE;
2538
2539 bool canDodge = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_DODGE);
2540 bool canParry = !spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_PARRY);
2541 bool canBlock = !spellInfo->HasAttribute(SPELL_ATTR8_NO_ATTACK_BLOCK);
2542
2543 // if victim is casting or cc'd it can't avoid attacks
2544 if (victim->IsNonMeleeSpellCast(false, false, true) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
2545 {
2546 canDodge = false;
2547 canParry = false;
2548 canBlock = false;
2549 }
2550
2551 // Ranged attacks can only miss, resist and deflect and get blocked
2552 if (attType == RANGED_ATTACK)
2553 {
2554 canParry = false;
2555 canDodge = false;
2556
2557 // only if in front
2558 if (!victim->HasUnitState(UNIT_STATE_CONTROLLED) && (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)))
2559 {
2560 int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
2561 tmp += deflect_chance;
2562 if (roll < tmp)
2563 return SPELL_MISS_DEFLECT;
2564 }
2565 }
2566
2567 // Check for attack from behind
2568 if (!victim->HasInArc(float(M_PI), this))
2569 {
2571 {
2572 // Can't dodge from behind in PvP (but its possible in PvE)
2573 if (victim->GetTypeId() == TYPEID_PLAYER)
2574 canDodge = false;
2575 // Can't parry or block
2576 canParry = false;
2577 canBlock = false;
2578 }
2579 else // Only deterrence as of 3.3.5
2580 {
2582 canParry = false;
2583 }
2584 }
2585
2586 // Ignore combat result aura
2588 for (AuraEffect const* aurEff : ignore)
2589 {
2590 if (!aurEff->IsAffectingSpell(spellInfo))
2591 continue;
2592
2593 switch (aurEff->GetMiscValue())
2594 {
2595 case MELEE_HIT_DODGE:
2596 canDodge = false;
2597 break;
2598 case MELEE_HIT_BLOCK:
2599 canBlock = false;
2600 break;
2601 case MELEE_HIT_PARRY:
2602 canParry = false;
2603 break;
2604 default:
2605 TC_LOG_DEBUG("entities.unit", "Spell {} SPELL_AURA_IGNORE_COMBAT_RESULT has unhandled state {}", aurEff->GetId(), aurEff->GetMiscValue());
2606 break;
2607 }
2608 }
2609
2610 if (canDodge)
2611 {
2612 // Roll dodge
2613 int32 dodgeChance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
2614 if (dodgeChance < 0)
2615 dodgeChance = 0;
2616
2617 if (roll < (tmp += dodgeChance))
2618 return SPELL_MISS_DODGE;
2619 }
2620
2621 if (canParry)
2622 {
2623 // Roll parry
2624 int32 parryChance = int32(GetUnitParryChance(attType, victim) * 100.0f);
2625 if (parryChance < 0)
2626 parryChance = 0;
2627
2628 tmp += parryChance;
2629 if (roll < tmp)
2630 return SPELL_MISS_PARRY;
2631 }
2632
2633 if (canBlock)
2634 {
2635 int32 blockChance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
2636 if (blockChance < 0)
2637 blockChance = 0;
2638 tmp += blockChance;
2639
2640 if (roll < tmp)
2641 return SPELL_MISS_BLOCK;
2642 }
2643
2644 return SPELL_MISS_NONE;
2645}
2646
2647float Unit::GetUnitDodgeChance(WeaponAttackType attType, Unit const* victim) const
2648{
2649 int32 const levelDiff = victim->GetLevelForTarget(this) - GetLevelForTarget(victim);
2650
2651 float chance = 0.0f;
2652 float levelBonus = 0.0f;
2653 if (Player const* playerVictim = victim->ToPlayer())
2654 chance = playerVictim->m_activePlayerData->DodgePercentage;
2655 else
2656 {
2657 if (!victim->IsTotem())
2658 {
2659 chance = 3.0f;
2661
2662 if (levelDiff > 0)
2663 levelBonus = 1.5f * levelDiff;
2664 }
2665 }
2666
2667 chance += levelBonus;
2668
2669 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2671
2672 // reduce dodge by SPELL_AURA_MOD_ENEMY_DODGE
2674
2675 // Reduce dodge chance by attacker expertise rating
2676 if (GetTypeId() == TYPEID_PLAYER)
2677 chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
2678 else
2680 return std::max(chance, 0.0f);
2681}
2682
2683float Unit::GetUnitParryChance(WeaponAttackType attType, Unit const* victim) const
2684{
2685 int32 const levelDiff = victim->GetLevelForTarget(this) - GetLevelForTarget(victim);
2686
2687 float chance = 0.0f;
2688 float levelBonus = 0.0f;
2689 if (Player const* playerVictim = victim->ToPlayer())
2690 {
2691 if (playerVictim->CanParry())
2692 {
2693 Item* tmpitem = playerVictim->GetWeaponForAttack(BASE_ATTACK, true);
2694 if (!tmpitem)
2695 tmpitem = playerVictim->GetWeaponForAttack(OFF_ATTACK, true);
2696
2697 if (tmpitem)
2698 chance = playerVictim->m_activePlayerData->ParryPercentage;
2699 }
2700 }
2701 else
2702 {
2704 {
2705 chance = 6.0f;
2707
2708 if (levelDiff > 0)
2709 levelBonus = 1.5f * levelDiff;
2710 }
2711 }
2712
2713 chance += levelBonus;
2714
2715 // Reduce parry chance by attacker expertise rating
2716 if (GetTypeId() == TYPEID_PLAYER)
2717 chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
2718 else
2720 return std::max(chance, 0.0f);
2721}
2722
2724{
2725 float miss_chance = 5.0f;
2726
2727 return miss_chance;
2728}
2729
2730float Unit::GetUnitBlockChance(WeaponAttackType /*attType*/, Unit const* victim) const
2731{
2732 int32 const levelDiff = victim->GetLevelForTarget(this) - GetLevelForTarget(victim);
2733
2734 float chance = 0.0f;
2735 float levelBonus = 0.0f;
2736 if (Player const* playerVictim = victim->ToPlayer())
2737 {
2738 if (playerVictim->CanBlock())
2739 {
2740 Item* tmpitem = playerVictim->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2741 if (tmpitem && !tmpitem->IsBroken() && tmpitem->GetTemplate()->GetInventoryType() == INVTYPE_SHIELD)
2742 chance = playerVictim->m_activePlayerData->BlockPercentage;
2743 }
2744 }
2745 else
2746 {
2748 {
2749 chance = 3.0f;
2751
2752 if (levelDiff > 0)
2753 levelBonus = 1.5f * levelDiff;
2754 }
2755 }
2756
2757 chance += levelBonus;
2758 return std::max(chance, 0.0f);
2759}
2760
2762{
2763 float chance = 0.0f;
2764 if (Player const* thisPlayer = ToPlayer())
2765 {
2766 switch (attackType)
2767 {
2768 case BASE_ATTACK:
2769 chance = thisPlayer->m_activePlayerData->CritPercentage;
2770 break;
2771 case OFF_ATTACK:
2772 chance = thisPlayer->m_activePlayerData->OffhandCritPercentage;
2773 break;
2774 case RANGED_ATTACK:
2775 chance = thisPlayer->m_activePlayerData->RangedCritPercentage;
2776 break;
2777 // Just for good manner
2778 default:
2779 chance = 0.0f;
2780 break;
2781 }
2782 }
2783 else
2784 {
2785 if (!(ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT))
2786 {
2787 chance = 5.0f;
2790 }
2791 }
2792
2793 return chance;
2794}
2795
2796float Unit::GetUnitCriticalChanceTaken(Unit const* attacker, WeaponAttackType attackType, float critDone) const
2797{
2798 float chance = critDone;
2799
2800 // flat aura mods
2801 if (attackType != RANGED_ATTACK)
2803
2805 {
2806 return !HealthBelowPct(aurEff->GetMiscValueB());
2807 });
2808
2809 chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [attacker](AuraEffect const* aurEff) -> bool
2810 {
2811 return aurEff->GetCasterGUID() == attacker->GetGUID();
2812 });
2813
2814 if (TempSummon const* tempSummon = attacker->ToTempSummon())
2815 {
2816 chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_PET, [tempSummon](AuraEffect const* aurEff) -> bool
2817 {
2818 return aurEff->GetCasterGUID() == tempSummon->GetSummonerGUID();
2819 });
2820 }
2821
2823
2824 return std::max(chance, 0.0f);
2825}
2826
2827float Unit::GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const* victim) const
2828{
2829 float chance = GetUnitCriticalChanceDone(attackType);
2830 return victim->GetUnitCriticalChanceTaken(this, attackType, chance);
2831}
2832
2834{
2835 while (!m_removedAuras.empty())
2836 {
2837 delete m_removedAuras.front();
2838 m_removedAuras.pop_front();
2839 }
2840
2842}
2843
2845{
2846 if (!_spellHistory->IsPaused())
2847 _spellHistory->Update();
2848
2851
2852 // remove finished spells from current pointers
2853 for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
2854 {
2855 if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED)
2856 {
2857 m_currentSpells[i]->SetReferencedFromCurrent(false);
2858 m_currentSpells[i] = nullptr; // remove pointer
2859 }
2860 }
2861
2862 // m_auraUpdateIterator can be updated in indirect called code at aura remove to skip next planned to update but removed auras
2864 {
2865 Aura* i_aura = m_auraUpdateIterator->second;
2866 ++m_auraUpdateIterator; // need shift to next for allow update if need into aura update
2867 i_aura->UpdateOwner(time, this);
2868 }
2869
2870 // remove expired auras - do that after updates(used in scripts?)
2871 for (AuraMap::iterator i = m_ownedAuras.begin(); i != m_ownedAuras.end();)
2872 {
2873 if (i->second->IsExpired())
2875 else if (i->second->GetSpellInfo()->IsChanneled() && i->second->GetCasterGUID() != GetGUID() && !ObjectAccessor::GetWorldObject(*this, i->second->GetCasterGUID()))
2876 RemoveOwnedAura(i, AURA_REMOVE_BY_CANCEL); // remove channeled auras when caster is not on the same map
2877 else
2878 ++i;
2879 }
2880
2881 for (AuraApplication* visibleAura : m_visibleAurasToUpdate)
2882 visibleAura->ClientUpdate();
2883
2884 m_visibleAurasToUpdate.clear();
2885
2887
2888 if (!m_gameObj.empty())
2889 {
2890 GameObjectList::iterator itr;
2891 for (itr = m_gameObj.begin(); itr != m_gameObj.end();)
2892 {
2893 if (!(*itr)->isSpawned())
2894 {
2895 (*itr)->SetOwnerGUID(ObjectGuid::Empty);
2896 (*itr)->SetRespawnTime(0);
2897 (*itr)->Delete();
2898 m_gameObj.erase(itr++);
2899 }
2900 else
2901 ++itr;
2902 }
2903 }
2904}
2905
2907{
2908 SpellInfo const* autoRepeatSpellInfo = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo;
2909
2910 // check "realtime" interrupts
2911 // don't cancel spells which are affected by a SPELL_AURA_CAST_WHILE_WALKING effect
2912 if ((isMoving() && m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckMovement() != SPELL_CAST_OK) || IsNonMeleeSpellCast(false, false, true, autoRepeatSpellInfo->Id == 75))
2913 {
2914 // cancel wand shoot
2915 if (autoRepeatSpellInfo->Id != 75)
2917 return;
2918 }
2919
2920 // castroutine
2922 {
2923 // Check if able to cast
2924 SpellCastResult result = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true);
2925 if (result != SPELL_CAST_OK)
2926 {
2927 if (autoRepeatSpellInfo->Id != 75)
2929 else if (GetTypeId() == TYPEID_PLAYER)
2930 Spell::SendCastResult(ToPlayer(), autoRepeatSpellInfo, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_SpellVisual, m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_castId, result);
2931
2932 return;
2933 }
2934
2935 // we want to shoot
2936 Spell* spell = new Spell(this, autoRepeatSpellInfo, TRIGGERED_IGNORE_GCD);
2938 }
2939}
2940
2942{
2943 ASSERT(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
2944
2945 CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer();
2946
2947 if (pSpell == m_currentSpells[CSpellType]) // avoid breaking self
2948 return;
2949
2950 // special breakage effects:
2951 switch (CSpellType)
2952 {
2954 {
2956
2957 // generic spells always break channeled not delayed spells
2960
2961 // autorepeat breaking
2963 {
2964 // break autorepeat if not Auto Shot
2965 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75)
2967 }
2968 if (pSpell->GetCastTime() > 0)
2970
2971 break;
2972 }
2974 {
2975 // channel spells always break generic non-delayed and any channeled spells
2978
2979 // it also does break autorepeat if not Auto Shot
2981 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75)
2984
2985 break;
2986 }
2988 {
2989 if (m_currentSpells[CSpellType] && m_currentSpells[CSpellType]->getState() == SPELL_STATE_IDLE)
2990 m_currentSpells[CSpellType]->setState(SPELL_STATE_FINISHED);
2991
2992 // only Auto Shoot does not break anything
2993 if (pSpell->GetSpellInfo()->Id != 75)
2994 {
2995 // generic autorepeats break generic non-delayed and channeled non-delayed spells
2998 }
2999
3000 break;
3001 }
3002 default:
3003 break; // other spell types don't break anything now
3004 }
3005
3006 // current spell (if it is still here) may be safely deleted now
3007 if (m_currentSpells[CSpellType])
3008 m_currentSpells[CSpellType]->SetReferencedFromCurrent(false);
3009
3010 // set new current spell
3011 m_currentSpells[CSpellType] = pSpell;
3012 pSpell->SetReferencedFromCurrent(true);
3013
3014 pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]);
3015}
3016
3017void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool withInstant)
3018{
3019 //TC_LOG_DEBUG("entities.unit", "Interrupt spell for unit {}.", GetEntry());
3020 Spell* spell = m_currentSpells[spellType];
3021 if (spell
3022 && (withDelayed || spell->getState() != SPELL_STATE_DELAYED)
3023 && (withInstant || spell->GetCastTime() > 0 || spell->getState() == SPELL_STATE_CASTING))
3024 {
3025 // for example, do not let self-stun aura interrupt itself
3026 if (!spell->IsInterruptable())
3027 return;
3028
3029 // send autorepeat cancel message for autorepeat spells
3030 if (spellType == CURRENT_AUTOREPEAT_SPELL)
3031 if (GetTypeId() == TYPEID_PLAYER)
3033
3034 if (spell->getState() != SPELL_STATE_FINISHED)
3035 spell->cancel();
3036 else
3037 {
3038 m_currentSpells[spellType] = nullptr;
3039 spell->SetReferencedFromCurrent(false);
3040 }
3041
3042 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
3043 ToCreature()->AI()->OnSpellFailed(spell->GetSpellInfo());
3044 }
3045}
3046
3047void Unit::FinishSpell(CurrentSpellTypes spellType, SpellCastResult result /*= SPELL_CAST_OK*/)
3048{
3049 Spell* spell = m_currentSpells[spellType];
3050 if (!spell)
3051 return;
3052
3053 if (spellType == CURRENT_CHANNELED_SPELL)
3054 spell->SendChannelUpdate(0);
3055
3056 spell->finish(result);
3057}
3058
3059bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAutorepeat, bool isAutoshoot, bool skipInstant) const
3060{
3061 // We don't do loop here to explicitly show that melee spell is excluded.
3062 // Maybe later some special spells will be excluded too.
3063
3064 // generic spells are cast when they are not finished and not delayed
3067 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED))
3068 {
3069 if (!skipInstant || m_currentSpells[CURRENT_GENERIC_SPELL]->GetCastTime())
3070 {
3071 if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)))
3072 return true;
3073 }
3074 }
3075 // channeled spells may be delayed, but they are still considered cast
3076 if (!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
3078 {
3079 if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS)))
3080 return true;
3081 }
3082 // autorepeat spells may be finished or delayed, but they are still considered cast
3083 if (!skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
3084 return true;
3085
3086 return false;
3087}
3088
3089void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id, bool withInstant)
3090{
3091 // generic spells are interrupted if they are not finished or delayed
3092 if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == spell_id))
3093 InterruptSpell(CURRENT_GENERIC_SPELL, withDelayed, withInstant);
3094
3095 // autorepeat spells are interrupted if they are not finished or delayed
3096 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == spell_id))
3097 InterruptSpell(CURRENT_AUTOREPEAT_SPELL, withDelayed, withInstant);
3098
3099 // channeled spells are interrupted if they are not finished, even if they are delayed
3100 if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id == spell_id))
3102}
3103
3105{
3106 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
3107 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id == spell_id)
3108 return m_currentSpells[i];
3109 return nullptr;
3110}
3111
3113{
3114 if (Spell const* spell = FindCurrentSpellBySpellId(spell_id))
3115 return spell->GetCastTime();
3116 return 0;
3117}
3118
3120{
3121 // can always move when not casting
3123 return false;
3124
3126 if (CanCastSpellWhileMoving(spell->GetSpellInfo()) || spell->getState() == SPELL_STATE_FINISHED ||
3127 !spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement))
3128 return false;
3129
3130 // channeled spells during channel stage (after the initial cast timer) allow movement with a specific spell attribute
3132 if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive())
3133 if (spell->GetSpellInfo()->IsMoveAllowedChannel() || CanCastSpellWhileMoving(spell->GetSpellInfo()))
3134 return false;
3135
3136 // prohibit movement for all other spell casts
3137 return true;
3138}
3139
3140bool Unit::CanCastSpellWhileMoving(SpellInfo const* spellInfo) const
3141{
3143 return true;
3144
3146 return true;
3147
3148 for (uint32 label : spellInfo->Labels)
3150 return true;
3151
3152 return false;
3153}
3154
3155bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
3156{
3157 return IsWithinDistInMap(target, distance) && HasInArc(arc, target);
3158}
3159
3160bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
3161{
3162 return IsWithinDistInMap(target, distance) && !HasInArc(2 * float(M_PI) - arc, target);
3163}
3164
3166{
3167 // Aquatic creatures are not allowed to leave liquids
3168 if (!IsInWater() && c->IsAquatic())
3169 return false;
3170
3171 // Underwater special case. Some creatures may not go below liquid surfaces
3172 if (IsUnderWater() && c->CannotPenetrateWater())
3173 return false;
3174
3175 // Water checks
3176 if (IsInWater() && !c->CanEnterWater())
3177 return false;
3178
3179 // Some creatures are tied to the ocean floor and cannot chase swimming targets.
3181 return false;
3182
3183 return true;
3184}
3185
3187{
3189}
3190
3192{
3194}
3195
3197{
3199}
3200
3202{
3203 ZLiquidStatus oldLiquidStatus = GetLiquidStatus();
3205 ProcessTerrainStatusUpdate(oldLiquidStatus, data.liquidInfo);
3206}
3207
3209{
3210 if (!IsControlledByPlayer())
3211 return;
3212
3213 // remove appropriate auras if we are swimming/not swimming respectively
3214 if (IsInWater())
3216 else
3218
3219 // liquid aura handling
3220 LiquidTypeEntry const* curLiquid = nullptr;
3221 if (IsInWater() && newLiquidData)
3222 curLiquid = sLiquidTypeStore.LookupEntry(newLiquidData->entry);
3223 if (curLiquid != _lastLiquid)
3224 {
3228
3229 // Set _lastLiquid before casting liquid spell to avoid infinite loops
3230 _lastLiquid = curLiquid;
3231
3232 if (curLiquid && curLiquid->SpellID && (!player || !player->IsGameMaster()))
3233 CastSpell(this, curLiquid->SpellID, true);
3234 }
3235
3236 // mount capability depends on liquid state change
3237 if (oldLiquidStatus != GetLiquidStatus())
3239}
3240
3242{
3244}
3245
3247{
3248 ASSERT(!createInfo.CasterGUID.IsEmpty() || createInfo.Caster);
3249
3250 // Check if these can stack anyway
3251 if (!createInfo.CasterGUID && !createInfo.GetSpellInfo()->IsStackableOnOneSlotWithDifferentCasters())
3252 createInfo.CasterGUID = createInfo.Caster->GetGUID();
3253
3254 // passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
3255 if (!createInfo.GetSpellInfo()->IsMultiSlotAura())
3256 {
3257 // check if cast item changed
3258 ObjectGuid castItemGUID = createInfo.CastItemGUID;
3259
3260 // find current aura from spell and change it's stackamount, or refresh it's duration
3261 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))
3262 {
3263 // effect masks do not match
3264 // extremely rare case
3265 // let's just recreate aura
3266 if (createInfo.GetAuraEffectMask() != foundAura->GetEffectMask())
3267 return nullptr;
3268
3269 // update basepoints with new values - effect amount will be recalculated in ModStackAmount
3270 for (SpellEffectInfo const& spellEffectInfo : createInfo.GetSpellInfo()->GetEffects())
3271 {
3272 AuraEffect const* auraEff = foundAura->GetEffect(spellEffectInfo.EffectIndex);
3273 if (!auraEff)
3274 continue;
3275
3276 int32 bp;
3277 if (createInfo.BaseAmount)
3278 bp = *(createInfo.BaseAmount + spellEffectInfo.EffectIndex);
3279 else
3280 bp = int32(spellEffectInfo.BasePoints);
3281
3282 int32* oldBP = const_cast<int32*>(&(auraEff->m_baseAmount));
3283 if (spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::AuraPointsStack))
3284 *oldBP += bp;
3285 else
3286 *oldBP = bp;
3287 }
3288
3289 // correct cast item guid if needed
3290 if (castItemGUID != foundAura->GetCastItemGUID())
3291 {
3292 ObjectGuid* oldGUID = const_cast<ObjectGuid*>(&foundAura->m_castItemGuid);
3293 *oldGUID = castItemGUID;
3294 uint32* oldItemId = const_cast<uint32*>(&foundAura->m_castItemId);
3295 *oldItemId = createInfo.CastItemId;
3296 int32* oldItemLevel = const_cast<int32*>(&foundAura->m_castItemLevel);
3297 *oldItemLevel = createInfo.CastItemLevel;
3298 }
3299
3300 // try to increase stack amount
3301 foundAura->ModStackAmount(1, AURA_REMOVE_BY_DEFAULT, createInfo.ResetPeriodicTimer);
3302 return foundAura;
3303 }
3304 }
3305
3306 return nullptr;
3307}
3308
3309void Unit::_AddAura(UnitAura* aura, Unit* caster)
3310{
3312 m_ownedAuras.emplace(aura->GetId(), aura);
3313
3314 _RemoveNoStackAurasDueToAura(aura, true);
3315
3316 if (aura->IsRemoved())
3317 return;
3318
3319 aura->SetIsSingleTarget(caster && aura->GetSpellInfo()->IsSingleTarget());
3320 if (aura->IsSingleTarget())
3321 {
3323 /* @HACK: Player is not in world during loading auras.
3324 * Single target auras are not saved or loaded from database
3325 * but may be created as a result of aura links.
3326 */
3327
3328 std::vector<Aura*> aurasSharingLimit;
3329 // remove other single target auras
3330 for (Aura* scAura : caster->GetSingleCastAuras())
3331 if (scAura->IsSingleTargetWith(aura))
3332 aurasSharingLimit.push_back(scAura);
3333
3334 // register single target aura
3335 caster->GetSingleCastAuras().push_front(aura);
3336
3337 uint32 maxOtherAuras = aura->GetSpellInfo()->MaxAffectedTargets - 1;
3338 while (aurasSharingLimit.size() > maxOtherAuras)
3339 {
3340 aurasSharingLimit.back()->Remove();
3341 aurasSharingLimit.pop_back();
3342 }
3343 }
3344}
3345
3346// creates aura application instance and registers it in lists
3347// aura application effects are handled separately to prevent aura list corruption
3349{
3350 // can't apply aura on unit which is going to be deleted - to not create a memory leak
3352
3353 // just return if the aura has been already removed
3354 // this can happen if OnEffectHitTarget() script hook killed the unit or the aura owner (which can be different)
3355 if (aura->IsRemoved())
3356 {
3357 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());
3358 return nullptr;
3359 }
3360
3361 // aura mustn't be already applied on target
3362 ASSERT (!aura->IsAppliedOnTarget(GetGUID()) && "Unit::_CreateAuraApplication: aura musn't be applied on target");
3363
3364 SpellInfo const* aurSpellInfo = aura->GetSpellInfo();
3365 uint32 aurId = aurSpellInfo->Id;
3366
3367 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3368 if (!IsAlive() && !aurSpellInfo->IsDeathPersistent() &&
3369 (GetTypeId() != TYPEID_PLAYER || !ToPlayer()->GetSession()->PlayerLoading()))
3370 return nullptr;
3371
3372 Unit* caster = aura->GetCaster();
3373
3374 AuraApplication * aurApp = new AuraApplication(this, caster, aura, effMask);
3375 m_appliedAuras.insert(AuraApplicationMap::value_type(aurId, aurApp));
3376
3377 if (aurSpellInfo->HasAnyAuraInterruptFlag())
3378 {
3379 m_interruptableAuras.push_front(aurApp);
3380 AddInterruptMask(aurSpellInfo->AuraInterruptFlags, aurSpellInfo->AuraInterruptFlags2);
3381 }
3382
3383 if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState())
3384 m_auraStateAuras.insert(AuraStateAurasMap::value_type(aState, aurApp));
3385
3386 aura->_ApplyForTarget(this, caster, aurApp);
3387 return aurApp;
3388}
3389
3390void Unit::_ApplyAuraEffect(Aura* aura, uint8 effIndex)
3391{
3392 ASSERT(aura);
3393 ASSERT(aura->HasEffect(effIndex));
3395 ASSERT(aurApp);
3396 if (!aurApp->GetEffectMask())
3397 _ApplyAura(aurApp, 1 << effIndex);
3398 else
3399 aurApp->_HandleEffect(effIndex, true);
3400}
3401
3402// handles effects of aura application
3403// should be done after registering aura in lists
3405{
3406 Aura* aura = aurApp->GetBase();
3407
3408 _RemoveNoStackAurasDueToAura(aura, false);
3409
3410 if (aurApp->GetRemoveMode())
3411 return;
3412
3413 // Update target aura state flag
3414 if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState())
3415 {
3416 uint32 aStateMask = (1 << (aState - 1));
3417 // force update so the new caster registers it
3418 if ((aStateMask & PER_CASTER_AURA_STATE_MASK) && *m_unitData->AuraState & aStateMask)
3420 else
3421 ModifyAuraState(aState, true);
3422 }
3423
3424 if (aurApp->GetRemoveMode())
3425 return;
3426
3427 // Sitdown on apply aura req seated
3430
3431 Unit* caster = aura->GetCaster();
3432
3433 if (aurApp->GetRemoveMode())
3434 return;
3435
3436 aura->HandleAuraSpecificMods(aurApp, caster, true, false);
3437
3438 // apply effects of the aura
3439 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
3440 {
3441 if (effMask & 1 << i && (!aurApp->GetRemoveMode()))
3442 aurApp->_HandleEffect(i, true);
3443 }
3444
3445 if (Player* player = ToPlayer())
3446 {
3447 if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId()))
3448 player->UpdateVisibleObjectInteractions(false, true, false, false);
3449
3450 player->FailCriteria(CriteriaFailEvent::GainAura, aurApp->GetBase()->GetId());
3451 player->StartCriteria(CriteriaStartEvent::GainAura, aurApp->GetBase()->GetId());
3452 player->UpdateCriteria(CriteriaType::GainAura, aurApp->GetBase()->GetId());
3453 }
3454}
3455
3456// removes aura application from lists and unapplies effects
3457void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMode)
3458{
3459 AuraApplication * aurApp = i->second;
3460 ASSERT(aurApp);
3461 ASSERT(!aurApp->GetRemoveMode());
3462 ASSERT(aurApp->GetTarget() == this);
3463
3464 aurApp->SetRemoveMode(removeMode);
3465 Aura* aura = aurApp->GetBase();
3466 TC_LOG_DEBUG("spells", "Aura {} now is remove mode {}", aura->GetId(), removeMode);
3467
3468 // dead loop is killing the server probably
3469 ASSERT(m_removedAurasCount < 0xFFFFFFFF);
3470
3472
3473 Unit* caster = aura->GetCaster();
3474
3475 // Remove all pointers from lists here to prevent possible pointer invalidation on spellcast/auraapply/auraremove
3476 m_appliedAuras.erase(i);
3477
3479 {
3482 }
3483
3484 bool auraStateFound = false;
3485 AuraStateType auraState = aura->GetSpellInfo()->GetAuraState();
3486 if (auraState)
3487 {
3488 bool canBreak = false;
3489 // Get mask of all aurastates from remaining auras
3490 for (AuraStateAurasMap::iterator itr = m_auraStateAuras.lower_bound(auraState); itr != m_auraStateAuras.upper_bound(auraState) && !(auraStateFound && canBreak);)
3491 {
3492 if (itr->second == aurApp)
3493 {
3494 m_auraStateAuras.erase(itr);
3495 itr = m_auraStateAuras.lower_bound(auraState);
3496 canBreak = true;
3497 continue;
3498 }
3499 auraStateFound = true;
3500 ++itr;
3501 }
3502 }
3503
3504 aurApp->_Remove();
3505 aura->_UnapplyForTarget(this, caster, aurApp);
3506
3507 // remove effects of the spell - needs to be done after removing aura from lists
3508 for (uint8 itr = 0; itr < MAX_SPELL_EFFECTS; ++itr)
3509 {
3510 if (aurApp->HasEffect(itr))
3511 aurApp->_HandleEffect(itr, false);
3512 }
3513
3514 // all effect mustn't be applied
3515 ASSERT(!aurApp->GetEffectMask());
3516
3517 // Remove totem at next update if totem loses its aura
3518 if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE && GetTypeId() == TYPEID_UNIT && IsTotem())
3519 {
3520 if (ToTotem()->GetSpell() == aura->GetId() && ToTotem()->GetTotemType() == TOTEM_PASSIVE)
3522 }
3523
3524 // Remove aurastates only if needed and were not found
3525 if (auraState)
3526 {
3527 if (!auraStateFound)
3528 ModifyAuraState(auraState, false);
3529 else
3530 {
3531 // update for casters, some shouldn't 'see' the aura state
3532 uint32 aStateMask = (1 << (auraState - 1));
3533 if ((aStateMask & PER_CASTER_AURA_STATE_MASK) != 0)
3535 }
3536 }
3537
3538 aura->HandleAuraSpecificMods(aurApp, caster, false, false);
3539
3540 if (Player* player = ToPlayer())
3541 {
3542 if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId()))
3543 player->UpdateVisibleObjectInteractions(false, true, false, false);
3544
3545 player->FailCriteria(CriteriaFailEvent::LoseAura, aurApp->GetBase()->GetId());
3546 }
3547
3548 i = m_appliedAuras.begin();
3549}
3550
3552{
3553 // aura can be removed from unit only if it's applied on it, shouldn't happen
3554 ASSERT(aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) == aurApp);
3555
3556 uint32 spellId = aurApp->GetBase()->GetId();
3557 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3558
3559 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3560 {
3561 if (iter->second == aurApp)
3562 {
3563 _UnapplyAura(iter, removeMode);
3564 return;
3565 }
3566 else
3567 ++iter;
3568 }
3569 ABORT();
3570}
3571
3573{
3574 SpellInfo const* spellProto = aura->GetSpellInfo();
3575
3576 // passive spell special case (only non stackable with ranks)
3577 if (spellProto->IsPassiveStackableWithRanks())
3578 return;
3579
3580 if (!IsHighestExclusiveAura(aura))
3581 {
3582 aura->Remove();
3583 return;
3584 }
3585
3586 if (owned)
3587 RemoveOwnedAuras([aura](Aura const* ownedAura) { return !aura->CanStackWith(ownedAura); }, AURA_REMOVE_BY_DEFAULT);
3588 else
3589 RemoveAppliedAuras([aura](AuraApplication const* appliedAura) { return !aura->CanStackWith(appliedAura->GetBase()); }, AURA_REMOVE_BY_DEFAULT);
3590}
3591
3593{
3594 if (apply)
3595 {
3596 m_modAuras[aurEff->GetAuraType()].push_front(aurEff);
3597 if (Player* player = ToPlayer())
3598 {
3599 player->StartCriteria(CriteriaStartEvent::GainAuraEffect, aurEff->GetAuraType());
3600 player->FailCriteria(CriteriaFailEvent::GainAuraEffect, aurEff->GetAuraType());
3601 }
3602 }
3603 else
3605}
3606
3607// All aura base removes should go through this function!
3608void Unit::RemoveOwnedAura(AuraMap::iterator& i, AuraRemoveMode removeMode)
3609{
3610 Aura* aura = i->second;
3611 ASSERT(!aura->IsRemoved());
3612
3613 // if unit currently update aura list then make safe update iterator shift to next
3614 if (m_auraUpdateIterator == i)
3616
3617 m_ownedAuras.erase(i);
3618 m_removedAuras.push_front(aura);
3619
3620 // Unregister single target aura
3621 if (aura->IsSingleTarget())
3622 aura->UnregisterSingleTarget();
3623
3624 aura->_Remove(removeMode);
3625
3626 i = m_ownedAuras.begin();
3627}
3628
3629void Unit::RemoveOwnedAura(uint32 spellId, ObjectGuid casterGUID, uint32 reqEffMask, AuraRemoveMode removeMode)
3630{
3631 for (AuraMap::iterator itr = m_ownedAuras.lower_bound(spellId); itr != m_ownedAuras.upper_bound(spellId);)
3632 if (((itr->second->GetEffectMask() & reqEffMask) == reqEffMask) && (!casterGUID || itr->second->GetCasterGUID() == casterGUID))
3633 {
3634 RemoveOwnedAura(itr, removeMode);
3635 itr = m_ownedAuras.lower_bound(spellId);
3636 }
3637 else
3638 ++itr;
3639}
3640
3642{
3643 if (aura->IsRemoved())
3644 return;
3645
3646 ASSERT(aura->GetOwner() == this);
3647
3648 if (removeMode == AURA_REMOVE_NONE)
3649 {
3650 TC_LOG_ERROR("spells", "Unit::RemoveOwnedAura() called with unallowed removeMode AURA_REMOVE_NONE, spellId {}", aura->GetId());
3651 return;
3652 }
3653
3654 uint32 spellId = aura->GetId();
3655 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3656
3657 for (AuraMap::iterator itr = range.first; itr != range.second; ++itr)
3658 {
3659 if (itr->second == aura)
3660 {
3661 RemoveOwnedAura(itr, removeMode);
3662 return;
3663 }
3664 }
3665
3666 ABORT();
3667}
3668
3669Aura* Unit::GetOwnedAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, Aura* except) const
3670{
3671 AuraMapBounds range = m_ownedAuras.equal_range(spellId);
3672 for (AuraMap::const_iterator itr = range.first; itr != range.second; ++itr)
3673 {
3674 if (((itr->second->GetEffectMask() & reqEffMask) == reqEffMask)
3675 && (!casterGUID || itr->second->GetCasterGUID() == casterGUID)
3676 && (!itemCasterGUID || itr->second->GetCastItemGUID() == itemCasterGUID)
3677 && (!except || except != itr->second))
3678 {
3679 return itr->second;
3680 }
3681 }
3682 return nullptr;
3683}
3684
3685void Unit::RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode)
3686{
3687 AuraApplication * aurApp = i->second;
3688 // Do not remove aura which is already being removed
3689 if (aurApp->GetRemoveMode())
3690 return;
3691 Aura* aura = aurApp->GetBase();
3692 _UnapplyAura(i, mode);
3693 // Remove aura - for Area and Target auras
3694 if (aura->GetOwner() == this)
3695 aura->Remove(mode);
3696}
3697
3698void Unit::RemoveAura(uint32 spellId, ObjectGuid caster, uint32 reqEffMask, AuraRemoveMode removeMode)
3699{
3700 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3701 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3702 {
3703 Aura const* aura = iter->second->GetBase();
3704 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
3705 && (!caster || aura->GetCasterGUID() == caster))
3706 {
3707 RemoveAura(iter, removeMode);
3708 return;
3709 }
3710 else
3711 ++iter;
3712 }
3713}
3714
3716{
3717 // we've special situation here, RemoveAura called while during aura removal
3718 // this kind of call is needed only when aura effect removal handler
3719 // or event triggered by it expects to remove
3720 // not yet removed effects of an aura
3721 if (aurApp->GetRemoveMode())
3722 {
3723 // remove remaining effects of an aura
3724 for (uint8 itr = 0; itr < MAX_SPELL_EFFECTS; ++itr)
3725 {
3726 if (aurApp->HasEffect(itr))
3727 aurApp->_HandleEffect(itr, false);
3728 }
3729 return;
3730 }
3731 // no need to remove
3732 if (aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) != aurApp || aurApp->GetBase()->IsRemoved())
3733 return;
3734
3735 uint32 spellId = aurApp->GetBase()->GetId();
3736 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3737
3738 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3739 {
3740 if (aurApp == iter->second)
3741 {
3742 RemoveAura(iter, mode);
3743 return;
3744 }
3745 else
3746 ++iter;
3747 }
3748}
3749
3751{
3752 if (aura->IsRemoved())
3753 return;
3754 if (AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID()))
3755 RemoveAura(aurApp, mode);
3756}
3757
3758void Unit::RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3759{
3760 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
3761 {
3762 if (check(iter->second))
3763 {
3764 RemoveAura(iter, removeMode);
3765 continue;
3766 }
3767 ++iter;
3768 }
3769}
3770
3771void Unit::RemoveOwnedAuras(std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3772{
3773 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
3774 {
3775 if (check(iter->second))
3776 {
3777 RemoveOwnedAura(iter, removeMode);
3778 continue;
3779 }
3780 ++iter;
3781 }
3782}
3783
3784void Unit::RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3785{
3786 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3787 {
3788 if (check(iter->second))
3789 {
3790 RemoveAura(iter, removeMode);
3791 iter = m_appliedAuras.lower_bound(spellId);
3792 continue;
3793 }
3794 ++iter;
3795 }
3796}
3797
3798void Unit::RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3799{
3800 for (AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
3801 {
3802 if (check(iter->second))
3803 {
3804 RemoveOwnedAura(iter, removeMode);
3805 iter = m_ownedAuras.lower_bound(spellId);
3806 continue;
3807 }
3808 ++iter;
3809 }
3810}
3811
3812void Unit::RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3813{
3814 for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
3815 {
3816 Aura* aura = (*iter)->GetBase();
3818 ASSERT(aurApp);
3819
3820 ++iter;
3821 if (check(aurApp))
3822 {
3823 uint32 removedAuras = m_removedAurasCount;
3824 RemoveAura(aurApp, removeMode);
3825 if (m_removedAurasCount > removedAuras + 1)
3826 iter = m_modAuras[auraType].begin();
3827 }
3828 }
3829}
3830
3831void Unit::RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID, uint32 reqEffMask, AuraRemoveMode removeMode)
3832{
3833 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3834 {
3835 Aura const* aura = iter->second->GetBase();
3836 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
3837 && (!casterGUID || aura->GetCasterGUID() == casterGUID))
3838 {
3839 RemoveAura(iter, removeMode);
3840 iter = m_appliedAuras.lower_bound(spellId);
3841 }
3842 else
3843 ++iter;
3844 }
3845}
3846
3847void Unit::RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID, AuraRemoveMode removeMode, uint16 num)
3848{
3849 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3850 for (AuraMap::iterator iter = range.first; iter != range.second;)
3851 {
3852 Aura* aura = iter->second;
3853 if ((aura->GetType() == UNIT_AURA_TYPE)
3854 && (!casterGUID || aura->GetCasterGUID() == casterGUID))
3855 {
3856 aura->ModStackAmount(-num, removeMode);
3857 return;
3858 }
3859 else
3860 ++iter;
3861 }
3862}
3863
3864void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject* dispeller, uint8 chargesRemoved /*= 1*/)
3865{
3866 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3867 for (AuraMap::iterator iter = range.first; iter != range.second;)
3868 {
3869 Aura* aura = iter->second;
3870 if (aura->GetCasterGUID() == casterGUID)
3871 {
3872 DispelInfo dispelInfo(dispeller, dispellerSpellId, chargesRemoved);
3873
3874 // Call OnDispel hook on AuraScript
3875 aura->CallScriptDispel(&dispelInfo);
3876
3879 else
3881
3882 // Call AfterDispel hook on AuraScript
3883 aura->CallScriptAfterDispel(&dispelInfo);
3884
3885 return;
3886 }
3887 else
3888 ++iter;
3889 }
3890}
3891
3892void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject* stealer, int32 stolenCharges /*= 1*/)
3893{
3894 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3895 for (AuraMap::iterator iter = range.first; iter != range.second;)
3896 {
3897 Aura* aura = iter->second;
3898 if (aura->GetCasterGUID() == casterGUID)
3899 {
3900 int32 damage[MAX_SPELL_EFFECTS];
3901 int32 baseDamage[MAX_SPELL_EFFECTS];
3902 uint32 effMask = 0;
3903 uint32 recalculateMask = 0;
3904 Unit* caster = aura->GetCaster();
3905 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
3906 {
3907 if (aura->GetEffect(i))
3908 {
3909 baseDamage[i] = aura->GetEffect(i)->GetBaseAmount();
3910 damage[i] = aura->GetEffect(i)->GetAmount();
3911 effMask |= 1 << i;
3912 if (aura->GetEffect(i)->CanBeRecalculated())
3913 recalculateMask |= 1 << i;
3914 }
3915 else
3916 {
3917 baseDamage[i] = 0;
3918 damage[i] = 0;
3919 }
3920 }
3921
3923 // Cast duration to unsigned to prevent permanent aura's such as Righteous Fury being permanently added to caster
3924 uint32 dur = std::min(2u * MINUTE * IN_MILLISECONDS, uint32(aura->GetDuration()));
3925
3926 if (Unit* unitStealer = stealer->ToUnit())
3927 {
3928 if (Aura* oldAura = unitStealer->GetAura(aura->GetId(), aura->GetCasterGUID()))
3929 {
3930 if (stealCharge)
3931 oldAura->ModCharges(stolenCharges);
3932 else
3933 oldAura->ModStackAmount(stolenCharges);
3934 oldAura->SetDuration(int32(dur));
3935 }
3936 else
3937 {
3938 // single target state must be removed before aura creation to preserve existing single target aura
3939 if (aura->IsSingleTarget())
3940 aura->UnregisterSingleTarget();
3941
3942 AuraCreateInfo createInfo(aura->GetCastId(), aura->GetSpellInfo(), aura->GetCastDifficulty(), effMask, unitStealer);
3943 createInfo
3945 .SetBaseAmount(baseDamage);
3946
3947 if (Aura* newAura = Aura::TryRefreshStackOrCreate(createInfo))
3948 {
3949 // created aura must not be single target aura,, so stealer won't loose it on recast
3950 if (newAura->IsSingleTarget())
3951 {
3952 newAura->UnregisterSingleTarget();
3953 // bring back single target aura status to the old aura
3954 aura->SetIsSingleTarget(true);
3955 caster->GetSingleCastAuras().push_front(aura);
3956 }
3957 // FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
3958 newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? stolenCharges : aura->GetCharges(), stolenCharges, recalculateMask, &damage[0]);
3959 newAura->ApplyForTargets();
3960 }
3961 }
3962 }
3963
3964 if (stealCharge)
3965 aura->ModCharges(-stolenCharges, AURA_REMOVE_BY_ENEMY_SPELL);
3966 else
3967 aura->ModStackAmount(-stolenCharges, AURA_REMOVE_BY_ENEMY_SPELL);
3968
3969 return;
3970 }
3971 else
3972 ++iter;
3973 }
3974}
3975
3977{
3978 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3979 {
3980 if (iter->second->GetBase()->GetCastItemGUID() == castItemGuid)
3981 {
3982 RemoveAura(iter);
3983 iter = m_appliedAuras.lower_bound(spellId);
3984 }
3985 else
3986 ++iter;
3987 }
3988}
3989
3990void Unit::RemoveAurasByType(AuraType auraType, ObjectGuid casterGUID, Aura* except, bool negative, bool positive)
3991{
3992 for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
3993 {
3994 Aura* aura = (*iter)->GetBase();
3996 ASSERT(aurApp);
3997
3998 ++iter;
3999 if (aura != except && (!casterGUID || aura->GetCasterGUID() == casterGUID)
4000 && ((negative && !aurApp->IsPositive()) || (positive && aurApp->IsPositive())))
4001 {
4002 uint32 removedAuras = m_removedAurasCount;
4003 RemoveAura(aurApp);
4004 if (m_removedAurasCount > removedAuras + 1)
4005 iter = m_modAuras[auraType].begin();
4006 }
4007 }
4008}
4009
4011{
4012 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4013 {
4014 SpellInfo const* spell = iter->second->GetBase()->GetSpellInfo();
4015 if (spell->Attributes & flags)
4016 RemoveAura(iter);
4017 else
4018 ++iter;
4019 }
4020}
4021
4022void Unit::RemoveNotOwnSingleTargetAuras(bool onPhaseChange /*= false*/)
4023{
4024 // single target auras from other casters
4025 // Iterate m_ownedAuras - aura is marked as single target in Unit::AddAura (and pushed to m_ownedAuras).
4026 // m_appliedAuras will NOT contain the aura before first Unit::Update after adding it to m_ownedAuras.
4027 // Quickly removing such an aura will lead to it not being unregistered from caster's single cast auras container
4028 // leading to assertion failures if the aura was cast on a player that can
4029 // (and is changing map at the point where this function is called).
4030 // Such situation occurs when player is logging in inside an instance and fails the entry check for any reason.
4031 // The aura that was loaded from db (indirectly, via linked casts) gets removed before it has a chance
4032 // to register in m_appliedAuras
4033 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4034 {
4035 Aura const* aura = iter->second;
4036
4037 if (aura->GetCasterGUID() != GetGUID() && aura->IsSingleTarget())
4038 {
4039 if (!onPhaseChange)
4040 RemoveOwnedAura(iter);
4041 else
4042 {
4043 Unit* caster = aura->GetCaster();
4044 if (!caster || !caster->InSamePhase(this))
4045 RemoveOwnedAura(iter);
4046 else
4047 ++iter;
4048 }
4049 }
4050 else
4051 ++iter;
4052 }
4053
4054 // single target auras at other targets
4055 AuraList& scAuras = GetSingleCastAuras();
4056 for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
4057 {
4058 Aura* aura = *iter;
4059 if (aura->GetUnitOwner() != this && (!onPhaseChange || !aura->GetUnitOwner()->InSamePhase(this)))
4060 {
4061 aura->Remove();
4062 iter = scAuras.begin();
4063 }
4064 else
4065 ++iter;
4066 }
4067}
4068
4069template<typename InterruptFlag>
4070bool IsInterruptFlagIgnoredForSpell(InterruptFlag /*flag*/, Unit const* /*unit*/, SpellInfo const* /*auraSpellInfo*/, SpellInfo const* /*interruptSource*/)
4071{
4072 return false;
4073}
4074
4075template<>
4076bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit const* unit, SpellInfo const* auraSpellInfo, SpellInfo const* interruptSource)
4077{
4078 switch (flag)
4079 {
4081 return unit->CanCastSpellWhileMoving(auraSpellInfo);
4084 if (interruptSource)
4085 {
4086 if (interruptSource->HasAttribute(SPELL_ATTR1_ALLOW_WHILE_STEALTHED) && auraSpellInfo->Dispel == DISPEL_STEALTH)
4087 return true;
4088
4089 if (interruptSource->HasAttribute(SPELL_ATTR2_ALLOW_WHILE_INVISIBLE) && auraSpellInfo->Dispel == DISPEL_INVISIBILITY)
4090 return true;
4091 }
4092 break;
4093 default:
4094 break;
4095 }
4096
4097 return false;
4098}
4099
4100template <typename InterruptFlags>
4101void Unit::RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const* source)
4102{
4103 if (!HasInterruptFlag(flag))
4104 return;
4105
4106 // interrupt auras
4107 for (AuraApplicationList::iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end();)
4108 {
4109 Aura* aura = (*iter)->GetBase();
4110 ++iter;
4111 if (aura->GetSpellInfo()->HasAuraInterruptFlag(flag)
4112 && (!source || aura->GetId() != source->Id)
4113 && !IsInterruptFlagIgnoredForSpell(flag, this, aura->GetSpellInfo(), source))
4114 {
4115 uint32 removedAuras = m_removedAurasCount;
4117 if (m_removedAurasCount > removedAuras + 1)
4118 iter = m_interruptableAuras.begin();
4119 }
4120 }
4121
4122 // interrupt channeled spell
4124 if (spell->getState() == SPELL_STATE_CASTING
4125 && spell->GetSpellInfo()->HasChannelInterruptFlag(flag)
4126 && (!source || spell->GetSpellInfo()->Id != source->Id)
4127 && !IsInterruptFlagIgnoredForSpell(flag, this, spell->GetSpellInfo(), source))
4129
4131}
4132
4135
4136void Unit::RemoveAurasWithFamily(SpellFamilyNames family, flag128 const& familyFlag, ObjectGuid casterGUID)
4137{
4138 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4139 {
4140 Aura const* aura = iter->second->GetBase();
4141 if (!casterGUID || aura->GetCasterGUID() == casterGUID)
4142 {
4143 SpellInfo const* spell = aura->GetSpellInfo();
4144 if (spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags & familyFlag)
4145 {
4146 RemoveAura(iter);
4147 continue;
4148 }
4149 }
4150 ++iter;
4151 }
4152}
4153
4155{
4156 if (withRoot)
4158
4160}
4161
4162void Unit::RemoveAurasWithMechanic(uint64 mechanicMaskToRemove, AuraRemoveMode removeMode, uint32 exceptSpellId, bool withEffectMechanics)
4163{
4164 std::vector<Aura*> aurasToUpdateTargets;
4165 RemoveAppliedAuras([=, &aurasToUpdateTargets](AuraApplication const* aurApp)
4166 {
4167 Aura* aura = aurApp->GetBase();
4168 if (exceptSpellId && aura->GetId() == exceptSpellId)
4169 return false;
4170
4171 uint64 appliedMechanicMask = aura->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask());
4172 if (!(appliedMechanicMask & mechanicMaskToRemove))
4173 return false;
4174
4175 // spell mechanic matches required mask for removal
4176 if ((UI64LIT(1) << aura->GetSpellInfo()->Mechanic) & mechanicMaskToRemove || withEffectMechanics)
4177 return true;
4178
4179 // effect mechanic matches required mask for removal - don't remove, only update targets
4180 aurasToUpdateTargets.push_back(aura);
4181 return false;
4182 }, removeMode);
4183
4184 for (Aura* aura : aurasToUpdateTargets)
4185 {
4186 aura->UpdateTargetMap(aura->GetCaster());
4187
4188 // Fully remove the aura if all effects were removed
4189 if (!aura->IsPassive() && aura->GetOwner() == this && !aura->GetApplicationOfTarget(GetGUID()))
4190 aura->Remove(removeMode);
4191 }
4192}
4193
4195{
4196 uint64 mechanic_mask = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT);
4197 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4198 {
4199 Aura const* aura = iter->second->GetBase();
4200 if ((aura->GetSpellInfo()->GetAllEffectsMechanicMask() & mechanic_mask) && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_CU_AURA_CC))
4201 {
4202 RemoveAura(iter);
4203 continue;
4204 }
4205 ++iter;
4206 }
4207}
4208
4210{
4211 // make sure that all area auras not applied on self are removed - prevent access to deleted pointer later
4212 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4213 {
4214 Aura* aura = iter->second;
4215 ++iter;
4216 Aura::ApplicationMap const& appMap = aura->GetApplicationMap();
4217 for (Aura::ApplicationMap::const_iterator itr = appMap.begin(); itr!= appMap.end();)
4218 {
4219 AuraApplication * aurApp = itr->second;
4220 ++itr;
4221 Unit* target = aurApp->GetTarget();
4222 if (target == this)
4223 continue;
4224 target->RemoveAura(aurApp);
4225 // things linked on aura remove may apply new area aura - so start from the beginning
4226 iter = m_ownedAuras.begin();
4227 }
4228 }
4229
4230 // remove area auras owned by others
4231 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4232 {
4233 if (iter->second->GetBase()->GetOwner() != this)
4234 {
4235 RemoveAura(iter);
4236 }
4237 else
4238 ++iter;
4239 }
4240}
4241
4243{
4244 // this may be a dead loop if some events on aura remove will continiously apply aura on remove
4245 // we want to have all auras removed, so use your brain when linking events
4246 for (int counter = 0; !m_appliedAuras.empty() || !m_ownedAuras.empty(); counter++)
4247 {
4248 AuraApplicationMap::iterator aurAppIter;
4249 for (aurAppIter = m_appliedAuras.begin(); aurAppIter != m_appliedAuras.end();)
4251
4252 AuraMap::iterator aurIter;
4253 for (aurIter = m_ownedAuras.begin(); aurIter != m_ownedAuras.end();)
4254 RemoveOwnedAura(aurIter);
4255
4256 const int maxIteration = 50;
4257 // give this loop a few tries, if there are still auras then log as much information as possible
4258 if (counter >= maxIteration)
4259 {
4260 std::stringstream sstr;
4261 sstr << "Unit::RemoveAllAuras() iterated " << maxIteration << " times already but there are still "
4262 << m_appliedAuras.size() << " m_appliedAuras and " << m_ownedAuras.size() << " m_ownedAuras. Details:" << "\n";
4263 sstr << GetDebugInfo() << "\n";
4264
4265 if (!m_appliedAuras.empty())
4266 {
4267 sstr << "m_appliedAuras:" << "\n";
4268
4269 for (std::pair<uint32 const, AuraApplication*>& auraAppPair : m_appliedAuras)
4270 sstr << auraAppPair.second->GetDebugInfo() << "\n";
4271 }
4272
4273 if (!m_ownedAuras.empty())
4274 {
4275 sstr << "m_ownedAuras:" << "\n";
4276
4277 for (auto const& [spellId, aura] : m_ownedAuras)
4278 sstr << aura->GetDebugInfo() << "\n";
4279 }
4280
4281 TC_LOG_ERROR("entities.unit", "{}", sstr.str());
4282 ABORT_MSG("%s", sstr.str().c_str());
4283
4284 break;
4285 }
4286 }
4287}
4288
4290{
4291 // in join, remove positive buffs, on end, remove negative
4292 // used to remove positive visible auras in arenas
4293 RemoveAppliedAuras([](AuraApplication const* aurApp)
4294 {
4295 Aura const* aura = aurApp->GetBase();
4296 return (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_ALLOW_ENTERING_ARENA) // don't remove stances, shadowform, pally/hunter auras
4297 && !aura->IsPassive() // don't remove passive auras
4298 && (aurApp->IsPositive() || !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD))) || // not negative death persistent auras
4299 aura->GetSpellInfo()->HasAttribute(SPELL_ATTR5_REMOVE_ENTERING_ARENA); // special marker, always remove
4300 });
4301}
4302
4304{
4305 if (IsCharmedOwnedByPlayerOrPlayer()) // if it is a player owned creature it should not remove the aura
4306 return;
4307
4308 // don't remove vehicle auras, passengers aren't supposed to drop off the vehicle
4309 // don't remove clone caster on evade (to be verified)
4310 auto evadeAuraCheck = [](Aura const* aura)
4311 {
4312 if (aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE))
4313 return false;
4314
4315 if (aura->HasEffectType(SPELL_AURA_CLONE_CASTER))
4316 return false;
4317
4318 if (aura->GetSpellInfo()->HasAttribute(SPELL_ATTR1_AURA_STAYS_AFTER_COMBAT))
4319 return false;
4320
4321 return true;
4322 };
4323
4324 auto evadeAuraApplicationCheck = [&evadeAuraCheck](AuraApplication const* aurApp)
4325 {
4326 return evadeAuraCheck(aurApp->GetBase());
4327 };
4328
4329 RemoveAppliedAuras(evadeAuraApplicationCheck);
4330 RemoveOwnedAuras(evadeAuraCheck);
4331}
4332
4334{
4335 // used just after dieing to remove all visible auras
4336 // and disable the mods for the passive ones
4337 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4338 {
4339 Aura const* aura = iter->second->GetBase();
4340 if (!aura->IsPassive() && !aura->IsDeathPersistent())
4342 else
4343 ++iter;
4344 }
4345
4346 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4347 {
4348 Aura* aura = iter->second;
4349 if (!aura->IsPassive() && !aura->IsDeathPersistent())
4351 else
4352 ++iter;
4353 }
4354}
4355
4357{
4358 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4359 {
4360 Aura const* aura = iter->second->GetBase();
4361 if (!aura->IsPassive() && aura->GetSpellInfo()->IsRequiringDeadTarget())
4363 else
4364 ++iter;
4365 }
4366
4367 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4368 {
4369 Aura* aura = iter->second;
4370 if (!aura->IsPassive() && aura->GetSpellInfo()->IsRequiringDeadTarget())
4372 else
4373 ++iter;
4374 }
4375}
4376
4378{
4379 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4380 {
4381 Aura const* aura = iter->second->GetBase();
4382 if (aura->GetSpellInfo()->HasAura(type))
4383 ++iter;
4384 else
4386 }
4387
4388 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4389 {
4390 Aura* aura = iter->second;
4391 if (aura->GetSpellInfo()->HasAura(type))
4392 ++iter;
4393 else
4395 }
4396}
4397
4399{
4400 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4401 {
4402 Aura const* aura = iter->second->GetBase();
4403 if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2))
4404 ++iter;
4405 else
4407 }
4408
4409 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4410 {
4411 Aura* aura = iter->second;
4412 if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2))
4413 ++iter;
4414 else
4416 }
4417}
4418
4420{
4421 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4422 {
4423 Aura* aura = iter->second;
4424 if (aura->GetCasterGUID() == casterGUID && aura->GetSpellInfo()->IsGroupBuff())
4425 {
4426 RemoveOwnedAura(iter);
4427 continue;
4428 }
4429 ++iter;
4430 }
4431}
4432
4433void Unit::DelayOwnedAuras(uint32 spellId, ObjectGuid caster, int32 delaytime)
4434{
4435 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
4436 for (; range.first != range.second; ++range.first)
4437 {
4438 Aura* aura = range.first->second;
4439 if (!caster || aura->GetCasterGUID() == caster)
4440 {
4441 if (aura->GetDuration() < delaytime)
4442 aura->SetDuration(0);
4443 else
4444 aura->SetDuration(aura->GetDuration() - delaytime);
4445
4446 // update for out of range group members (on 1 slot use)
4448 }
4449 }
4450}
4451
4453{
4454 for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
4455 (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, false);
4456}
4457
4459{
4460 for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
4461 (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, true);
4462}
4463
4464AuraEffect* Unit::GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster) const
4465{
4466 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4467 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4468 {
4469 if (itr->second->HasEffect(effIndex)
4470 && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
4471 {
4472 return itr->second->GetBase()->GetEffect(effIndex);
4473 }
4474 }
4475 return nullptr;
4476}
4477
4479{
4480 uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
4481 while (rankSpell)
4482 {
4483 if (AuraEffect* aurEff = GetAuraEffect(rankSpell, effIndex, caster))
4484 return aurEff;
4485 rankSpell = sSpellMgr->GetNextSpellInChain(rankSpell);
4486 }
4487 return nullptr;
4488}
4489
4490AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames family, flag128 const& familyFlag, ObjectGuid casterGUID) const
4491{
4492 AuraEffectList const& auras = GetAuraEffectsByType(type);
4493 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4494 {
4495 SpellInfo const* spell = (*i)->GetSpellInfo();
4496 if (spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags & familyFlag)
4497 {
4498 if (!casterGUID.IsEmpty() && (*i)->GetCasterGUID() != casterGUID)
4499 continue;
4500 return (*i);
4501 }
4502 }
4503 return nullptr;
4504}
4505
4506AuraApplication * Unit::GetAuraApplication(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, AuraApplication * except) const
4507{
4508 return GetAuraApplication(spellId, [&](AuraApplication const* app)
4509 {
4510 Aura const* aura = app->GetBase();
4511
4512 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
4513 && (!casterGUID || aura->GetCasterGUID() == casterGUID)
4514 && (!itemCasterGUID || aura->GetCastItemGUID() == itemCasterGUID)
4515 && (!except || except != app))
4516 {
4517 return true;
4518 }
4519
4520 return false;
4521 });
4522}
4523
4524AuraApplication* Unit::GetAuraApplication(uint32 spellId, std::function<bool(AuraApplication const*)> const& predicate) const
4525{
4526 for (AuraApplicationMap::value_type const& pair : Trinity::Containers::MapEqualRange(m_appliedAuras, spellId))
4527 if (predicate(pair.second))
4528 return pair.second;
4529
4530 return nullptr;
4531}
4532
4533AuraApplication* Unit::GetAuraApplication(uint32 spellId, std::function<bool(Aura const*)> const& predicate) const
4534{
4535 for (AuraApplicationMap::value_type const& pair : Trinity::Containers::MapEqualRange(m_appliedAuras, spellId))
4536 if (predicate(pair.second->GetBase()))
4537 return pair.second;
4538
4539 return nullptr;
4540}
4541
4542AuraApplication* Unit::GetAuraApplication(std::function<bool(AuraApplication const*)> const& predicate) const
4543{
4544 for (AuraApplicationMap::value_type const& pair : m_appliedAuras)
4545 if (predicate(pair.second))
4546 return pair.second;
4547
4548 return nullptr;
4549}
4550
4551AuraApplication* Unit::GetAuraApplication(std::function<bool(Aura const*)> const& predicate) const
4552{
4553 for (AuraApplicationMap::value_type const& pair : m_appliedAuras)
4554 if (predicate(pair.second->GetBase()))
4555 return pair.second;
4556
4557 return nullptr;
4558}
4559
4560Aura* Unit::GetAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const
4561{
4562 AuraApplication* aurApp = GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask);
4563 return aurApp ? aurApp->GetBase() : nullptr;
4564}
4565
4566Aura* Unit::GetAura(uint32 spellId, std::function<bool(Aura const*)> const& predicate) const
4567{
4568 AuraApplication* aurApp = GetAuraApplication(spellId, predicate);
4569 return aurApp ? aurApp->GetBase() : nullptr;
4570}
4571
4572Aura* Unit::GetAura(std::function<bool(Aura const*)> const& predicate) const
4573{
4574 AuraApplication* aurApp = GetAuraApplication(predicate);
4575 return aurApp ? aurApp->GetBase() : nullptr;
4576}
4577
4578AuraApplication * Unit::GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask, AuraApplication* except) const
4579{
4580 uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
4581 while (rankSpell)
4582 {
4583 if (AuraApplication * aurApp = GetAuraApplication(rankSpell, casterGUID, itemCasterGUID, reqEffMask, except))
4584 return aurApp;
4585 rankSpell = sSpellMgr->GetNextSpellInChain(rankSpell);
4586 }
4587 return nullptr;
4588}
4589
4590Aura* Unit::GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const
4591{
4592 AuraApplication * aurApp = GetAuraApplicationOfRankedSpell(spellId, casterGUID, itemCasterGUID, reqEffMask);
4593 return aurApp ? aurApp->GetBase() : nullptr;
4594}
4595
4596void Unit::GetDispellableAuraList(WorldObject const* caster, uint32 dispelMask, DispelChargesList& dispelList, bool isReflect /*= false*/) const
4597{
4598 AuraMap const& auras = GetOwnedAuras();
4599 for (auto itr = auras.begin(); itr != auras.end(); ++itr)
4600 {
4601 Aura* aura = itr->second;
4602 AuraApplication const* aurApp = aura->GetApplicationOfTarget(GetGUID());
4603 if (!aurApp)
4604 continue;
4605
4606 // don't try to remove passive auras
4607 if (aura->IsPassive())
4608 continue;
4609
4610 if (aura->GetSpellInfo()->GetDispelMask() & dispelMask)
4611 {
4612 // do not remove positive auras if friendly target
4613 // negative auras if non-friendly
4614 // unless we're reflecting (dispeller eliminates one of it's benefitial buffs)
4615 if (isReflect != (aurApp->IsPositive() == IsFriendlyTo(caster)))
4616 continue;
4617
4618 // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
4619 int32 chance = aura->CalcDispelChance(this, !IsFriendlyTo(caster));
4620 if (!chance)
4621 continue;
4622
4623 // The charges / stack amounts don't count towards the total number of auras that can be dispelled.
4624 // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
4625 // Polymorph instead of 1 / (5 + 1) -> 16%.
4626 bool const dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_REMOVES_CHARGES);
4627 uint8 charges = dispelCharges ? aura->GetCharges() : aura->GetStackAmount();
4628 if (charges > 0)
4629 dispelList.emplace_back(aura, chance, charges);
4630 }
4631 }
4632}
4633
4634bool Unit::HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster) const
4635{
4636 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4637 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4638 {
4639 if (itr->second->HasEffect(effIndex)
4640 && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
4641 {
4642 return true;
4643 }
4644 }
4645 return false;
4646}
4647
4649{
4650 uint32 count = 0;
4651 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4652
4653 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4654 {
4655 if (itr->second->GetBase()->GetStackAmount() == 0)
4656 ++count;
4657 else
4658 count += (uint32)itr->second->GetBase()->GetStackAmount();
4659 }
4660
4661 return count;
4662}
4663
4664bool Unit::HasAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint32 reqEffMask) const
4665{
4666 return GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask) != nullptr;
4667}
4668
4669bool Unit::HasAura(std::function<bool(Aura const*)> const& predicate) const
4670{
4671 return GetAuraApplication(predicate) != nullptr;
4672}
4673
4674bool Unit::HasAuraType(AuraType auraType) const
4675{
4676 return (!m_modAuras[auraType].empty());
4677}
4678
4680{
4681 for (AuraEffect const* eff : GetAuraEffectsByType(auraType))
4682 if (caster == eff->GetCasterGUID())
4683 return true;
4684 return false;
4685}
4686
4687bool Unit::HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscvalue) const
4688{
4689 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4690 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4691 if (miscvalue == (*i)->GetMiscValue())
4692 return true;
4693 return false;
4694}
4695
4696bool Unit::HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
4697{
4698 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4699 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4700 if ((*i)->IsAffectingSpell(affectedSpell))
4701 return true;
4702 return false;
4703}
4704
4705bool Unit::HasAuraTypeWithValue(AuraType auraType, int32 value) const
4706{
4707 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4708 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4709 if (value == (*i)->GetAmount())
4710 return true;
4711 return false;
4712}
4713
4714bool Unit::HasAuraTypeWithTriggerSpell(AuraType auratype, uint32 triggerSpell) const
4715{
4716 for (AuraEffect const* aura : GetAuraEffectsByType(auratype))
4717 if (aura->GetSpellEffectInfo().TriggerSpell == triggerSpell)
4718 return true;
4719 return false;
4720}
4721
4722template <typename InterruptFlags>
4723bool Unit::HasNegativeAuraWithInterruptFlag(InterruptFlags flag, ObjectGuid guid) const
4724{
4725 if (!HasInterruptFlag(flag))
4726 return false;
4727
4728 for (AuraApplicationList::const_iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end(); ++iter)
4729 if (!(*iter)->IsPositive() && (*iter)->GetBase()->GetSpellInfo()->HasAuraInterruptFlag(flag) &&
4730 (!guid || (*iter)->GetBase()->GetCasterGUID() == guid))
4731 return true;
4732
4733 return false;
4734}
4735
4738
4739bool Unit::HasAuraWithMechanic(uint64 mechanicMask) const
4740{
4741 for (AuraApplicationMap::const_iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end(); ++iter)
4742 {
4743 SpellInfo const* spellInfo = iter->second->GetBase()->GetSpellInfo();
4744 if (spellInfo->Mechanic && (mechanicMask & (UI64LIT(1) << spellInfo->Mechanic)))
4745 return true;
4746
4747 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
4748 if (iter->second->HasEffect(spellEffectInfo.EffectIndex) && spellEffectInfo.IsEffect() && spellEffectInfo.Mechanic)
4749 if (mechanicMask & (UI64LIT(1) << spellEffectInfo.Mechanic))
4750 return true;
4751 }
4752
4753 return false;
4754}
4755
4756bool Unit::HasStrongerAuraWithDR(SpellInfo const* auraSpellInfo, Unit* caster) const
4757{
4758 DiminishingGroup diminishGroup = auraSpellInfo->GetDiminishingReturnsGroupForSpell();
4759 DiminishingLevels level = GetDiminishing(diminishGroup);
4760 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
4761 {
4762 SpellInfo const* spellInfo = itr->second->GetBase()->GetSpellInfo();
4763 if (spellInfo->GetDiminishingReturnsGroupForSpell() != diminishGroup)
4764 continue;
4765
4766 int32 existingDuration = itr->second->GetBase()->GetDuration();
4767 int32 newDuration = auraSpellInfo->GetMaxDuration();
4768 ApplyDiminishingToDuration(auraSpellInfo, newDuration, caster, level);
4769 if (newDuration > 0 && newDuration < existingDuration)
4770 return true;
4771 }
4772
4773 return false;
4774}
4775
4777{
4779 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4780 {
4781 if ((*i)->GetMiscValue() == script)
4782 if ((*i)->IsAffectingSpell(spell))
4783 return (*i);
4784 }
4785 return nullptr;
4786}
4787
4789{
4790 static const AuraType diseaseAuraTypes[] =
4791 {
4792 SPELL_AURA_PERIODIC_DAMAGE, // Frost Fever and Blood Plague
4793 SPELL_AURA_LINKED // Crypt Fever and Ebon Plague
4794 };
4795
4796 uint32 diseases = 0;
4797 for (AuraType aType : diseaseAuraTypes)
4798 {
4799 for (auto itr = m_modAuras[aType].begin(); itr != m_modAuras[aType].end();)
4800 {
4801 // Get auras with disease dispel type by caster
4802 if ((*itr)->GetSpellInfo()->Dispel == DISPEL_DISEASE
4803 && (*itr)->GetCasterGUID() == casterGUID)
4804 {
4805 ++diseases;
4806
4807 if (remove)
4808 {
4809 RemoveAura((*itr)->GetId(), (*itr)->GetCasterGUID());
4810 itr = m_modAuras[aType].begin();
4811 continue;
4812 }
4813 }
4814 ++itr;
4815 }
4816 }
4817 return diseases;
4818}
4819
4821{
4822 static const AuraType diseaseAuraTypes[] =
4823 {
4827 };
4828
4829 uint32 dots = 0;
4830 for (AuraType const* itr = &diseaseAuraTypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr)
4831 {
4832 Unit::AuraEffectList const& auras = GetAuraEffectsByType(*itr);
4833 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4834 {
4835 // Get auras by caster
4836 if ((*i)->GetCasterGUID() == casterGUID)
4837 ++dots;
4838 }
4839 }
4840 return dots;
4841}
4842
4843int32 Unit::GetTotalAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4844{
4845 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4846 if (mTotalAuraList.empty())
4847 return 0;
4848
4849 std::map<SpellGroup, int32> sameEffectSpellGroup;
4850 int32 modifier = 0;
4851
4852 for (AuraEffect const* aurEff : mTotalAuraList)
4853 {
4854 if (predicate(aurEff))
4855 {
4856 // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
4857 // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
4858 if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), static_cast<uint32>(auraType), aurEff->GetAmount(), sameEffectSpellGroup))
4859 modifier += aurEff->GetAmount();
4860 }
4861 }
4862
4863 // Add the highest of the Same Effect Stack Rule SpellGroups to the accumulator
4864 for (auto itr = sameEffectSpellGroup.begin(); itr != sameEffectSpellGroup.end(); ++itr)
4865 modifier += itr->second;
4866
4867 return modifier;
4868}
4869
4870float Unit::GetTotalAuraMultiplier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4871{
4872 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4873 if (mTotalAuraList.empty())
4874 return 1.0f;
4875
4876 std::map<SpellGroup, int32> sameEffectSpellGroup;
4877 float multiplier = 1.0f;
4878
4879 for (AuraEffect const* aurEff : mTotalAuraList)
4880 {
4881 if (predicate(aurEff))
4882 {
4883 // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
4884 // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
4885 if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), static_cast<uint32>(auraType), aurEff->GetAmount(), sameEffectSpellGroup))
4886 AddPct(multiplier, aurEff->GetAmount());
4887 }
4888 }
4889
4890 // Add the highest of the Same Effect Stack Rule SpellGroups to the multiplier
4891 for (auto itr = sameEffectSpellGroup.begin(); itr != sameEffectSpellGroup.end(); ++itr)
4892 AddPct(multiplier, itr->second);
4893
4894 return multiplier;
4895}
4896
4897int32 Unit::GetMaxPositiveAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4898{
4899 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4900 if (mTotalAuraList.empty())
4901 return 0;
4902
4903 int32 modifier = 0;
4904 for (AuraEffect const* aurEff : mTotalAuraList)
4905 {
4906 if (predicate(aurEff))
4907 modifier = std::max(modifier, aurEff->GetAmount());
4908 }
4909
4910 return modifier;
4911}
4912
4913int32 Unit::GetMaxNegativeAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4914{
4915 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4916 if (mTotalAuraList.empty())
4917 return 0;
4918
4919 int32 modifier = 0;
4920 for (AuraEffect const* aurEff : mTotalAuraList)
4921 {
4922 if (predicate(aurEff))
4923 modifier = std::min(modifier, aurEff->GetAmount());
4924 }
4925
4926 return modifier;
4927}
4928
4930{
4931 return GetTotalAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
4932}
4933
4935{
4936 return GetTotalAuraMultiplier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
4937}
4938
4940{
4941 return GetMaxPositiveAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
4942}
4943
4945{
4946 return GetMaxNegativeAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
4947}
4948
4950{
4951 return GetTotalAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
4952 {
4953 if ((aurEff->GetMiscValue() & miscMask) != 0)
4954 return true;
4955 return false;
4956 });
4957}
4958
4960{
4961 return GetTotalAuraMultiplier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
4962 {
4963 if ((aurEff->GetMiscValue() & miscMask) != 0)
4964 return true;
4965 return false;
4966 });
4967}
4968
4969int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auraType, uint32 miscMask, AuraEffect const* except /*= nullptr*/) const
4970{
4971 return GetMaxPositiveAuraModifier(auraType, [miscMask, except](AuraEffect const* aurEff) -> bool
4972 {
4973 if (except != aurEff && (aurEff->GetMiscValue() & miscMask) != 0)
4974 return true;
4975 return false;
4976 });
4977}
4978
4980{
4981 return GetMaxNegativeAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
4982 {
4983 if ((aurEff->GetMiscValue() & miscMask) != 0)
4984 return true;
4985 return false;
4986 });
4987}
4988
4990{
4991 return GetTotalAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
4992 {
4993 if (aurEff->GetMiscValue() == miscValue)
4994 return true;
4995 return false;
4996 });
4997}
4998
5000{
5001 return GetTotalAuraMultiplier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5002 {
5003 if (aurEff->GetMiscValue() == miscValue)
5004 return true;
5005 return false;
5006 });
5007}
5008
5010{
5011 return GetMaxPositiveAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5012 {
5013 if (aurEff->GetMiscValue() == miscValue)
5014 return true;
5015 return false;
5016 });
5017}
5018
5020{
5021 return GetMaxNegativeAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
5022 {
5023 if (aurEff->GetMiscValue() == miscValue)
5024 return true;
5025 return false;
5026 });
5027}
5028
5030{
5031 return GetTotalAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5032 {
5033 if (aurEff->IsAffectingSpell(affectedSpell))
5034 return true;
5035 return false;
5036 });
5037}
5038
5039float Unit::GetTotalAuraMultiplierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
5040{
5041 return GetTotalAuraMultiplier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5042 {
5043 if (aurEff->IsAffectingSpell(affectedSpell))
5044 return true;
5045 return false;
5046 });
5047}
5048
5050{
5051 return GetMaxPositiveAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5052 {
5053 if (aurEff->IsAffectingSpell(affectedSpell))
5054 return true;
5055 return false;
5056 });
5057}
5058
5060{
5061 return GetMaxNegativeAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
5062 {
5063 if (aurEff->IsAffectingSpell(affectedSpell))
5064 return true;
5065 return false;
5066 });
5067}
5068
5070{
5071 for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
5072 {
5073 m_floatStatPosBuff[i] = 0.0f;
5074 m_floatStatNegBuff[i] = 0.0f;
5076 }
5077}
5078
5080{
5081 float modPos = 0.0f;
5082 float modNeg = 0.0f;
5083 float factor = 0.0f;
5084
5085 UnitMods const unitMod = static_cast<UnitMods>(UNIT_MOD_STAT_START + AsUnderlyingType(stat));
5086
5087 // includes value from items and enchantments
5088 float modValue = GetFlatModifierValue(unitMod, BASE_VALUE);
5089 if (modValue > 0.f)
5090 modPos += modValue;
5091 else
5092 modNeg += modValue;
5093
5094 if (IsGuardian())
5095 {
5096 modValue = static_cast<Guardian*>(this)->GetBonusStatFromOwner(stat);
5097 if (modValue > 0.f)
5098 modPos += modValue;
5099 else
5100 modNeg += modValue;
5101 }
5102
5103 // SPELL_AURA_MOD_STAT_BONUS_PCT only affects BASE_VALUE
5104 modPos = CalculatePct(modPos, std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
5105 modNeg = CalculatePct(modNeg, std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
5106
5107 modPos += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
5108 {
5109 if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() > 0)
5110 return true;
5111 return false;
5112 });
5113
5114 modNeg += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
5115 {
5116 if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() < 0)
5117 return true;
5118 return false;
5119 });
5120
5121 factor = GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [stat](AuraEffect const* aurEff) -> bool
5122 {
5123 if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat)
5124 return true;
5125 return false;
5126 });
5127
5128 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [stat](AuraEffect const* aurEff) -> bool
5129 {
5130 if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat)
5131 return true;
5132 return false;
5133 });
5134
5135 modPos *= factor;
5136 modNeg *= factor;
5137
5138 m_floatStatPosBuff[stat] = modPos;
5139 m_floatStatNegBuff[stat] = modNeg;
5140
5142}
5143
5145{
5148}
5149
5151{
5152 m_dynObj.push_back(dynObj);
5153 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5155}
5156
5158{
5159 std::erase(m_dynObj, dynObj);
5160 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5162}
5163
5165{
5166 std::vector<DynamicObject*> dynamicobjects = GetDynObjects(spellId);
5167 return dynamicobjects.empty() ? nullptr : dynamicobjects.front();
5168}
5169
5170std::vector<DynamicObject*> Unit::GetDynObjects(uint32 spellId) const
5171{
5172 std::vector<DynamicObject*> dynamicobjects;
5173 for (DynObjectList::const_iterator i = m_dynObj.begin(); i != m_dynObj.end(); ++i)
5174 if ((*i)->GetSpellId() == spellId)
5175 dynamicobjects.push_back(*i);
5176
5177 return dynamicobjects;
5178}
5179
5181{
5182 for (DynObjectList::iterator i = m_dynObj.begin(); i != m_dynObj.end();)
5183 {
5184 DynamicObject* dynObj = *i;
5185 if (dynObj->GetSpellId() == spellId)
5186 {
5187 dynObj->Remove();
5188 i = m_dynObj.begin();
5189 }
5190 else
5191 ++i;
5192 }
5193}
5194
5196{
5197 while (!m_dynObj.empty())
5198 m_dynObj.back()->Remove();
5199}
5200
5202{
5203 std::vector<GameObject*> gameobjects = GetGameObjects(spellId);
5204 return gameobjects.empty() ? nullptr : gameobjects.front();
5205}
5206
5207std::vector<GameObject*> Unit::GetGameObjects(uint32 spellId) const
5208{
5209 std::vector<GameObject*> gameobjects;
5210 for (GameObjectList::const_iterator i = m_gameObj.begin(); i != m_gameObj.end(); ++i)
5211 if ((*i)->GetSpellId() == spellId)
5212 gameobjects.push_back(*i);
5213
5214 return gameobjects;
5215}
5216
5218{
5219 if (!gameObj || !gameObj->GetOwnerGUID().IsEmpty())
5220 return;
5221
5222 m_gameObj.push_back(gameObj);
5223 gameObj->SetOwnerGUID(GetGUID());
5224
5225 if (gameObj->GetSpellId())
5226 {
5227 SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(gameObj->GetSpellId(), GetMap()->GetDifficultyID());
5228 // Need disable spell use for owner
5229 if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
5230 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
5231 GetSpellHistory()->StartCooldown(createBySpell, 0, nullptr, true);
5232 }
5233
5235 ToCreature()->AI()->JustSummonedGameobject(gameObj);
5236}
5237
5238void Unit::RemoveGameObject(GameObject* gameObj, bool del)
5239{
5240 if (!gameObj || gameObj->GetOwnerGUID() != GetGUID())
5241 return;
5242
5244
5245 for (uint8 i = 0; i < MAX_GAMEOBJECT_SLOT; ++i)
5246 {
5247 if (m_ObjectSlot[i] == gameObj->GetGUID())
5248 {
5249 m_ObjectSlot[i].Clear();
5250 break;
5251 }
5252 }
5253
5254 // GO created by some spell
5255 if (uint32 spellid = gameObj->GetSpellId())
5256 {
5257 RemoveAurasDueToSpell(spellid);
5258
5259 SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid, GetMap()->GetDifficultyID());
5260 // Need activate spell use for owner
5261 if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
5262 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
5263 GetSpellHistory()->SendCooldownEvent(createBySpell);
5264 }
5265
5266 m_gameObj.remove(gameObj);
5267
5270
5271 if (del)
5272 {
5273 gameObj->SetRespawnTime(0);
5274 gameObj->Delete();
5275 }
5276}
5277
5278void Unit::RemoveGameObject(uint32 spellid, bool del)
5279{
5280 if (m_gameObj.empty())
5281 return;
5282 GameObjectList::iterator i, next;
5283 for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
5284 {
5285 next = i;
5286 if (spellid == 0 || (*i)->GetSpellId() == spellid)
5287 {
5288 (*i)->SetOwnerGUID(ObjectGuid::Empty);
5289 if (del)
5290 {
5291 (*i)->SetRespawnTime(0);
5292 (*i)->Delete();
5293 }
5294
5295 next = m_gameObj.erase(i);
5296 }
5297 else
5298 ++next;
5299 }
5300}
5301
5303{
5304 // remove references to unit
5305 while (!m_gameObj.empty())
5306 {
5307 GameObjectList::iterator i = m_gameObj.begin();
5308 (*i)->SetOwnerGUID(ObjectGuid::Empty);
5309 (*i)->SetRespawnTime(0);
5310 (*i)->Delete();
5311 m_gameObj.erase(i);
5312 }
5313}
5314
5316{
5317 m_areaTrigger.push_back(areaTrigger);
5318 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5319 ToCreature()->AI()->JustRegisteredAreaTrigger(areaTrigger);
5320}
5321
5323{
5324 std::erase(m_areaTrigger, areaTrigger);
5325 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
5326 ToCreature()->AI()->JustUnregisteredAreaTrigger(areaTrigger);
5327}
5328
5330{
5331 std::vector<AreaTrigger*> areaTriggers = GetAreaTriggers(spellId);
5332 return areaTriggers.empty() ? nullptr : areaTriggers.front();
5333}
5334
5335std::vector<AreaTrigger*> Unit::GetAreaTriggers(uint32 spellId) const
5336{
5337 std::vector<AreaTrigger*> areaTriggers;
5338 for (AreaTriggerList::const_iterator i = m_areaTrigger.begin(); i != m_areaTrigger.end(); ++i)
5339 if ((*i)->GetSpellId() == spellId)
5340 areaTriggers.push_back(*i);
5341
5342 return areaTriggers;
5343}
5344
5346{
5347 for (AreaTriggerList::iterator i = m_areaTrigger.begin(); i != m_areaTrigger.end();)
5348 {
5349 AreaTrigger* areaTrigger = *i;
5350 if (areaTrigger->GetSpellId() == spellId)
5351 {
5352 areaTrigger->Remove();
5353 i = m_areaTrigger.begin();
5354 }
5355 else
5356 ++i;
5357 }
5358}
5359
5361{
5362 for (AreaTrigger* areaTrigger : m_areaTrigger)
5363 {
5364 if (areaTrigger->GetAuraEffect() == aurEff)
5365 {
5366 areaTrigger->Remove();
5367 break; // There can only be one AreaTrigger per AuraEffect
5368 }
5369 }
5370}
5371
5373{
5374 while (!m_areaTrigger.empty())
5375 m_areaTrigger.back()->Remove();
5376}
5377
5379{
5381 packet.Me = log->target->GetGUID();
5382 packet.CasterGUID = log->attacker ? log->attacker->GetGUID() : ObjectGuid::Empty;
5383 packet.CastID = log->castId;
5384 packet.SpellID = log->Spell ? log->Spell->Id : 0;
5385 packet.Visual = log->SpellVisual;
5386 packet.Damage = log->damage;
5387 packet.OriginalDamage = log->originalDamage;
5388 if (log->damage > log->preHitHealth)
5389 packet.Overkill = log->damage - log->preHitHealth;
5390 else
5391 packet.Overkill = -1;
5392
5393 packet.SchoolMask = log->schoolMask;
5394 packet.Absorbed = log->absorb;
5395 packet.Resisted = log->resist;
5396 packet.ShieldBlock = log->blocked;
5397 packet.Periodic = log->periodicLog;
5398 packet.Flags = log->HitInfo;
5399
5401 if (contentTuningParams.GenerateDataForUnits(log->attacker, log->target))
5402 packet.ContentTuning = contentTuningParams;
5403
5404 SendCombatLogMessage(&packet);
5405}
5406
5407/*static*/ void Unit::ProcSkillsAndAuras(Unit* actor, Unit* actionTarget, ProcFlagsInit const& typeMaskActor, ProcFlagsInit const& typeMaskActionTarget,
5408 ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask,
5409 Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
5410{
5411 static constexpr int32 ProcChainHardLimit = 10;
5412 if (spell && spell->GetProcChainLength() >= ProcChainHardLimit)
5413 {
5414 TC_LOG_ERROR("spells.aura.effect", "Unit::ProcSkillsAndAuras: Possible infinite proc loop detected, current triggering spell {}", spell->GetDebugInfo().c_str());
5415 return;
5416 }
5417
5418 WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK;
5419 SpellInfo const* spellInfo = [&]() -> SpellInfo const*
5420 {
5421 if (spell)
5422 return spell->GetSpellInfo();
5423 if (damageInfo)
5424 return damageInfo->GetSpellInfo();
5425 if (healInfo)
5426 return healInfo->GetSpellInfo();
5427 return nullptr;
5428 }();
5429 if (typeMaskActor && actor && !(spellInfo && spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_CASTER_PROCS)))
5430 actor->ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
5431
5432 if (typeMaskActionTarget && actionTarget && !(spellInfo && spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS)))
5433 actionTarget->ProcSkillsAndReactives(true, actor, typeMaskActionTarget, hitMask, attType);
5434
5435 if (actor)
5436 actor->TriggerAurasProcOnEvent(nullptr, nullptr, actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
5437}
5438
5440{
5441 AuraEffect const* aura = info->auraEff;
5443 data.TargetGUID = GetGUID();
5444 data.CasterGUID = aura->GetCasterGUID();
5445 data.SpellID = aura->GetId();
5446 data.LogData.Initialize(this);
5447
5449 spellLogEffect.Effect = aura->GetAuraType();
5450 spellLogEffect.Amount = info->damage;
5451 spellLogEffect.OriginalDamage = info->originalDamage;
5452 spellLogEffect.OverHealOrKill = info->overDamage;
5453 spellLogEffect.SchoolMaskOrPower = aura->GetSpellInfo()->GetSchoolMask();
5454 spellLogEffect.AbsorbedOrAmplitude = info->absorb;
5455 spellLogEffect.Resisted = info->resist;
5456 spellLogEffect.Crit = info->critical;
5458
5460 if (Unit* caster = ObjectAccessor::GetUnit(*this, aura->GetCasterGUID()))
5461 if (contentTuningParams.GenerateDataForUnits(caster, this))
5462 spellLogEffect.ContentTuning = contentTuningParams;
5463
5464 data.Effects.push_back(spellLogEffect);
5465
5466 SendCombatLogMessage(&data);
5467}
5468
5470{
5472 procResist.Caster = GetGUID();
5473 procResist.SpellID = spellId;
5474 procResist.Target = target->GetGUID();
5475 SendMessageToSet(procResist.Write(), true);
5476}
5477
5478void Unit::SendSpellDamageImmune(Unit* target, uint32 spellId, bool isPeriodic)
5479{
5481 spellOrDamageImmune.CasterGUID = GetGUID();
5482 spellOrDamageImmune.VictimGUID = target->GetGUID();
5483 spellOrDamageImmune.SpellID = spellId;
5484 spellOrDamageImmune.IsPeriodic = isPeriodic;
5485 SendMessageToSet(spellOrDamageImmune.Write(), true);
5486}
5487
5489{
5491 packet.HitInfo = damageInfo->HitInfo;
5492 packet.AttackerGUID = damageInfo->Attacker->GetGUID();
5493 packet.VictimGUID = damageInfo->Target->GetGUID();
5494 packet.Damage = damageInfo->Damage;
5495 packet.OriginalDamage = damageInfo->OriginalDamage;
5496 int32 overkill = damageInfo->Damage - damageInfo->Target->GetHealth();
5497 packet.OverDamage = (overkill < 0 ? -1 : overkill);
5498
5499 packet.SubDmg.emplace();
5500 packet.SubDmg->SchoolMask = damageInfo->DamageSchoolMask; // School of sub damage
5501 packet.SubDmg->FDamage = damageInfo->Damage; // sub damage
5502 packet.SubDmg->Damage = damageInfo->Damage; // Sub Damage
5503 packet.SubDmg->Absorbed = damageInfo->Absorb;
5504 packet.SubDmg->Resisted = damageInfo->Resist;
5505
5506 packet.VictimState = damageInfo->TargetState;
5507 packet.BlockAmount = damageInfo->Blocked;
5508
5509 packet.LogData.Initialize(damageInfo->Attacker);
5510
5512 if (contentTuningParams.GenerateDataForUnits(damageInfo->Attacker, damageInfo->Target))
5513 packet.ContentTuning = contentTuningParams;
5514
5515 SendCombatLogMessage(&packet);
5516}
5517
5518void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType*/, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount)
5519{
5520 CalcDamageInfo dmgInfo;
5521 dmgInfo.HitInfo = HitInfo;
5522 dmgInfo.Attacker = this;
5523 dmgInfo.Target = target;
5524 dmgInfo.Damage = Damage - AbsorbDamage - Resist - BlockedAmount;
5525 dmgInfo.OriginalDamage = Damage;
5526 dmgInfo.DamageSchoolMask = damageSchoolMask;
5527 dmgInfo.Absorb = AbsorbDamage;
5528 dmgInfo.Resist = Resist;
5529 dmgInfo.TargetState = TargetState;
5530 dmgInfo.Blocked = BlockedAmount;
5531 SendAttackStateUpdate(&dmgInfo);
5532}
5533
5534void Unit::SetPowerType(Powers new_powertype, bool sendUpdate/* = true*/)
5535{
5536 if (GetPowerType() == new_powertype)
5537 return;
5538
5540
5541 if (!sendUpdate)
5542 return;
5543
5544 if (Player* thisPlayer = ToPlayer())
5545 {
5546 if (thisPlayer->GetGroup())
5547 thisPlayer->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POWER_TYPE);
5548 }
5549 /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x
5550 {
5551 if (pet->isControlled())
5552 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_POWER_TYPE);
5553 }*/
5554
5555 // Update max power
5556 UpdateMaxPower(new_powertype);
5557
5558 // Update current power
5559 switch (new_powertype)
5560 {
5561 case POWER_MANA: // Keep the same (druid form switching...)
5562 case POWER_ENERGY:
5563 break;
5564 case POWER_RAGE: // Reset to zero
5565 SetPower(POWER_RAGE, 0);
5566 break;
5567 case POWER_FOCUS: // Make it full
5568 SetFullPower(new_powertype);
5569 break;
5570 default:
5571 break;
5572 }
5573}
5574
5576{
5577 Powers displayPower = POWER_MANA;
5578 switch (GetShapeshiftForm())
5579 {
5580 case FORM_GHOUL:
5581 case FORM_CAT_FORM:
5582 displayPower = POWER_ENERGY;
5583 break;
5584 case FORM_BEAR_FORM:
5585 displayPower = POWER_RAGE;
5586 break;
5587 case FORM_TRAVEL_FORM:
5588 case FORM_GHOST_WOLF:
5589 displayPower = POWER_MANA;
5590 break;
5591 default:
5592 {
5594 if (!powerTypeAuras.empty())
5595 {
5596 AuraEffect const* powerTypeAura = powerTypeAuras.front();
5597 displayPower = Powers(powerTypeAura->GetMiscValue());
5598 }
5599 else
5600 {
5601 ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(GetClass());
5602 if (cEntry && cEntry->DisplayPower < MAX_POWERS)
5603 displayPower = Powers(cEntry->DisplayPower);
5604
5605 if (Vehicle* vehicle = GetVehicleKit())
5606 {
5607 if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(vehicle->GetVehicleInfo()->PowerDisplayID[0]))
5608 displayPower = Powers(powerDisplay->ActualType);
5609 }
5610 else if (Pet const* pet = ToPet())
5611 {
5612 if (pet->getPetType() == HUNTER_PET) // Hunter pets have focus
5613 displayPower = POWER_FOCUS;
5614 else if (pet->IsPetGhoul() || pet->IsPetAbomination()) // DK pets have energy
5615 displayPower = POWER_ENERGY;
5616 }
5617 }
5618 break;
5619 }
5620 }
5621
5622 return displayPower;
5623}
5624
5626{
5628}
5629
5631{
5633 if (sheathed == SHEATH_STATE_UNARMED)
5635}
5636
5637void Unit::_addAttacker(Unit* pAttacker)
5638{
5639 m_attackers.insert(pAttacker);
5640}
5641
5643{
5644 m_attackers.erase(pAttacker);
5645}
5646
5647Unit* Unit::getAttackerForHelper() const // If someone wants to help, who to give them
5648{
5649 if (!IsEngaged())
5650 return nullptr;
5651
5652 if (Unit* victim = GetVictim())
5653 if ((!IsPet() && !GetPlayerMovingMe()) || IsInCombatWith(victim))
5654 return victim;
5655
5656 CombatManager const& mgr = GetCombatManager();
5657 // pick arbitrary targets; our pvp combat > owner's pvp combat > our pve combat > owner's pve combat
5658 Unit* owner = GetCharmerOrOwner();
5659 if (mgr.HasPvPCombat())
5660 return mgr.GetPvPCombatRefs().begin()->second->GetOther(this);
5661 if (owner && (owner->GetCombatManager().HasPvPCombat()))
5662 return owner->GetCombatManager().GetPvPCombatRefs().begin()->second->GetOther(owner);
5663 if (mgr.HasPvECombat())
5664 return mgr.GetPvECombatRefs().begin()->second->GetOther(this);
5665 if (owner && (owner->GetCombatManager().HasPvECombat()))
5666 return owner->GetCombatManager().GetPvECombatRefs().begin()->second->GetOther(owner);
5667 return nullptr;
5668}
5669
5670bool Unit::Attack(Unit* victim, bool meleeAttack)
5671{
5672 if (!victim || victim == this)
5673 return false;
5674
5675 // dead units can neither attack nor be attacked
5676 if (!IsAlive() || !victim->IsInWorld() || !victim->IsAlive())
5677 return false;
5678
5679 // player cannot attack in mount state
5680 if (GetTypeId() == TYPEID_PLAYER && IsMounted())
5681 return false;
5682
5683 Creature* creature = ToCreature();
5684 // creatures cannot attack while evading
5685 if (creature && creature->IsInEvadeMode())
5686 return false;
5687
5688 // nobody can attack GM in GM-mode
5689 if (victim->GetTypeId() == TYPEID_PLAYER)
5690 {
5691 if (victim->ToPlayer()->IsGameMaster())
5692 return false;
5693 }
5694 else
5695 {
5696 if (victim->ToCreature()->IsEvadingAttacks())
5697 return false;
5698 }
5699
5700 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
5703
5704 if (m_attacking)
5705 {
5706 if (m_attacking == victim)
5707 {
5708 // switch to melee attack from ranged/magic
5709 if (meleeAttack)
5710 {
5712 {
5714 SendMeleeAttackStart(victim);
5715 return true;
5716 }
5717 }
5719 {
5721 SendMeleeAttackStop(victim);
5722 return true;
5723 }
5724 return false;
5725 }
5726
5727 // switch target
5729 if (!meleeAttack)
5731 }
5732
5733 if (m_attacking)
5735
5736 m_attacking = victim;
5738
5739 // Set our target
5740 SetTarget(victim->GetGUID());
5741
5742 if (meleeAttack)
5744
5745 // set position before any AI calls/assistance
5746 //if (GetTypeId() == TYPEID_UNIT)
5747 // ToCreature()->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
5748
5749 if (creature && !IsControlledByPlayer())
5750 {
5751 EngageWithTarget(victim); // ensure that anything we're attacking has threat
5752
5754 creature->CallAssistance();
5755
5756 // Remove emote and stand state - will be restored on creature reset
5759 }
5760
5761 // delay offhand weapon attack by 50% of the base attack time
5764
5765 if (meleeAttack)
5766 SendMeleeAttackStart(victim);
5767
5768 // Let the pet know we've started attacking someting. Handles melee attacks only
5769 // Spells such as auto-shot and others handled in WorldSession::HandleCastSpellOpcode
5770 if (GetTypeId() == TYPEID_PLAYER)
5771 {
5772 for (Unit* controlled : m_Controlled)
5773 if (Creature* cControlled = controlled->ToCreature())
5774 if (CreatureAI* controlledAI = cControlled->AI())
5775 controlledAI->OwnerAttacked(victim);
5776 }
5777
5778 return true;
5779}
5780
5782{
5783 if (!m_attacking)
5784 return false;
5785
5786 Unit* victim = m_attacking;
5787
5789 m_attacking = nullptr;
5790
5791 // Clear our target
5793
5795
5797
5798 // reset only at real combat stop
5799 if (Creature* creature = ToCreature())
5800 {
5801 creature->SetNoCallAssistance(false);
5802 }
5803
5804 SendMeleeAttackStop(victim);
5805
5806 return true;
5807}
5808
5810{
5811 // iterate attackers
5812 UnitVector toRemove;
5813 AttackerSet const& attackers = getAttackers();
5814 for (Unit* attacker : attackers)
5815 if (!attacker->IsValidAttackTarget(this))
5816 toRemove.push_back(attacker);
5817
5818 for (Unit* attacker : toRemove)
5819 attacker->AttackStop();
5820
5821 // remove our own victim
5822 if (Unit* victim = GetVictim())
5823 if (!IsValidAttackTarget(victim))
5824 AttackStop();
5825}
5826
5827void Unit::CombatStop(bool includingCast, bool mutualPvP, bool (*unitFilter)(Unit const* otherUnit))
5828{
5829 if (includingCast && IsNonMeleeSpellCast(false))
5831
5832 AttackStop();
5833 if (!unitFilter)
5835 else
5836 {
5837 std::vector<Unit*> attackersToRemove;
5838 attackersToRemove.reserve(m_attackers.size());
5839 std::copy_if(m_attackers.begin(), m_attackers.end(), std::back_inserter(attackersToRemove), unitFilter);
5840
5841 for (Unit* attacker : attackersToRemove)
5842 attacker->AttackStop();
5843 }
5844
5845 if (GetTypeId() == TYPEID_PLAYER)
5846 ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
5847
5848 m_combatManager.EndAllPvECombat(unitFilter);
5849 if (mutualPvP)
5850 m_combatManager.EndAllPvPCombat(unitFilter);
5851 else // vanish and brethren are weird
5853}
5854
5855void Unit::CombatStopWithPets(bool includingCast)
5856{
5857 CombatStop(includingCast);
5858
5859 for (Unit* minion : m_Controlled)
5860 minion->CombatStop(includingCast);
5861}
5862
5864{
5866 return true;
5867
5868 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
5869 if ((*itr)->isAttackingPlayer())
5870 return true;
5871
5872 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
5873 if (!m_SummonSlot[i].IsEmpty())
5874 if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
5875 if (summon->isAttackingPlayer())
5876 return true;
5877
5878 return false;
5879}
5880
5882{
5883 while (!m_attackers.empty())
5884 {
5885 AttackerSet::iterator iter = m_attackers.begin();
5886 if (!(*iter)->AttackStop())
5887 {
5888 TC_LOG_ERROR("entities.unit", "WORLD: Unit has an attacker that isn't attacking it!");
5889 m_attackers.erase(iter);
5890 }
5891 }
5892}
5893
5895{
5896 uint32 mask = 1 << (flag - 1);
5897 if (apply)
5898 {
5899 if (!(*m_unitData->AuraState & mask))
5900 {
5902 if (GetTypeId() == TYPEID_PLAYER)
5903 {
5904 PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap();
5905 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
5906 {
5907 if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
5908 continue;
5909 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE);
5910 if (!spellInfo || !spellInfo->IsPassive())
5911 continue;
5912 if (spellInfo->CasterAuraState == uint32(flag))
5913 CastSpell(this, itr->first, true);
5914 }
5915 }
5916 else if (Pet* pet = ToCreature()->ToPet())
5917 {
5918 for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
5919 {
5920 if (itr->second.state == PETSPELL_REMOVED)
5921 continue;
5922 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE);
5923 if (!spellInfo || !spellInfo->IsPassive())
5924 continue;
5925 if (spellInfo->CasterAuraState == uint32(flag))
5926 CastSpell(this, itr->first, true);
5927 }
5928 }
5929 }
5930 }
5931 else
5932 {
5933 if (*m_unitData->AuraState & mask)
5934 {
5936
5938 for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
5939 {
5940 SpellInfo const* spellProto = itr->second->GetBase()->GetSpellInfo();
5941 if (itr->second->GetBase()->GetCasterGUID() == GetGUID() && spellProto->CasterAuraState == uint32(flag) && (spellProto->IsPassive() || flag != AURA_STATE_ENRAGED))
5942 RemoveAura(itr);
5943 else
5944 ++itr;
5945 }
5946 }
5947 }
5948}
5949
5951{
5952 uint32 auraStates = *m_unitData->AuraState & ~(PER_CASTER_AURA_STATE_MASK);
5953 for (AuraStateAurasMap::const_iterator itr = m_auraStateAuras.begin(); itr != m_auraStateAuras.end(); ++itr)
5954 if ((1 << (itr->first - 1)) & PER_CASTER_AURA_STATE_MASK)
5955 if (itr->second->GetBase()->GetCasterGUID() == target->GetGUID())
5956 auraStates |= (1 << (itr->first - 1));
5957
5958 return auraStates;
5959}
5960
5961bool Unit::HasAuraState(AuraStateType flag, SpellInfo const* spellProto, Unit const* Caster) const
5962{
5963 if (Caster)
5964 {
5965 if (spellProto)
5966 {
5967 if (Caster->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_IGNORE_AURASTATE, spellProto))
5968 return true;
5969 }
5970
5971 // Check per caster aura state
5972 // If aura with aurastate by caster not found return false
5973 if ((1 << (flag - 1)) & PER_CASTER_AURA_STATE_MASK)
5974 {
5975 AuraStateAurasMapBounds range = m_auraStateAuras.equal_range(flag);
5976 for (AuraStateAurasMap::const_iterator itr = range.first; itr != range.second; ++itr)
5977 if (itr->second->GetBase()->GetCasterGUID() == Caster->GetGUID())
5978 return true;
5979 return false;
5980 }
5981 }
5982
5983 return (*m_unitData->AuraState & (1 << (flag - 1))) != 0;
5984}
5985
5987{
5988 if (GetOwnerGUID() == owner)
5989 return;
5990
5992 if (!owner)
5993 return;
5994
5995 // Update owner dependent fields
5996 Player* player = ObjectAccessor::GetPlayer(*this, owner);
5997 if (!player || !player->HaveAtClient(this)) // if player cannot see this unit yet, he will receive needed data with create object
5998 return;
5999
6000 UpdateData udata(GetMapId());
6001 WorldPacket packet;
6003 udata.BuildPacket(&packet);
6004 player->SendDirectMessage(&packet);
6005}
6006
6008{
6010}
6011
6013{
6015}
6016
6018{
6020 if (!guid.IsEmpty())
6021 {
6022 if (Unit* master = ObjectAccessor::GetUnit(*this, guid))
6023 return master->GetControllingPlayer();
6024 return nullptr;
6025 }
6026 else
6027 return const_cast<Player*>(ToPlayer());
6028}
6029
6031{
6032 ObjectGuid pet_guid = GetMinionGUID();
6033 if (!pet_guid.IsEmpty())
6034 {
6035 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
6036 if (pet->HasUnitTypeMask(UNIT_MASK_MINION))
6037 return (Minion*)pet;
6038
6039 TC_LOG_ERROR("entities.unit", "Unit::GetFirstMinion: Minion {} not exist.", pet_guid.ToString());
6040 const_cast<Unit*>(this)->SetMinionGUID(ObjectGuid::Empty);
6041 }
6042
6043 return nullptr;
6044}
6045
6047{
6048 ObjectGuid pet_guid = GetPetGUID();
6049 if (!pet_guid.IsEmpty())
6050 {
6051 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
6052 if (pet->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
6053 return (Guardian*)pet;
6054
6055 TC_LOG_FATAL("entities.unit", "Unit::GetGuardianPet: Guardian {} not exist.", pet_guid.ToString());
6056 const_cast<Unit*>(this)->SetPetGUID(ObjectGuid::Empty);
6057 }
6058
6059 return nullptr;
6060}
6061
6062void Unit::SetMinion(Minion *minion, bool apply)
6063{
6064 TC_LOG_DEBUG("entities.unit", "SetMinion {} for {}, apply {}", minion->GetEntry(), GetEntry(), apply);
6065
6066 if (apply)
6067 {
6068 if (!minion->GetOwnerGUID().IsEmpty())
6069 {
6070 TC_LOG_FATAL("entities.unit", "SetMinion: Minion {} is not the minion of owner {}", minion->GetEntry(), GetEntry());
6071 return;
6072 }
6073
6074 if (!IsInWorld())
6075 {
6076 TC_LOG_FATAL("entities.unit", "SetMinion: Minion being added to owner not in world. Minion: {}, Owner: {}", minion->GetGUID().ToString(), GetDebugInfo());
6077 return;
6078 }
6079
6080 minion->SetOwnerGUID(GetGUID());
6081
6082 m_Controlled.insert(minion);
6083
6084 if (GetTypeId() == TYPEID_PLAYER)
6085 {
6086 minion->m_ControlledByPlayer = true;
6088 }
6089
6090 // Can only have one pet. If a new one is summoned, dismiss the old one.
6091 if (minion->IsGuardianPet())
6092 {
6093 if (Guardian* oldPet = GetGuardianPet())
6094 {
6095 if (oldPet != minion && (oldPet->IsPet() || minion->IsPet() || oldPet->GetEntry() != minion->GetEntry()))
6096 {
6097 // remove existing minion pet
6098 if (Pet* oldPetAsPet = oldPet->ToPet())
6099 oldPetAsPet->Remove(PET_SAVE_NOT_IN_SLOT);
6100 else
6101 oldPet->UnSummon();
6102 SetPetGUID(minion->GetGUID());
6104 }
6105 }
6106 else
6107 {
6108 SetPetGUID(minion->GetGUID());
6110 }
6111 }
6112
6114 {
6115 if (GetMinionGUID().IsEmpty())
6116 SetMinionGUID(minion->GetGUID());
6117 }
6118
6119 SummonPropertiesEntry const* properties = minion->m_Properties;
6120 if (properties && SummonTitle(properties->Title) == SummonTitle::Companion)
6121 {
6122 SetCritterGUID(minion->GetGUID());
6123 if (Player const* thisPlayer = ToPlayer())
6124 {
6126 {
6127 if (BattlePets::BattlePet const* pet = thisPlayer->GetSession()->GetBattlePetMgr()->GetPet(thisPlayer->GetSummonedBattlePetGUID()))
6128 {
6129 minion->SetBattlePetCompanionGUID(thisPlayer->GetSummonedBattlePetGUID());
6130 minion->SetBattlePetCompanionNameTimestamp(pet->NameTimestamp);
6131 minion->SetWildBattlePetLevel(pet->PacketInfo.Level);
6132
6133 if (uint32 display = pet->PacketInfo.DisplayID)
6134 minion->SetDisplayId(display, true);
6135 }
6136 }
6137 }
6138 }
6139
6140 // PvP, FFAPvP
6142
6143 // FIXME: hack, speed must be set only at follow
6144 if (GetTypeId() == TYPEID_PLAYER && minion->IsPet())
6145 for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
6146 minion->SetSpeedRate(UnitMoveType(i), m_speed_rate[i]);
6147
6148 // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
6149 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->m_unitData->CreatedBySpell, DIFFICULTY_NONE);
6150
6151 if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
6152 GetSpellHistory()->StartCooldown(spellInfo, 0, nullptr, true);
6153 }
6154 else
6155 {
6156 if (minion->GetOwnerGUID() != GetGUID())
6157 {
6158 TC_LOG_FATAL("entities.unit", "SetMinion: Minion {} is not the minion of owner {}", minion->GetEntry(), GetEntry());
6159 return;
6160 }
6161
6162 m_Controlled.erase(minion);
6163
6165 if (GetCritterGUID() == minion->GetGUID())
6167
6168 if (minion->IsGuardianPet())
6169 {
6170 if (GetPetGUID() == minion->GetGUID())
6172 }
6173 else if (minion->IsTotem())
6174 {
6175 // All summoned by totem minions must disappear when it is removed.
6176 if (SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(minion->ToTotem()->GetSpell(), DIFFICULTY_NONE))
6177 {
6178 for (SpellEffectInfo const& spellEffectInfo : spInfo->GetEffects())
6179 {
6180 if (!spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON))
6181 continue;
6182
6183 RemoveAllMinionsByEntry(spellEffectInfo.MiscValue);
6184 }
6185 }
6186 }
6187
6188 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->m_unitData->CreatedBySpell, DIFFICULTY_NONE);
6189 // Remove infinity cooldown
6190 if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
6191 GetSpellHistory()->SendCooldownEvent(spellInfo);
6192
6193 //if (minion->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
6194 {
6195 if (GetMinionGUID() == minion->GetGUID())
6196 {
6198 // Check if there is another minion
6199 for (ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
6200 {
6201 // do not use this check, creature do not have charm guid
6202 //if (GetCharmedGUID() == (*itr)->GetGUID())
6203 if (GetGUID() == (*itr)->GetCharmerGUID())
6204 continue;
6205
6206 //ASSERT((*itr)->GetOwnerGUID() == GetGUID());
6207 if ((*itr)->GetOwnerGUID() != GetGUID())
6208 {
6209 OutDebugInfo();
6210 (*itr)->OutDebugInfo();
6211 ABORT();
6212 }
6213 ASSERT((*itr)->GetTypeId() == TYPEID_UNIT);
6214
6215 if (!(*itr)->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
6216 continue;
6217
6218 SetMinionGUID((*itr)->GetGUID());
6219 // show another pet bar if there is no charm bar
6220 if (GetTypeId() == TYPEID_PLAYER && !GetCharmedGUID())
6221 {
6222 if ((*itr)->IsPet())
6224 else
6226 }
6227 break;
6228 }
6229 }
6230 }
6231 }
6233}
6234
6235void Unit::GetAllMinionsByEntry(std::list<TempSummon*>& Minions, uint32 entry)
6236{
6237 for (Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
6238 {
6239 Unit* unit = *itr;
6240 if (unit->GetEntry() == entry && unit->IsSummon()) // minion, actually
6241 Minions.push_back(unit->ToTempSummon());
6242 }
6243}
6244
6246{
6247 for (Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end();)
6248 {
6249 Unit* unit = *itr;
6250 ++itr;
6251 if (unit->GetEntry() == entry && unit->GetTypeId() == TYPEID_UNIT
6252 && unit->ToCreature()->IsSummon()) // minion, actually
6253 unit->ToTempSummon()->UnSummon();
6254 // i think this is safe because i have never heard that a despawned minion will trigger a same minion
6255 }
6256}
6257
6258void Unit::SetCharm(Unit* charm, bool apply)
6259{
6260 if (apply)
6261 {
6262 if (GetTypeId() == TYPEID_PLAYER)
6263 {
6264 ASSERT(GetCharmedGUID().IsEmpty(),
6265 "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());
6267 m_charmed = charm;
6268
6269 charm->m_ControlledByPlayer = true;
6272 }
6273 else
6274 charm->m_ControlledByPlayer = false;
6275
6276 // PvP, FFAPvP
6278
6279 ASSERT(charm->GetCharmerGUID().IsEmpty(),
6280 "Unit %u is being charmed, but it already has a charmer %s", charm->GetEntry(), charm->GetCharmerGUID().ToString().c_str());
6282 charm->m_charmer = this;
6283
6286 charm->SetWalk(false);
6287
6288 m_Controlled.insert(charm);
6289 }
6290 else
6291 {
6293
6294 if (GetTypeId() == TYPEID_PLAYER)
6295 {
6296 ASSERT(GetCharmedGUID() == charm->GetGUID(),
6297 "Player %s is trying to uncharm unit %u, but it has another charmed unit %s", GetName().c_str(), charm->GetEntry(), GetCharmedGUID().ToString().c_str());
6299 m_charmed = nullptr;
6300 }
6301
6302 ASSERT(charm->GetCharmerGUID() == GetGUID(),
6303 "Unit %u is being uncharmed, but it has another charmer %s", charm->GetEntry(), charm->GetCharmerGUID().ToString().c_str());
6305 charm->m_charmer = nullptr;
6306
6307 if (charm->GetTypeId() == TYPEID_PLAYER)
6308 {
6309 charm->m_ControlledByPlayer = true;
6311 charm->ToPlayer()->UpdatePvPState();
6312 }
6313 else if (Player* player = charm->GetCharmerOrOwnerPlayerOrPlayerItself())
6314 {
6315 charm->m_ControlledByPlayer = true;
6317 charm->ReplaceAllPvpFlags(player->GetPvpFlags());
6318 }
6319 else
6320 {
6321 charm->m_ControlledByPlayer = false;
6324 }
6325
6326 if (charm->IsWalking() != _isWalkingBeforeCharm)
6328
6329 if (charm->GetTypeId() == TYPEID_PLAYER
6331 || charm->GetOwnerGUID() != GetGUID())
6332 {
6333 m_Controlled.erase(charm);
6334 }
6335 }
6337}
6338
6339/*static*/ void Unit::DealHeal(HealInfo& healInfo)
6340{
6341 int32 gain = 0;
6342 Unit* healer = healInfo.GetHealer();
6343 Unit* victim = healInfo.GetTarget();
6344 uint32 addhealth = healInfo.GetHeal();
6345
6346 if (UnitAI* victimAI = victim->GetAI())
6347 victimAI->HealReceived(healer, addhealth);
6348
6349 if (UnitAI* healerAI = healer ? healer->GetAI() : nullptr)
6350 healerAI->HealDone(victim, addhealth);
6351
6352 if (addhealth)
6353 gain = victim->ModifyHealth(int32(addhealth));
6354
6355 // Hook for OnHeal Event
6356 sScriptMgr->OnHeal(healer, victim, (uint32&)gain);
6357
6358 Unit* unit = healer;
6359 if (healer && healer->GetTypeId() == TYPEID_UNIT && healer->IsTotem())
6360 unit = healer->GetOwner();
6361
6362 if (unit)
6363 {
6364 if (Player* player = unit->ToPlayer())
6365 {
6367 if (Battleground* bg = player->GetBattleground())
6368 bg->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain);
6369
6370 // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
6371 if (gain)
6372 player->UpdateCriteria(CriteriaType::HealingDone, gain, 0, 0, victim);
6373
6374 player->UpdateCriteria(CriteriaType::HighestHealCast, addhealth);
6375 }
6376 }
6377
6378 if (Player* player = victim->ToPlayer())
6379 {
6380 player->UpdateCriteria(CriteriaType::TotalHealReceived, gain);
6381 player->UpdateCriteria(CriteriaType::HighestHealReceived, addhealth);
6382 }
6383
6384 if (gain)
6385 healInfo.SetEffectiveHeal(gain > 0 ? static_cast<uint32>(gain) : 0UL);
6386}
6387
6388bool Unit::IsMagnet() const
6389{
6390 // Grounding Totem
6391 if (*m_unitData->CreatedBySpell == 8177)
6392 return true;
6393
6394 return false;
6395}
6396
6397Unit* Unit::GetMeleeHitRedirectTarget(Unit* victim, SpellInfo const* spellInfo /*= nullptr*/)
6398{
6400 for (AuraEffectList::const_iterator i = interceptAuras.begin(); i != interceptAuras.end(); ++i)
6401 {
6402 if (Unit* magnet = (*i)->GetBase()->GetCaster())
6403 if (IsValidAttackTarget(magnet, spellInfo) && magnet->IsWithinLOSInMap(this)
6404 && (!spellInfo || (spellInfo->CheckExplicitTarget(this, magnet) == SPELL_CAST_OK
6405 && spellInfo->CheckTarget(this, magnet, false) == SPELL_CAST_OK)))
6406 {
6407 (*i)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE);
6408 return magnet;
6409 }
6410 }
6411 return victim;
6412}
6413
6415{
6416 // Sequence: charmed, pet, other guardians
6417 Unit* unit = GetCharmed();
6418 if (!unit)
6419 {
6420 ObjectGuid guid = GetMinionGUID();
6421 if (!guid.IsEmpty())
6422 unit = ObjectAccessor::GetUnit(*this, guid);
6423 }
6424
6425 return unit;
6426}
6427
6429{
6430 // possessed pet and vehicle
6431 if (GetTypeId() == TYPEID_PLAYER)
6433
6434 while (!m_Controlled.empty())
6435 {
6436 Unit* target = *m_Controlled.begin();
6437 m_Controlled.erase(m_Controlled.begin());
6438 if (target->GetCharmerGUID() == GetGUID())
6439 target->RemoveCharmAuras();
6440 else if (target->GetOwnerGUID() == GetGUID() && target->IsSummon())
6441 target->ToTempSummon()->UnSummon();
6442 else
6443 TC_LOG_ERROR("entities.unit", "Unit {} is trying to release unit {} which is neither charmed nor owned by it", GetEntry(), target->GetEntry());
6444 }
6445 if (!GetPetGUID().IsEmpty())
6446 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its pet {}", GetEntry(), GetPetGUID().ToString());
6447 if (!GetMinionGUID().IsEmpty())
6448 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its minion {}", GetEntry(), GetMinionGUID().ToString());
6449 if (!GetCharmedGUID().IsEmpty())
6450 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its charm {}", GetEntry(), GetCharmedGUID().ToString());
6451 if (!IsPet()) // pets don't use the flag for this
6452 RemoveUnitFlag(UNIT_FLAG_PET_IN_COMBAT); // m_controlled is now empty, so we know none of our minions are in combat
6453}
6454
6456{
6458}
6459
6461{
6462 return u->isPossessed() && GetCharmedGUID() == u->GetGUID();
6463}
6464
6466{
6467 if (Unit* u = GetCharmed())
6468 return u->isPossessed();
6469 else
6470 return false;
6471}
6472
6474{
6475 Player* player = nullptr;
6476 if (GetTypeId() == TYPEID_PLAYER)
6477 player = ToPlayer();
6478 // Should we enable this also for charmed units?
6479 else if (GetTypeId() == TYPEID_UNIT && IsPet())
6480 player = GetOwner()->ToPlayer();
6481
6482 if (!player)
6483 return nullptr;
6484 Group* group = player->GetGroup();
6485 // When there is no group check pet presence
6486 if (!group)
6487 {
6488 // We are pet now, return owner
6489 if (player != this)
6490 return IsWithinDistInMap(player, radius) ? player : nullptr;
6491 Unit* pet = GetGuardianPet();
6492 // No pet, no group, nothing to return
6493 if (!pet)
6494 return nullptr;
6495 // We are owner now, return pet
6496 return IsWithinDistInMap(pet, radius) ? pet : nullptr;
6497 }
6498
6499 std::vector<Unit*> nearMembers;
6500 // reserve place for players and pets because resizing vector every unit push is unefficient (vector is reallocated then)
6501 nearMembers.reserve(group->GetMembersCount() * 2);
6502
6503 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
6504 if (Player* Target = itr->GetSource())
6505 {
6506 // IsHostileTo check duel and controlled by enemy
6507 if (Target != this && IsWithinDistInMap(Target, radius) && Target->IsAlive() && !IsHostileTo(Target))
6508 nearMembers.push_back(Target);
6509
6510 // Push player's pet to vector
6511 if (Unit* pet = Target->GetGuardianPet())
6512 if (pet != this && IsWithinDistInMap(pet, radius) && pet->IsAlive() && !IsHostileTo(pet))
6513 nearMembers.push_back(pet);
6514 }
6515
6516 if (nearMembers.empty())
6517 return nullptr;
6518
6519 uint32 randTarget = urand(0, nearMembers.size()-1);
6520 return nearMembers[randTarget];
6521}
6522
6523// only called in Player::SetSeer
6524// so move it to Player?
6526{
6527 if (m_sharedVision.empty())
6528 {
6529 setActive(true);
6531 }
6532 m_sharedVision.push_back(player);
6533}
6534
6535// only called in Player::SetSeer
6537{
6538 m_sharedVision.remove(player);
6539 if (m_sharedVision.empty())
6540 {
6541 setActive(false);
6543 }
6544}
6545
6547{
6549}
6550
6552{
6557}
6558
6560{
6561 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
6562 {
6563 if (!m_SummonSlot[i])
6564 continue;
6565
6566 if (Creature* OldTotem = GetMap()->GetCreature(m_SummonSlot[i]))
6567 if (OldTotem->IsSummon())
6568 OldTotem->ToTempSummon()->UnSummon();
6569 }
6570}
6571
6572void Unit::SendHealSpellLog(HealInfo& healInfo, bool critical /*= false*/)
6573{
6575
6576 TC_LOG_DEBUG("spells", "HealSpellLog -- SpellId: {} Caster: {} Target: {} (Health: {} OverHeal: {} Absorbed: {} Crit: {})", healInfo.GetSpellInfo()->Id, healInfo.GetHealer()->GetGUID().ToString(), healInfo.GetTarget()->GetGUID().ToString(),
6577 healInfo.GetHeal(), healInfo.GetHeal() - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), critical);
6578
6579 spellHealLog.TargetGUID = healInfo.GetTarget()->GetGUID();
6580 spellHealLog.CasterGUID = healInfo.GetHealer()->GetGUID();
6581 spellHealLog.SpellID = healInfo.GetSpellInfo()->Id;
6582 spellHealLog.Health = healInfo.GetHeal();
6583 spellHealLog.OriginalHeal = healInfo.GetOriginalHeal();
6584 spellHealLog.OverHeal = int32(healInfo.GetHeal()) - healInfo.GetEffectiveHeal();
6585 spellHealLog.Absorbed = healInfo.GetAbsorb();
6586 spellHealLog.Crit = critical;
6587 spellHealLog.LogData.Initialize(healInfo.GetTarget());
6588 SendCombatLogMessage(&spellHealLog);
6589}
6590
6591int32 Unit::HealBySpell(HealInfo& healInfo, bool critical /*= false*/)
6592{
6593 // calculate heal absorb and reduce healing
6594 Unit::CalcHealAbsorb(healInfo);
6595 Unit::DealHeal(healInfo);
6596 SendHealSpellLog(healInfo, critical);
6597 return healInfo.GetEffectiveHeal();
6598}
6599
6600void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellID, int32 damage, int32 overEnergize, Powers powertype)
6601{
6603 data.CasterGUID = GetGUID();
6604 data.TargetGUID = victim->GetGUID();
6605 data.SpellID = spellID;
6606 data.Type = powertype;
6607 data.Amount = damage;
6608 data.OverEnergize = overEnergize;
6609 data.LogData.Initialize(victim);
6610 SendCombatLogMessage(&data);
6611}
6612
6613void Unit::EnergizeBySpell(Unit* victim, SpellInfo const* spellInfo, int32 damage, Powers powerType)
6614{
6615 if (Player* player = victim->ToPlayer())
6616 if (PowerTypeEntry const* powerTypeEntry = sDB2Manager.GetPowerTypeEntry(powerType))
6617 if (powerTypeEntry->GetFlags().HasFlag(PowerTypeFlags::UseRegenInterrupt))
6618 player->InterruptPowerRegen(powerType);
6619
6620 int32 gain = victim->ModifyPower(powerType, damage, false);
6621 int32 overEnergize = damage - gain;
6622 victim->GetThreatManager().ForwardThreatForAssistingMe(this, float(damage) / 2, spellInfo, true);
6623 SendEnergizeSpellLog(victim, spellInfo->Id, gain, overEnergize, powerType);
6624}
6625
6626int32 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
6627{
6628 if (!spellProto || !victim)
6629 return pdamage;
6630
6631 int32 DoneTotal = 0;
6632 float DoneTotalMod = 1.0f;
6633
6634 auto callDamageScript = [&](int32& dmg, int32& flatMod, float& pctMod)
6635 {
6636 if (spell)
6637 spell->CallScriptCalcDamageHandlers(victim, dmg, flatMod, pctMod);
6638 else if (aurEff)
6639 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID()), victim, dmg, flatMod, pctMod);
6640 };
6641
6642 // Some spells don't benefit from done mods
6643 if (damagetype == DIRECT_DAMAGE || spellProto->HasAttribute(SPELL_ATTR3_IGNORE_CASTER_MODIFIERS))
6644 {
6645 callDamageScript(pdamage, DoneTotal, DoneTotalMod);
6646 return int32(std::max(float(pdamage + DoneTotal) * DoneTotalMod, 0.0f));
6647 }
6648
6649 // For totems get damage bonus from owner
6650 if (GetTypeId() == TYPEID_UNIT && IsTotem())
6651 if (Unit* owner = GetOwner())
6652 return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, spellEffectInfo, stack, spell, aurEff);
6653
6654 DoneTotalMod = SpellDamagePctDone(victim, spellProto, damagetype, spellEffectInfo);
6655
6656 // Done fixed damage bonus auras
6657 int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto->GetSchoolMask());
6658 // modify spell power by victim's SPELL_AURA_MOD_DAMAGE_TAKEN auras (eg Amplify/Dampen Magic)
6659 DoneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_TAKEN, spellProto->GetSchoolMask());
6660
6661 // Pets just add their bonus damage to their spell damage
6662 // note that their spell damage is just gain of their own auras
6664 DoneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
6665
6666 // Check for table values
6667 if (spellEffectInfo.BonusCoefficientFromAP > 0.0f)
6668 {
6669 float ApCoeffMod = spellEffectInfo.BonusCoefficientFromAP;
6670 if (Player* modOwner = GetSpellModOwner())
6671 {
6672 ApCoeffMod *= 100.0f;
6673 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, ApCoeffMod);
6674 ApCoeffMod /= 100.0f;
6675 }
6676
6677 WeaponAttackType const attType = [&]()
6678 {
6679 if ((spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE))
6680 return RANGED_ATTACK;
6681
6683 return OFF_ATTACK;
6684
6685 return BASE_ATTACK;
6686 }();
6688 APbonus += GetTotalAttackPowerValue(attType);
6689 DoneTotal += int32(stack * ApCoeffMod * APbonus);
6690 }
6691
6692 // Default calculation
6693 if (DoneAdvertisedBenefit)
6694 {
6695 float coeff = spellEffectInfo.BonusCoefficient;
6696 if (Player* modOwner = GetSpellModOwner())
6697 {
6698 coeff *= 100.0f;
6699 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, coeff);
6700 coeff /= 100.0f;
6701 }
6702
6703 DoneTotal += int32(DoneAdvertisedBenefit * coeff * stack);
6704 }
6705
6706 callDamageScript(pdamage, DoneTotal, DoneTotalMod);
6707
6708 float tmpDamage = float(pdamage + DoneTotal) * DoneTotalMod;
6709
6710 // apply spellmod to Done damage (flat and pct)
6711 if (Player* modOwner = GetSpellModOwner())
6712 modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, tmpDamage);
6713
6714 return int32(std::max(tmpDamage, 0.0f));
6715}
6716
6717float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo) const
6718{
6719 if (!spellProto || !victim || damagetype == DIRECT_DAMAGE)
6720 return 1.0f;
6721
6722 // Some spells don't benefit from done mods
6724 return 1.0f;
6725
6726 // Some spells don't benefit from pct done mods
6728 return 1.0f;
6729
6730 // For totems get damage bonus from owner
6731 if (GetTypeId() == TYPEID_UNIT && IsTotem())
6732 if (Unit* owner = GetOwner())
6733 return owner->SpellDamagePctDone(victim, spellProto, damagetype, spellEffectInfo);
6734
6735 // Done total percent damage auras
6736 float DoneTotalMod = 1.0f;
6737
6738 // Pet damage?
6739 if (GetTypeId() == TYPEID_UNIT && !IsPet())
6740 DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureTemplate()->Classification);
6741
6742 // Versatility
6743 if (Player* modOwner = GetSpellModOwner())
6744 AddPct(DoneTotalMod, modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_DONE) + modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY));
6745
6746 float maxModDamagePercentSchool = 0.0f;
6747 if (Player const* thisPlayer = ToPlayer())
6748 {
6749 for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
6750 if (spellProto->GetSchoolMask() & (1 << i))
6751 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, thisPlayer->m_activePlayerData->ModDamageDonePercent[i]);
6752 }
6753 else
6754 maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, spellProto->GetSchoolMask());
6755
6756 DoneTotalMod *= maxModDamagePercentSchool;
6757
6758 uint32 creatureTypeMask = victim->GetCreatureTypeMask();
6759
6761
6762 // bonus against aurastate
6763 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim](AuraEffect const* aurEff) -> bool
6764 {
6765 if (victim->HasAuraState(static_cast<AuraStateType>(aurEff->GetMiscValue())))
6766 return true;
6767 return false;
6768 });
6769
6770 // bonus against target aura mechanic
6772 {
6773 if (victim->HasAuraWithMechanic(UI64LIT(1) << aurEff->GetMiscValue()))
6774 return true;
6775 return false;
6776 });
6777
6778 // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
6779 if (spellEffectInfo.Mechanic)
6781 else if (spellProto->Mechanic)
6783
6784 // Custom scripted damage
6785 switch (spellProto->SpellFamilyName)
6786 {
6787 case SPELLFAMILY_MAGE:
6788 // Ice Lance (no unique family flag)
6789 if (spellProto->Id == 228598)
6790 if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
6791 DoneTotalMod *= 3.0f;
6792 break;
6794 // Shadow Bite (30% increase from each dot)
6795 if (spellProto->SpellFamilyFlags[1] & 0x00400000 && IsPet())
6796 if (uint8 count = victim->GetDoTsByCaster(GetOwnerGUID()))
6797 AddPct(DoneTotalMod, 30 * count);
6798
6799 // Drain Soul - increased damage for targets under 20% HP
6800 if (spellProto->Id == 198590)
6802 DoneTotalMod *= 2;
6803 break;
6804 }
6805
6806 return DoneTotalMod;
6807}
6808
6809int32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, int32 pdamage, DamageEffectType damagetype) const
6810{
6811 if (!spellProto || damagetype == DIRECT_DAMAGE)
6812 return pdamage;
6813
6814 float TakenTotalMod = 1.0f;
6815
6816 // Mod damage from spell mechanic
6817 if (uint64 mechanicMask = spellProto->GetAllEffectsMechanicMask())
6818 {
6819 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
6820 {
6821 if (mechanicMask & uint64(UI64LIT(1) << aurEff->GetMiscValue()))
6822 return true;
6823 return false;
6824 });
6825 }
6826
6827 if (AuraEffect const* cheatDeath = GetAuraEffect(45182, EFFECT_0))
6828 if (cheatDeath->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
6829 AddPct(TakenTotalMod, cheatDeath->GetAmount());
6830
6831 // Spells with SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS should only benefit from mechanic damage mod auras.
6833 {
6834 // Versatility
6835 if (Player* modOwner = GetSpellModOwner())
6836 {
6837 // only 50% of SPELL_AURA_MOD_VERSATILITY for damage reduction
6838 float versaBonus = modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY) / 2.0f;
6839 AddPct(TakenTotalMod, -(modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_TAKEN) + versaBonus));
6840 }
6841
6842 // from positive and negative SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
6843 // multiplicative bonus, for example Dispersion + Shadowform (0.10*0.85=0.085)
6845
6846 // From caster spells
6847 if (caster)
6848 {
6849 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SCHOOL_MASK_DAMAGE_FROM_CASTER, [caster, spellProto](AuraEffect const* aurEff) -> bool
6850 {
6851 return aurEff->GetCasterGUID() == caster->GetGUID() && (aurEff->GetMiscValue() & spellProto->GetSchoolMask());
6852 });
6853
6854 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER, [caster, spellProto](AuraEffect const* aurEff) -> bool
6855 {
6856 return aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectingSpell(spellProto);
6857 });
6858
6859 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_TAKEN_FROM_CASTER_BY_LABEL, [caster, spellProto](AuraEffect const* aurEff) -> bool
6860 {
6861 return aurEff->GetCasterGUID() == caster->GetGUID() && spellProto->HasLabel(aurEff->GetMiscValue());
6862 });
6863 }
6864
6865 if (damagetype == DOT)
6866 {
6867 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_PERIODIC_DAMAGE_TAKEN, [spellProto](AuraEffect const* aurEff) -> bool
6868 {
6869 return aurEff->GetMiscValue() & spellProto->GetSchoolMask();
6870 });
6871 }
6872 }
6873
6874 // Sanctified Wrath (bypass damage reduction)
6875 if (caster && TakenTotalMod < 1.0f)
6876 {
6877 float damageReduction = 1.0f - TakenTotalMod;
6879 for (AuraEffect const* aurEff : casterIgnoreResist)
6880 {
6881 if (!(aurEff->GetMiscValue() & spellProto->GetSchoolMask()))
6882 continue;
6883
6884 AddPct(damageReduction, -aurEff->GetAmount());
6885 }
6886
6887 TakenTotalMod = 1.0f - damageReduction;
6888 }
6889
6890 float tmpDamage = pdamage * TakenTotalMod;
6891 return int32(std::max(tmpDamage, 0.0f));
6892}
6893
6895{
6896 if (Player const* thisPlayer = ToPlayer())
6897 {
6898 float overrideSP = thisPlayer->m_activePlayerData->OverrideSpellPowerByAPPercent;
6899 if (overrideSP > 0.0f)
6900 return int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), overrideSP) + 0.5f);
6901 }
6902
6903 int32 DoneAdvertisedBenefit = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE, schoolMask);
6904
6905 if (GetTypeId() == TYPEID_PLAYER)
6906 {
6907 // Base value
6908 DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
6909
6910 // Check if we are ever using mana - PaperDollFrame.lua
6912 DoneAdvertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT))); // spellpower from intellect
6913
6914 // Damage bonus from stats
6916 for (AuraEffect const* aurEff : mDamageDoneOfStatPercent)
6917 {
6918 if ((aurEff->GetMiscValue() & schoolMask) != 0)
6919 {
6920 // stat used stored in miscValueB for this aura
6921 Stats const usedStat = static_cast<Stats>(aurEff->GetMiscValueB());
6922 DoneAdvertisedBenefit += static_cast<int32>(CalculatePct(GetStat(usedStat), aurEff->GetAmount()));
6923 }
6924 }
6925
6926 }
6927
6928 return DoneAdvertisedBenefit;
6929}
6930
6931float Unit::SpellCritChanceDone(Spell* spell, AuraEffect const* aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType /*= BASE_ATTACK*/) const
6932{
6933 SpellInfo const* spellInfo = spell ? spell->GetSpellInfo() : aurEff->GetSpellInfo();
6935 if (GetTypeId() == TYPEID_UNIT && !GetSpellModOwner())
6936 return 0.0f;
6937
6938 // not critting spell
6939 if (spell && !spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
6940 return 0.0f;
6941
6942 float crit_chance = 0.0f;
6943 switch (spellInfo->DmgClass)
6944 {
6947 {
6948 auto getPhysicalCritChance = [&]
6949 {
6950 return GetUnitCriticalChanceDone(attackType);
6951 };
6952
6953 auto getMagicCritChance = [&]
6954 {
6955 if (Player const* thisPlayer = ToPlayer())
6956 return *thisPlayer->m_activePlayerData->SpellCritPercentage;
6957
6958 return m_baseSpellCritChance;
6959 };
6960
6961 if (schoolMask & SPELL_SCHOOL_MASK_NORMAL)
6962 crit_chance = std::max(crit_chance, getPhysicalCritChance());
6963
6964 if (schoolMask & ~SPELL_SCHOOL_MASK_NORMAL)
6965 crit_chance = std::max(crit_chance, getMagicCritChance());
6966 break;
6967 }
6970 {
6971 crit_chance += GetUnitCriticalChanceDone(attackType);
6972 break;
6973 }
6974 default:
6975 return 0.0f;
6976 }
6977 // percent done
6978 // only players use intelligence for critical chance computations
6979 if (Player* modOwner = GetSpellModOwner())
6980 modOwner->ApplySpellMod(spellInfo, SpellModOp::CritChance, crit_chance);
6981
6982 return std::max(crit_chance, 0.0f);
6983}
6984
6985float Unit::SpellCritChanceTaken(Unit const* caster, Spell* spell, AuraEffect const* aurEff, SpellSchoolMask /*schoolMask*/, float doneChance, WeaponAttackType attackType /*= BASE_ATTACK*/) const
6986{
6987 SpellInfo const* spellInfo = spell ? spell->GetSpellInfo() : aurEff->GetSpellInfo();
6988 // not critting spell
6989 if (spell && !spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
6990 return 0.0f;
6991
6992 float crit_chance = doneChance;
6993 switch (spellInfo->DmgClass)
6994 {
6996 {
6997 // taken
6998 if (!spellInfo->IsPositive())
6999 {
7000 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7002 }
7003
7004 if (caster)
7005 {
7006 // scripted (increase crit chance ... against ... target by x%
7007 AuraEffectList const& mOverrideClassScript = caster->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7008 for (AuraEffect const* aurEff : mOverrideClassScript)
7009 {
7010 if (!aurEff->IsAffectingSpell(spellInfo))
7011 continue;
7012
7013 switch (aurEff->GetMiscValue())
7014 {
7015 case 911: // Shatter
7016 if (HasAuraState(AURA_STATE_FROZEN, spellInfo, caster))
7017 {
7018 crit_chance *= 1.5f;
7019 if (AuraEffect const* eff = aurEff->GetBase()->GetEffect(EFFECT_1))
7020 crit_chance += eff->GetAmount();
7021 }
7022 break;
7023 default:
7024 break;
7025 }
7026 }
7027 // Custom crit by class
7028 switch (spellInfo->SpellFamilyName)
7029 {
7030 case SPELLFAMILY_ROGUE:
7031 // Shiv-applied poisons can't crit
7032 if (caster->FindCurrentSpellBySpellId(5938))
7033 crit_chance = 0.0f;
7034 break;
7035 }
7036
7037 // Spell crit suppression
7038 if (GetTypeId() == TYPEID_UNIT)
7039 {
7040 int32 const levelDiff = static_cast<int32>(GetLevelForTarget(caster)) - caster->GetLevel();
7041 crit_chance -= levelDiff * 1.0f;
7042 }
7043 }
7044 break;
7045 }
7047
7049 if (caster)
7050 crit_chance = GetUnitCriticalChanceTaken(caster, attackType, crit_chance);
7051 break;
7053 default:
7054 return 0.f;
7055 }
7056
7057 // for this types the bonus was already added in GetUnitCriticalChance, do not add twice
7058 if (caster && spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && spellInfo->DmgClass != SPELL_DAMAGE_CLASS_RANGED)
7059 {
7060 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_WITH_ABILITIES, [caster, spellInfo](AuraEffect const* aurEff) -> bool
7061 {
7062 return aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectingSpell(spellInfo);
7063 });
7064 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [caster](AuraEffect const* aurEff) -> bool
7065 {
7066 return aurEff->GetCasterGUID() == caster->GetGUID();
7067 });
7068 crit_chance += caster->GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_VERSUS_TARGET_HEALTH, [this](AuraEffect const* aurEff)
7069 {
7070 return !HealthBelowPct(aurEff->GetMiscValueB());
7071 });
7072 if (TempSummon const* tempSummon = caster->ToTempSummon())
7073 {
7074 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_PET, [tempSummon](AuraEffect const* aurEff) -> bool
7075 {
7076 return aurEff->GetCasterGUID() == tempSummon->GetSummonerGUID();
7077 });
7078 }
7079 }
7080
7081 // call script handlers
7082 if (spell)
7083 spell->CallScriptCalcCritChanceHandlers(this, crit_chance);
7084 else
7085 aurEff->GetBase()->CallScriptEffectCalcCritChanceHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(GetGUID()), this, crit_chance);
7086
7087 return std::max(crit_chance, 0.0f);
7088}
7089
7090/*static*/ uint32 Unit::SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim)
7091{
7092 // Calculate critical bonus
7093 int32 crit_bonus = damage * 2;
7094 float crit_mod = 0.0f;
7095
7096 if (caster)
7097 {
7098 crit_mod += (caster->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellProto->GetSchoolMask()) - 1.0f) * 100;
7099
7100 if (crit_bonus != 0)
7101 AddPct(crit_bonus, crit_mod);
7102
7104 {
7105 return aurEff->GetCasterGUID() == caster->GetGUID();
7106 }));
7107
7108 crit_bonus -= damage;
7109
7110 // adds additional damage to critBonus (from talents)
7111 if (Player* modOwner = caster->GetSpellModOwner())
7112 modOwner->ApplySpellMod(spellProto, SpellModOp::CritDamageAndHealing, crit_bonus);
7113
7114 crit_bonus += damage;
7115 }
7116
7117 return crit_bonus;
7118}
7119
7120/*static*/ uint32 Unit::SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* /*victim*/)
7121{
7122 // Calculate critical bonus
7123 int32 crit_bonus = damage;
7124
7125 // adds additional damage to critBonus (from talents)
7126 if (caster)
7127 if (Player* modOwner = caster->GetSpellModOwner())
7128 modOwner->ApplySpellMod(spellProto, SpellModOp::CritDamageAndHealing, crit_bonus);
7129
7130 damage += crit_bonus;
7131
7132 if (caster)
7133 damage = int32(float(damage) * caster->GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT));
7134
7135 return damage;
7136}
7137
7138int32 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
7139{
7140 // For totems get healing bonus from owner (statue isn't totem in fact)
7141 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7142 if (Unit* owner = GetOwner())
7143 return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, spellEffectInfo, stack, spell, aurEff);
7144
7145 // No bonus healing for potion spells
7146 if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
7147 return healamount;
7148
7149 int32 DoneTotal = 0;
7150 float DoneTotalMod = SpellHealingPctDone(victim, spellProto);
7151
7152 // done scripted mod (take it from owner)
7153 Unit const* owner = GetOwner() ? GetOwner() : this;
7154 AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7155 for (AuraEffect const* aurEff : mOverrideClassScript)
7156 {
7157 if (!aurEff->IsAffectingSpell(spellProto))
7158 continue;
7159
7160 switch (aurEff->GetMiscValue())
7161 {
7162 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
7163 DoneTotal += aurEff->GetAmount();
7164 break;
7165 default:
7166 break;
7167 }
7168 }
7169
7170 // Done fixed damage bonus auras
7171 int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(spellProto->GetSchoolMask());
7172 // modify spell power by victim's SPELL_AURA_MOD_HEALING auras (eg Amplify/Dampen Magic)
7173 DoneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_HEALING, spellProto->GetSchoolMask());
7174
7175 // Pets just add their bonus damage to their spell damage
7176 // note that their spell damage is just gain of their own auras
7178 DoneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
7179
7180 // Check for table values
7181 if (spellEffectInfo.BonusCoefficientFromAP > 0.0f)
7182 {
7183 WeaponAttackType const attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
7185 APbonus += GetTotalAttackPowerValue(attType);
7186
7187 DoneTotal += int32(spellEffectInfo.BonusCoefficientFromAP * stack * APbonus);
7188 }
7189
7190 // Default calculation
7191 if (DoneAdvertisedBenefit)
7192 {
7193 float coeff = spellEffectInfo.BonusCoefficient;
7194 if (Player* modOwner = GetSpellModOwner())
7195 {
7196 coeff *= 100.0f;
7197 modOwner->ApplySpellMod(spellProto, SpellModOp::BonusCoefficient, coeff);
7198 coeff /= 100.0f;
7199 }
7200
7201 DoneTotal += int32(DoneAdvertisedBenefit * coeff * stack);
7202 }
7203
7204 for (SpellEffectInfo const& otherSpellEffect : spellProto->GetEffects())
7205 {
7206 switch (otherSpellEffect.ApplyAuraName)
7207 {
7208 // Bonus healing does not apply to these spells
7211 DoneTotal = 0;
7212 break;
7213 default:
7214 break;
7215 }
7216 if (otherSpellEffect.IsEffect(SPELL_EFFECT_HEALTH_LEECH))
7217 DoneTotal = 0;
7218 }
7219
7220 if (spell)
7221 spell->CallScriptCalcHealingHandlers(victim, healamount, DoneTotal, DoneTotalMod);
7222 else if (aurEff)
7223 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(victim->GetGUID()), victim, healamount, DoneTotal, DoneTotalMod);
7224
7225 float heal = float(healamount + DoneTotal) * DoneTotalMod;
7226
7227 // apply spellmod to Done amount
7228 if (Player* modOwner = GetSpellModOwner())
7229 modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, heal);
7230
7231 return int32(std::max(heal, 0.0f));
7232}
7233
7234float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const
7235{
7236 // For totems get healing bonus from owner
7237 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7238 if (Unit* owner = GetOwner())
7239 return owner->SpellHealingPctDone(victim, spellProto);
7240
7241 // Some spells don't benefit from done mods
7243 return 1.0f;
7244
7245 // Some spells don't benefit from done mods
7247 return 1.0f;
7248
7249 // No bonus healing for potion spells
7250 if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
7251 return 1.0f;
7252
7253 float DoneTotalMod = 1.0f;
7254
7255 // Healing done percent
7256 if (Player const* thisPlayer = ToPlayer())
7257 {
7258 float maxModDamagePercentSchool = 0.0f;
7259 for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
7260 if (spellProto->GetSchoolMask() & (1 << i))
7261 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, thisPlayer->m_activePlayerData->ModHealingDonePercent[i]);
7262
7263 DoneTotalMod *= maxModDamagePercentSchool;
7264 }
7265 else // SPELL_AURA_MOD_HEALING_DONE_PERCENT is included in m_activePlayerData->ModHealingDonePercent for players
7267
7268 // bonus against aurastate
7269 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim](AuraEffect const* aurEff) -> bool
7270 {
7271 if (victim->HasAuraState(static_cast<AuraStateType>(aurEff->GetMiscValue())))
7272 return true;
7273 return false;
7274 });
7275
7276 // bonus from missing health of target
7277 float healthPctDiff = 100.0f - victim->GetHealthPct();
7279 if (healingDonePctVsTargetHealth->IsAffectingSpell(spellProto))
7280 AddPct(DoneTotalMod, CalculatePct(float(healingDonePctVsTargetHealth->GetAmount()), healthPctDiff));
7281
7282 return DoneTotalMod;
7283}
7284
7285int32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, int32 healamount, DamageEffectType damagetype) const
7286{
7287 float TakenTotalMod = 1.0f;
7288
7289 // Healing taken percent
7291 if (minval)
7292 AddPct(TakenTotalMod, minval);
7293
7295 if (maxval)
7296 AddPct(TakenTotalMod, maxval);
7297
7298 // Nourish cast
7299 if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[1] & 0x2000000)
7300 {
7301 // Rejuvenation, Regrowth, Lifebloom, or Wild Growth
7303 // increase healing by 20%
7304 TakenTotalMod *= 1.2f;
7305 }
7306
7307 if (damagetype == DOT)
7308 {
7309 // Healing over time taken percent
7310 float minval_hot = float(GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT));
7311 if (minval_hot)
7312 AddPct(TakenTotalMod, minval_hot);
7313
7314 float maxval_hot = float(GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT));
7315 if (maxval_hot)
7316 AddPct(TakenTotalMod, maxval_hot);
7317 }
7318
7319 if (caster)
7320 {
7321 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_RECEIVED, [caster, spellProto](AuraEffect const* aurEff) -> bool
7322 {
7323 if (caster->GetGUID() == aurEff->GetCasterGUID() && aurEff->IsAffectingSpell(spellProto))
7324 return true;
7325 return false;
7326 });
7327
7328 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_TAKEN_FROM_CASTER, [caster](AuraEffect const* aurEff) -> bool
7329 {
7330 return aurEff->GetCasterGUID() == caster->GetGUID();
7331 });
7332 }
7333
7334 float heal = healamount * TakenTotalMod;
7335 return int32(std::max(heal, 0.0f));
7336}
7337
7339{
7340 if (Player const* thisPlayer = ToPlayer())
7341 {
7342 float overrideSP = thisPlayer->m_activePlayerData->OverrideSpellPowerByAPPercent;
7343 if (overrideSP > 0.0f)
7344 return int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), overrideSP) + 0.5f);
7345 }
7346
7347 int32 advertisedBenefit = GetTotalAuraModifier(SPELL_AURA_MOD_HEALING_DONE, [schoolMask](AuraEffect const* aurEff) -> bool
7348 {
7349 if (!aurEff->GetMiscValue() || (aurEff->GetMiscValue() & schoolMask) != 0)
7350 return true;
7351 return false;
7352 });
7353
7354 // Healing bonus of spirit, intellect and strength
7355 if (GetTypeId() == TYPEID_PLAYER)
7356 {
7357 // Base value
7358 advertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
7359
7360 // Check if we are ever using mana - PaperDollFrame.lua
7362 advertisedBenefit += std::max(0, int32(GetStat(STAT_INTELLECT))); // spellpower from intellect
7363
7364 // Healing bonus from stats
7366 for (AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i)
7367 {
7368 // stat used dependent from misc value (stat index)
7369 Stats usedStat = Stats((*i)->GetSpellEffectInfo().MiscValue);
7370 advertisedBenefit += int32(CalculatePct(GetStat(usedStat), (*i)->GetAmount()));
7371 }
7372 }
7373 return advertisedBenefit;
7374}
7375
7377{
7378 if (schoolMask == SPELL_SCHOOL_MASK_NONE)
7379 return false;
7380
7381 // If m_immuneToSchool type contain this school type, IMMUNE damage.
7382 uint32 schoolImmunityMask = GetSchoolImmunityMask();
7383 if ((schoolImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7384 return true;
7385
7386 // If m_immuneToDamage type contain magic, IMMUNE damage.
7387 uint32 damageImmunityMask = GetDamageImmunityMask();
7388 if ((damageImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7389 return true;
7390
7391 return false;
7392}
7393
7394bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo, SpellEffectInfo const* spellEffectInfo /*= nullptr*/) const
7395{
7396 if (!spellInfo)
7397 return false;
7398
7399 // for example 40175
7401 return false;
7402
7404 return false;
7405
7406 if (spellEffectInfo && spellEffectInfo->EffectAttributes.HasFlag(SpellEffectAttributes::NoImmunity))
7407 return false;
7408
7409 if (uint32 schoolMask = spellInfo->GetSchoolMask())
7410 {
7411 // If m_immuneToSchool type contain this school type, IMMUNE damage.
7412 uint32 schoolImmunityMask = 0;
7414 for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7415 if ((itr->first & schoolMask) && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->second, GetMap()->GetDifficultyID())))
7416 schoolImmunityMask |= itr->first;
7417
7418 // // We need to be immune to all types
7419 if ((schoolImmunityMask & schoolMask) == schoolMask)
7420 return true;
7421
7422 // If m_immuneToDamage type contain magic, IMMUNE damage.
7423 uint32 damageImmunityMask = GetDamageImmunityMask();
7424 if ((damageImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7425 return true;
7426 }
7427
7428 return false;
7429}
7430
7431bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute /*= false*/) const
7432{
7433 if (!spellInfo)
7434 return false;
7435
7436 auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
7437 {
7439 if (!requireImmunityPurgesEffectAttribute)
7440 return range.begin() != range.end();
7441
7442 return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
7443 {
7444 if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second, DIFFICULTY_NONE))
7445 if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
7446 return true;
7447
7448 return false;
7449 });
7450 };
7451
7452 // Single spell immunity.
7454 if (hasImmunity(idList, spellInfo->Id))
7455 return true;
7456
7458 return false;
7459
7460 if (uint32 dispel = spellInfo->Dispel)
7461 {
7463 if (hasImmunity(dispelList, dispel))
7464 return true;
7465 }
7466
7467 // Spells that don't have effectMechanics.
7468 if (uint32 mechanic = spellInfo->Mechanic)
7469 {
7471 if (hasImmunity(mechanicList, mechanic))
7472 return true;
7473 }
7474
7475 bool immuneToAllEffects = true;
7476 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
7477 {
7478 // State/effect immunities applied by aura expect full spell immunity
7479 // Ignore effects with mechanic, they are supposed to be checked separately
7480 if (!spellEffectInfo.IsEffect())
7481 continue;
7482 if (!IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute))
7483 {
7484 immuneToAllEffects = false;
7485 break;
7486 }
7488 return true;
7489 }
7490
7491 if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
7492 return true;
7493
7494 if (uint32 schoolMask = spellInfo->GetSchoolMask())
7495 {
7496 uint32 schoolImmunityMask = 0;
7498 for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7499 {
7500 if ((itr->first & schoolMask) == 0)
7501 continue;
7502
7503 SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second, GetMap()->GetDifficultyID());
7504 if (requireImmunityPurgesEffectAttribute)
7505 if (!immuneSpellInfo || !immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
7506 continue;
7507
7508 // Consider the school immune if any of these conditions are not satisfied.
7509 // In case of no immuneSpellInfo, ignore that condition and check only the other conditions
7510 if ((immuneSpellInfo && !immuneSpellInfo->IsPositive()) || !spellInfo->IsPositive() || !caster || !IsFriendlyTo(caster))
7511 if (!spellInfo->CanPierceImmuneAura(immuneSpellInfo))
7512 schoolImmunityMask |= itr->first;
7513 }
7514 if ((schoolImmunityMask & schoolMask) == schoolMask)
7515 return true;
7516 }
7517
7518 return false;
7519}
7520
7522{
7523 uint32 mask = 0;
7525 for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7526 mask |= itr->first;
7527
7528 return mask;
7529}
7530
7532{
7533 uint32 mask = 0;
7535 for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
7536 mask |= itr->first;
7537
7538 return mask;
7539}
7540
7542{
7543 uint64 mask = 0;
7545 for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
7546 mask |= (UI64LIT(1) << itr->first);
7547
7548 return mask;
7549}
7550
7552{
7553 SpellOtherImmunity mask = { };
7555 for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
7556 mask |= SpellOtherImmunity(itr->first);
7557
7558 return mask;
7559}
7560
7561bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster,
7562 bool requireImmunityPurgesEffectAttribute /*= false*/) const
7563{
7564 if (!spellInfo)
7565 return false;
7566
7568 return false;
7569
7571 return false;
7572
7573 auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
7574 {
7576 if (!requireImmunityPurgesEffectAttribute)
7577 return range.begin() != range.end();
7578
7579 return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
7580 {
7581 if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second, DIFFICULTY_NONE))
7582 if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
7583 return true;
7584
7585 return false;
7586 });
7587 };
7588
7589 // If m_immuneToEffect type contain this effect type, IMMUNE effect.
7590 auto const& effectList = m_spellImmune[IMMUNITY_EFFECT];
7591 if (hasImmunity(effectList, spellEffectInfo.Effect))
7592 return true;
7593
7594 if (uint32 mechanic = spellEffectInfo.Mechanic)
7595 {
7597 if (hasImmunity(mechanicList, mechanic))
7598 return true;
7599 }
7600
7601 if (AuraType aura = spellEffectInfo.ApplyAuraName)
7602 {
7603 if (!spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
7604 {
7606 if (hasImmunity(list, aura))
7607 return true;
7608 }
7609
7611 {
7612 // Check for immune to application of harmful magical effects
7614 for (AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
7615 if (((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) && // Check school
7616 ((caster && !IsFriendlyTo(caster)) || !spellInfo->IsPositiveEffect(spellEffectInfo.EffectIndex))) // Harmful
7617 return true;
7618 }
7619 }
7620
7621 return false;
7622}
7623
7624int32 Unit::MeleeDamageBonusDone(Unit* pVictim, int32 damage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto /*= nullptr*/, Mechanics mechanic /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/, Spell* spell /*= nullptr*/, AuraEffect const* aurEff /*= nullptr*/)
7625{
7626 if (!pVictim || damage == 0)
7627 return 0;
7628
7629 uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
7630
7631 // Done fixed damage bonus auras
7632 int32 DoneFlatBenefit = 0;
7633
7634 // ..done
7635 DoneFlatBenefit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE, creatureTypeMask);
7636
7637 // ..done
7638 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
7639
7640 // ..done (base at attack power for marked target and base at attack power for creature type)
7641 int32 APbonus = 0;
7642
7643 if (attType == RANGED_ATTACK)
7644 {
7646
7647 // ..done (base at attack power and creature type)
7649 }
7650 else
7651 {
7653
7654 // ..done (base at attack power and creature type)
7656 }
7657
7658 if (APbonus != 0) // Can be negative
7659 {
7660 bool const normalized = spellProto && spellProto->HasEffect(SPELL_EFFECT_NORMALIZED_WEAPON_DMG);
7661 DoneFlatBenefit += int32(APbonus / 3.5f * GetAPMultiplier(attType, normalized));
7662 }
7663
7664 // Done total percent damage auras
7665 float DoneTotalMod = 1.0f;
7666
7667 SpellSchoolMask schoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask;
7668
7669 if (!(schoolMask & SPELL_SCHOOL_MASK_NORMAL))
7670 {
7671 // Some spells don't benefit from pct done mods
7672 // mods for SPELL_SCHOOL_MASK_NORMAL are already factored in base melee damage calculation
7673 if (!spellProto || !spellProto->HasAttribute(SPELL_ATTR6_IGNORE_CASTER_DAMAGE_MODIFIERS))
7674 {
7675 float maxModDamagePercentSchool = 0.0f;
7676 if (Player const* thisPlayer = ToPlayer())
7677 {
7678 for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
7679 if (schoolMask & (1 << i))
7680 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, thisPlayer->m_activePlayerData->ModDamageDonePercent[i]);
7681 }
7682 else
7683 maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, schoolMask);
7684
7685 DoneTotalMod *= maxModDamagePercentSchool;
7686 }
7687 }
7688
7689 if (!spellProto)
7690 {
7691 // melee attack
7693 AddPct(DoneTotalMod, autoAttackDamage->GetAmount());
7694 }
7695
7697
7698 // bonus against aurastate
7699 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [pVictim](AuraEffect const* aurEff) -> bool
7700 {
7701 if (pVictim->HasAuraState(AuraStateType(aurEff->GetMiscValue())))
7702 return true;
7703 return false;
7704 });
7705
7706 // bonus against target aura mechanic
7708 {
7709 if (pVictim->HasAuraWithMechanic(UI64LIT(1) << aurEff->GetMiscValue()))
7710 return true;
7711 return false;
7712 });
7713
7714 // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
7715 if (mechanic != MECHANIC_NONE)
7717 else if (spellProto && spellProto->Mechanic)
7719
7720 if (spell)
7721 spell->CallScriptCalcDamageHandlers(pVictim, damage, DoneFlatBenefit, DoneTotalMod);
7722 else if (aurEff)
7723 aurEff->GetBase()->CallScriptCalcDamageAndHealingHandlers(aurEff, aurEff->GetBase()->GetApplicationOfTarget(pVictim->GetGUID()), pVictim, damage, DoneFlatBenefit, DoneTotalMod);
7724
7725 float damageF = float(damage + DoneFlatBenefit) * DoneTotalMod;
7726
7727 // apply spellmod to Done damage
7728 if (spellProto)
7729 if (Player* modOwner = GetSpellModOwner())
7730 modOwner->ApplySpellMod(spellProto, damagetype == DOT ? SpellModOp::PeriodicHealingAndDamage : SpellModOp::HealingAndDamage, damageF);
7731
7732 // bonus result can be negative
7733 return int32(std::max(damageF, 0.0f));
7734}
7735
7736int32 Unit::MeleeDamageBonusTaken(Unit* attacker, int32 pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const* spellProto /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/)
7737{
7738 if (pdamage == 0)
7739 return 0;
7740
7741 int32 TakenFlatBenefit = 0;
7742
7743 // ..taken
7745
7746 if (attType != RANGED_ATTACK)
7748 else
7750
7751 if ((TakenFlatBenefit < 0) && (pdamage < -TakenFlatBenefit))
7752 return 0;
7753
7754 // Taken total percent damage auras
7755 float TakenTotalMod = 1.0f;
7756
7757 // ..taken
7759
7760 // .. taken pct (special attacks)
7761 if (spellProto)
7762 {
7763 // From caster spells
7764 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SCHOOL_MASK_DAMAGE_FROM_CASTER, [attacker, spellProto](AuraEffect const* aurEff) -> bool
7765 {
7766 return aurEff->GetCasterGUID() == attacker->GetGUID() && (aurEff->GetMiscValue() & spellProto->GetSchoolMask());
7767 });
7768
7769 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER, [attacker, spellProto](AuraEffect const* aurEff) -> bool
7770 {
7771 return aurEff->GetCasterGUID() == attacker->GetGUID() && aurEff->IsAffectingSpell(spellProto);
7772 });
7773
7774 // Mod damage from spell mechanic
7775 uint64 mechanicMask = spellProto->GetAllEffectsMechanicMask();
7776
7777 // Shred, Maul - "Effects which increase Bleed damage also increase Shred damage"
7778 if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x00008800)
7779 mechanicMask |= (1 << MECHANIC_BLEED);
7780
7781 if (mechanicMask)
7782 {
7783 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
7784 {
7785 if (mechanicMask & uint64(UI64LIT(1) << (aurEff->GetMiscValue())))
7786 return true;
7787 return false;
7788 });
7789 }
7790
7791 if (damagetype == DOT)
7792 {
7793 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_PERIODIC_DAMAGE_TAKEN, [spellProto](AuraEffect const* aurEff) -> bool
7794 {
7795 return aurEff->GetMiscValue() & spellProto->GetSchoolMask();
7796 });
7797 }
7798 }
7799 else // melee attack
7800 {
7801 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MELEE_DAMAGE_FROM_CASTER, [attacker](AuraEffect const* aurEff) -> bool
7802 {
7803 return aurEff->GetCasterGUID() == attacker->GetGUID();
7804 });
7805 }
7806
7807 if (AuraEffect const* cheatDeath = GetAuraEffect(45182, EFFECT_0))
7808 AddPct(TakenTotalMod, cheatDeath->GetAmount());
7809
7810 if (attType != RANGED_ATTACK)
7812 else
7814
7815 // Versatility
7816 if (Player* modOwner = GetSpellModOwner())
7817 {
7818 // only 50% of SPELL_AURA_MOD_VERSATILITY for damage reduction
7819 float versaBonus = modOwner->GetTotalAuraModifier(SPELL_AURA_MOD_VERSATILITY) / 2.0f;
7820 AddPct(TakenTotalMod, -(modOwner->GetRatingBonusValue(CR_VERSATILITY_DAMAGE_TAKEN) + versaBonus));
7821 }
7822
7823 // Sanctified Wrath (bypass damage reduction)
7824 if (TakenTotalMod < 1.0f)
7825 {
7826 SpellSchoolMask const attackSchoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask;
7827
7828 float damageReduction = 1.0f - TakenTotalMod;
7830 for (AuraEffect const* aurEff : casterIgnoreResist)
7831 {
7832 if (!(aurEff->GetMiscValue() & attackSchoolMask))
7833 continue;
7834
7835 AddPct(damageReduction, -aurEff->GetAmount());
7836 }
7837
7838 TakenTotalMod = 1.0f - damageReduction;
7839 }
7840
7841 float tmpDamage = float(pdamage + TakenFlatBenefit) * TakenTotalMod;
7842 return int32(std::max(tmpDamage, 0.0f));
7843}
7844
7846{
7847 if (apply)
7848 m_spellImmune[op].emplace(type, spellId);
7849 else
7850 {
7851 auto bounds = m_spellImmune[op].equal_range(type);
7852 for (auto itr = bounds.first; itr != bounds.second;)
7853 {
7854 if (itr->second == spellId)
7855 itr = m_spellImmune[op].erase(itr);
7856 else
7857 ++itr;
7858 }
7859 }
7860}
7861
7863{
7864 // normalized proc chance for weapon attack speed
7865 // (odd formula...)
7867 return (GetBaseAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
7869 return (GetBaseAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
7870 return 0;
7871}
7872
7873float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const* spellProto) const
7874{
7875 // proc per minute chance calculation
7876 if (PPM <= 0)
7877 return 0.0f;
7878
7879 // Apply chance modifer aura
7880 if (spellProto)
7881 if (Player* modOwner = GetSpellModOwner())
7882 modOwner->ApplySpellMod(spellProto, SpellModOp::ProcFrequency, PPM);
7883
7884 return std::floor((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
7885}
7886
7887void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry)
7888{
7890 if (mount)
7891 SetMountDisplayId(mount);
7892
7894
7896
7897 if (Player* player = ToPlayer())
7898 {
7899 // mount as a vehicle
7900 if (VehicleId)
7901 {
7902 if (CreateVehicleKit(VehicleId, creatureEntry))
7903 {
7904 player->SendOnCancelExpectedVehicleRideAura();
7905
7906 // mounts can also have accessories
7908 }
7909 }
7910
7911 // disable pet controls
7912 player->DisablePetControlsOnMount(REACT_PASSIVE, COMMAND_FOLLOW);
7913
7914 player->SendMovementSetCollisionHeight(player->GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Mount);
7915 }
7916
7918}
7919
7921{
7922 if (!IsMounted())
7923 return;
7924
7927
7928 if (Player* thisPlayer = ToPlayer())
7929 thisPlayer->SendMovementSetCollisionHeight(thisPlayer->GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Mount);
7930
7932
7933 // dismount as a vehicle
7935 {
7936 // Remove vehicle from player
7938 }
7939
7941
7942 // only resummon old pet if the player is already added to a map
7943 // this prevents adding a pet to a not created map which would otherwise cause a crash
7944 // (it could probably happen when logging in after a previous crash)
7945 if (Player* player = ToPlayer())
7946 {
7947 player->EnablePetControlsOnDismount();
7948 player->ResummonPetTemporaryUnSummonedIfAny();
7949 player->ResummonBattlePetTemporaryUnSummonedIfAny();
7950 }
7951}
7952
7954{
7955 if (!mountType)
7956 return nullptr;
7957
7958 DB2Manager::MountTypeXCapabilitySet const* capabilities = sDB2Manager.GetMountCapabilities(mountType);
7959 if (!capabilities)
7960 return nullptr;
7961
7962 uint32 areaId = GetAreaId();
7963 uint32 ridingSkill = 5000;
7965 bool isSubmerged = false;
7966 bool isInWater = false;
7967
7968 if (GetTypeId() == TYPEID_PLAYER)
7969 ridingSkill = ToPlayer()->GetSkillValue(SKILL_RIDING);
7970
7972 {
7974 mountFlags |= AreaMountFlags(auraEffect->GetMiscValue());
7975 }
7976 else if (AreaTableEntry const* areaTable = sAreaTableStore.LookupEntry(areaId))
7977 mountFlags = areaTable->GetMountFlags();
7978
7979 LiquidData liquid;
7980 ZLiquidStatus liquidStatus = GetMap()->GetLiquidStatus(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ(), {}, &liquid);
7981 isSubmerged = (liquidStatus & LIQUID_MAP_UNDER_WATER) != 0 || HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
7982 isInWater = (liquidStatus & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)) != 0;
7983
7984 for (MountTypeXCapabilityEntry const* mountTypeXCapability : *capabilities)
7985 {
7986 MountCapabilityEntry const* mountCapability = sMountCapabilityStore.LookupEntry(mountTypeXCapability->MountCapabilityID);
7987 if (!mountCapability)
7988 continue;
7989
7990 if (ridingSkill < mountCapability->ReqRidingSkill)
7991 continue;
7992
7993 if (!(mountCapability->Flags & MOUNT_CAPABIILTY_FLAG_IGNORE_RESTRICTIONS))
7994 {
7995 if (mountCapability->Flags & MOUNT_CAPABILITY_FLAG_GROUND && !(mountFlags.HasFlag(AreaMountFlags::AllowGroundMounts)))
7996 continue;
7997 if (mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLYING && !(mountFlags.HasFlag(AreaMountFlags::AllowFlyingMounts)))
7998 continue;
8000 continue;
8002 continue;
8003 }
8004
8005 if (!isSubmerged)
8006 {
8007 if (!isInWater)
8008 {
8009 // player is completely out of water
8010 if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_GROUND))
8011 continue;
8012 }
8013 // player is on water surface
8014 else if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLOAT))
8015 continue;
8016 }
8017 else if (isInWater)
8018 {
8019 if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_UNDERWATER))
8020 continue;
8021 }
8022 else if (!(mountCapability->Flags & MOUNT_CAPABILITY_FLAG_FLOAT))
8023 continue;
8024
8025 if (mountCapability->ReqMapID != -1 &&
8026 int32(GetMapId()) != mountCapability->ReqMapID &&
8027 GetMap()->GetEntry()->CosmeticParentMapID != mountCapability->ReqMapID &&
8028 GetMap()->GetEntry()->ParentMapID != mountCapability->ReqMapID)
8029 continue;
8030
8031 if (mountCapability->ReqAreaID && !DB2Manager::IsInArea(areaId, mountCapability->ReqAreaID))
8032 continue;
8033
8034 if (mountCapability->ReqSpellAuraID && !HasAura(mountCapability->ReqSpellAuraID))
8035 continue;
8036
8037 if (mountCapability->ReqSpellKnownID && !HasSpell(mountCapability->ReqSpellKnownID))
8038 continue;
8039
8040 if (Player const* thisPlayer = ToPlayer())
8041 if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(mountCapability->PlayerConditionID))
8042 if (!ConditionMgr::IsPlayerMeetingCondition(thisPlayer, playerCondition))
8043 continue;
8044
8045 return mountCapability;
8046 }
8047
8048 return nullptr;
8049}
8050
8052{
8053 if (IsLoading())
8054 return;
8055
8057 for (AuraEffect* aurEff : mounts)
8058 {
8059 aurEff->RecalculateAmount();
8060 if (!aurEff->GetAmount())
8061 aurEff->GetBase()->Remove();
8062 else if (MountCapabilityEntry const* capability = sMountCapabilityStore.LookupEntry(aurEff->GetAmount())) // aura may get removed by interrupt flag, reapply
8063 if (!HasAura(capability->ModSpellAuraID))
8064 CastSpell(this, capability->ModSpellAuraID, aurEff);
8065 }
8066}
8067
8069{
8070 return HasNpcFlag(
8075}
8076
8078{
8079 if (!enemy)
8080 return;
8081
8082 if (CanHaveThreatList())
8083 m_threatManager.AddThreat(enemy, 0.0f, nullptr, true, true);
8084 else
8085 SetInCombatWith(enemy);
8086}
8087
8088void Unit::SetImmuneToAll(bool apply, bool keepCombat)
8089{
8090 if (apply)
8091 {
8094 if (!keepCombat)
8096 }
8097 else
8099}
8100
8101void Unit::SetImmuneToPC(bool apply, bool keepCombat)
8102{
8103 if (apply)
8104 {
8107 if (!keepCombat)
8108 {
8109 std::list<CombatReference*> toEnd;
8110 for (auto const& pair : m_combatManager.GetPvECombatRefs())
8111 if (pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8112 toEnd.push_back(pair.second);
8113 for (auto const& pair : m_combatManager.GetPvPCombatRefs())
8114 if (pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8115 toEnd.push_back(pair.second);
8116 for (CombatReference* ref : toEnd)
8117 ref->EndCombat();
8118 }
8119 }
8120 else
8122}
8123
8124void Unit::SetImmuneToNPC(bool apply, bool keepCombat)
8125{
8126 if (apply)
8127 {
8130 if (!keepCombat)
8131 {
8132 std::list<CombatReference*> toEnd;
8133 for (auto const& pair : m_combatManager.GetPvECombatRefs())
8134 if (!pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8135 toEnd.push_back(pair.second);
8136 for (auto const& pair : m_combatManager.GetPvPCombatRefs())
8137 if (!pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8138 toEnd.push_back(pair.second);
8139 for (CombatReference* ref : toEnd)
8140 ref->EndCombat();
8141 }
8142 }
8143 else
8145}
8146
8148{
8149 if (apply)
8151 else
8153}
8154
8156{
8157 if (apply)
8159 else
8161}
8162
8164{
8166}
8167
8168bool Unit::isTargetableForAttack(bool checkFakeDeath) const
8169{
8170 if (!IsAlive())
8171 return false;
8172
8174 return false;
8175
8176 if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->IsGameMaster())
8177 return false;
8178
8179 return !HasUnitState(UNIT_STATE_UNATTACKABLE) && (!checkFakeDeath || !HasUnitState(UNIT_STATE_DIED));
8180}
8181
8183{
8184 int64 gain = 0;
8185
8186 if (dVal == 0)
8187 return 0;
8188
8189 int64 curHealth = (int64)GetHealth();
8190
8191 int64 val = dVal + curHealth;
8192 if (val <= 0)
8193 {
8194 SetHealth(0);
8195 return -curHealth;
8196 }
8197
8198 int64 maxHealth = (int64)GetMaxHealth();
8199
8200 if (val < maxHealth)
8201 {
8202 SetHealth(val);
8203 gain = val - curHealth;
8204 }
8205 else if (curHealth != maxHealth)
8206 {
8207 SetHealth(maxHealth);
8208 gain = maxHealth - curHealth;
8209 }
8210
8211 if (dVal < 0)
8212 {
8214 packet.Guid = GetGUID();
8215 packet.Health = GetHealth();
8216
8218 player->GetSession()->SendPacket(packet.Write());
8219 }
8220
8221 return gain;
8222}
8223
8225{
8226 int64 gain = 0;
8227
8228 if (dVal == 0)
8229 return 0;
8230
8231 int64 curHealth = (int64)GetHealth();
8232
8233 int64 val = dVal + curHealth;
8234 if (val <= 0)
8235 {
8236 return -curHealth;
8237 }
8238
8239 int64 maxHealth = (int64)GetMaxHealth();
8240
8241 if (val < maxHealth)
8242 gain = dVal;
8243 else if (curHealth != maxHealth)
8244 gain = maxHealth - curHealth;
8245
8246 return gain;
8247}
8248
8250{
8252 return;
8253
8255 for (AuraEffect const* effect : effects)
8256 {
8257 uint32 triggerHealthPct = effect->GetAmount();
8258 uint32 triggerSpell = effect->GetSpellEffectInfo().TriggerSpell;
8259 uint64 threshold = CountPctFromMaxHealth(triggerHealthPct);
8260
8261 switch (AuraTriggerOnHealthChangeDirection(effect->GetMiscValue()))
8262 {
8264 if (newVal < threshold || oldVal > threshold)
8265 continue;
8266 break;
8268 if (newVal > threshold || oldVal < threshold)
8269 continue;
8270 break;
8271 default:
8272 break;
8273 }
8274
8275 CastSpell(this, triggerSpell, effect);
8276 }
8277}
8278
8279// returns negative amount on power reduction
8280int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true*/)
8281{
8282 int32 gain = 0;
8283
8284 if (dVal == 0)
8285 return 0;
8286
8287 if (dVal > 0)
8289
8290 int32 curPower = GetPower(power);
8291
8292 int32 val = dVal + curPower;
8293 if (val <= GetMinPower(power))
8294 {
8295 SetPower(power, GetMinPower(power), withPowerUpdate);
8296 return -curPower;
8297 }
8298
8299 int32 maxPower = GetMaxPower(power);
8300
8301 if (val < maxPower)
8302 {
8303 SetPower(power, val, withPowerUpdate);
8304 gain = val - curPower;
8305 }
8306 else if (curPower != maxPower)
8307 {
8308 SetPower(power, maxPower, withPowerUpdate);
8309 gain = maxPower - curPower;
8310 }
8311
8312 return gain;
8313}
8314
8316{
8318 return true;
8319
8320 // Always seen by owner
8322 if (!guid.IsEmpty())
8323 if (seer->GetGUID() == guid)
8324 return true;
8325
8326 if (Player const* seerPlayer = seer->ToPlayer())
8327 if (Unit* owner = GetOwner())
8328 if (Player* ownerPlayer = owner->ToPlayer())
8329 if (ownerPlayer->IsGroupVisibleFor(seerPlayer))
8330 return true;
8331
8332 return false;
8333}
8334
8336{
8338 return true;
8339
8341 return true;
8342
8343 return false;
8344}
8345
8347{
8349}
8350
8352{
8353 if (!x)
8355 else
8357
8359}
8360
8362{
8363 int32 main_speed_mod = 0;
8364 float stack_bonus = 1.0f;
8365 float non_stack_bonus = 1.0f;
8366
8367 switch (mtype)
8368 {
8369 // Only apply debuffs
8370 case MOVE_FLIGHT_BACK:
8371 case MOVE_RUN_BACK:
8372 case MOVE_SWIM_BACK:
8373 break;
8374 case MOVE_WALK:
8375 return;
8376 case MOVE_RUN:
8377 {
8378 if (IsMounted()) // Use on mount auras
8379 {
8383 }
8384 else
8385 {
8389 }
8390 break;
8391 }
8392 case MOVE_SWIM:
8393 {
8395 break;
8396 }
8397 case MOVE_FLIGHT:
8398 {
8399 if (GetTypeId() == TYPEID_UNIT && IsControlledByPlayer()) // not sure if good for pet
8400 {
8403
8404 // for some spells this mod is applied on vehicle owner
8405 int32 owner_speed_mod = 0;
8406
8407 if (Unit* owner = GetCharmer())
8408 owner_speed_mod = owner->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED);
8409
8410 main_speed_mod = std::max(main_speed_mod, owner_speed_mod);
8411 }
8412 else if (IsMounted())
8413 {
8416 }
8417 else // Use not mount (shapeshift for example) auras (should stack)
8419
8421
8422 // Update speed for vehicle if available
8423 if (GetTypeId() == TYPEID_PLAYER && GetVehicle())
8425 break;
8426 }
8427 default:
8428 TC_LOG_ERROR("entities.unit", "Unit::UpdateSpeed: Unsupported move type ({})", mtype);
8429 return;
8430 }
8431
8432 // now we ready for speed calculation
8433 float speed = std::max(non_stack_bonus, stack_bonus);
8434 if (main_speed_mod)
8435 AddPct(speed, main_speed_mod);
8436
8437 switch (mtype)
8438 {
8439 case MOVE_RUN:
8440 case MOVE_SWIM:
8441 case MOVE_FLIGHT:
8442 {
8443 // Set creature speed rate
8444 if (GetTypeId() == TYPEID_UNIT)
8445 speed *= ToCreature()->GetCreatureTemplate()->speed_run; // at this point, MOVE_WALK is never reached
8446
8447 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8450 {
8451 if (Creature* creature = ToCreature())
8452 if (CreatureImmunities const* immunities = SpellMgr::GetCreatureImmunities(creature->GetCreatureTemplate()->CreatureImmunitiesId))
8453 if (immunities->Mechanic[MECHANIC_SNARE] || immunities->Mechanic[MECHANIC_DAZE])
8454 break;
8455
8456 // Use speed from aura
8457 float max_speed = normalization / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8458 if (speed > max_speed)
8459 speed = max_speed;
8460 }
8461
8462 if (mtype == MOVE_RUN)
8463 {
8464 // force minimum speed rate @ aura 437 SPELL_AURA_MOD_MINIMUM_SPEED_RATE
8466 {
8467 float minSpeed = minSpeedMod / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8468 if (speed < minSpeed)
8469 speed = minSpeed;
8470 }
8471 }
8472 break;
8473 }
8474 default:
8475 break;
8476 }
8477
8478 if (Creature* creature = ToCreature())
8479 {
8480 if (creature->HasUnitTypeMask(UNIT_MASK_MINION) && !creature->IsInCombat())
8481 {
8483 {
8484 Unit* followed = ASSERT_NOTNULL(dynamic_cast<AbstractFollower*>(GetMotionMaster()->GetCurrentMovementGenerator()))->GetTarget();
8485 if (followed && followed->GetGUID() == GetOwnerGUID() && !followed->IsInCombat())
8486 {
8487 float ownerSpeed = followed->GetSpeedRate(mtype);
8488 if (speed < ownerSpeed || creature->IsWithinDist3d(followed, 10.0f))
8489 speed = ownerSpeed;
8490 speed *= std::min(std::max(1.0f, 0.75f + (GetDistance(followed) - PET_FOLLOW_DIST) * 0.05f), 1.3f);
8491 }
8492 }
8493 }
8494 }
8495
8496 // Apply strongest slow aura mod to speed
8498 if (slow)
8499 AddPct(speed, slow);
8500
8501 if (float minSpeedMod = (float)GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MINIMUM_SPEED))
8502 {
8503 float baseMinSpeed = 1.0f;
8504 if (!GetOwnerGUID().IsPlayer() && !IsHunterPet() && GetTypeId() == TYPEID_UNIT)
8505 baseMinSpeed = ToCreature()->GetCreatureTemplate()->speed_run;
8506
8507 float min_speed = CalculatePct(baseMinSpeed, minSpeedMod);
8508 if (speed < min_speed)
8509 speed = min_speed;
8510 }
8511
8512 SetSpeedRate(mtype, speed);
8513}
8514
8516{
8517 return m_speed_rate[mtype]*(IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8518}
8519
8520void Unit::SetSpeed(UnitMoveType mtype, float newValue)
8521{
8522 SetSpeedRate(mtype, newValue / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]));
8523}
8524
8525void Unit::SetSpeedRate(UnitMoveType mtype, float rate)
8526{
8527 rate = std::max(rate, 0.01f);
8528
8529 // Update speed only on change
8530 if (m_speed_rate[mtype] == rate)
8531 return;
8532
8533 m_speed_rate[mtype] = rate;
8534
8536
8537 // Spline packets are for creatures and move_update are for players
8538 static OpcodeServer const moveTypeToOpcode[MAX_MOVE_TYPE][3] =
8539 {
8549 };
8550
8551 if (GetTypeId() == TYPEID_PLAYER)
8552 {
8553 // register forced speed changes for WorldSession::HandleForceSpeedChangeAck
8554 // and do it only for real sent packets and use run for run/mounted as client expected
8555 ++ToPlayer()->m_forced_speed_changes[mtype];
8556
8557 if (!IsInCombat())
8558 if (Pet* pet = ToPlayer()->GetPet())
8559 pet->SetSpeedRate(mtype, m_speed_rate[mtype]);
8560 }
8561
8562 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved())) // unit controlled by a player.
8563 {
8564 // Send notification to self
8565 WorldPackets::Movement::MoveSetSpeed selfpacket(moveTypeToOpcode[mtype][1]);
8566 selfpacket.MoverGUID = GetGUID();
8567 selfpacket.SequenceIndex = m_movementCounter++;
8568 selfpacket.Speed = GetSpeed(mtype);
8569 playerMover->GetSession()->SendPacket(selfpacket.Write());
8570
8571 // Send notification to other players
8572 WorldPackets::Movement::MoveUpdateSpeed packet(moveTypeToOpcode[mtype][2]);
8573 packet.Status = &m_movementInfo;
8574 packet.Speed = GetSpeed(mtype);
8575 playerMover->SendMessageToSet(packet.Write(), false);
8576 }
8577 else
8578 {
8579 WorldPackets::Movement::MoveSplineSetSpeed packet(moveTypeToOpcode[mtype][0]);
8580 packet.MoverGUID = GetGUID();
8581 packet.Speed = GetSpeed(mtype);
8582 SendMessageToSet(packet.Write(), true);
8583 }
8584}
8585
8587{
8588 while (!m_followingMe.empty())
8589 (*m_followingMe.begin())->SetTarget(nullptr);
8590}
8591
8593{
8594 // Death state needs to be updated before RemoveAllAurasOnDeath() is called, to prevent entering combat
8595 m_deathState = s;
8596
8597 bool isOnVehicle = GetVehicle() != nullptr;
8598
8599 if (s != ALIVE && s != JUST_RESPAWNED)
8600 {
8601 CombatStop();
8602
8603 if (IsNonMeleeSpellCast(false))
8605
8606 ExitVehicle(); // Exit vehicle before calling RemoveAllControlled
8607 // vehicles use special type of charm that is not removed by the next function
8608 // triggering an assert
8612 }
8613
8614 if (s == JUST_DIED)
8615 {
8616 // remove aurastates allowing special moves
8619
8620 // Don't clear the movement if the Unit was on a vehicle as we are exiting now
8621 if (!isOnVehicle)
8622 {
8623 if (GetMotionMaster()->StopOnDeath())
8624 DisableSpline();
8625 }
8626
8627 // without this when removing IncreaseMaxHealth aura player may stuck with 1 hp
8628 // do not why since in IncreaseMaxHealth currenthealth is checked
8629 SetHealth(0);
8630 SetPower(GetPowerType(), 0);
8633
8634 if (m_vignette && !m_vignette->Data->GetFlags().HasFlag(VignetteFlags::PersistsThroughDeath))
8635 SetVignette(0);
8636
8637 // players in instance don't have ZoneScript, but they have InstanceScript
8638 if (ZoneScript* zoneScript = GetZoneScript() ? GetZoneScript() : GetInstanceScript())
8639 zoneScript->OnUnitDeath(this);
8640 }
8641 else if (s == JUST_RESPAWNED)
8642 RemoveUnitFlag(UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground)
8643}
8644
8645//======================================================================
8646
8648{
8649 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end();)
8650 {
8651 AuraApplication* aurApp = itr->second;
8652 ++itr;
8653
8654 aurApp->GetBase()->CallScriptEnterLeaveCombatHandlers(aurApp, true);
8655 }
8656
8658 if (spell->getState() == SPELL_STATE_PREPARING
8659 && spell->m_spellInfo->HasAttribute(SPELL_ATTR0_NOT_IN_COMBAT_ONLY_PEACEFUL)
8660 && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Combat))
8662
8665
8668}
8669
8671{
8672 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end();)
8673 {
8674 AuraApplication* aurApp = itr->second;
8675 ++itr;
8676
8677 aurApp->GetBase()->CallScriptEnterLeaveCombatHandlers(aurApp, false);
8678 }
8679
8681
8684}
8685
8686void Unit::AtTargetAttacked(Unit* target, bool canInitialAggro)
8687{
8688 if (!target->IsEngaged() && !canInitialAggro)
8689 return;
8690 target->EngageWithTarget(this);
8691 if (Unit* targetOwner = target->GetCharmerOrOwner())
8692 targetOwner->EngageWithTarget(this);
8693
8695 Player* targetPlayerOwner = target->GetCharmerOrOwnerPlayerOrPlayerItself();
8696 if (myPlayerOwner && targetPlayerOwner && !(myPlayerOwner->duel && myPlayerOwner->duel->Opponent == targetPlayerOwner))
8697 {
8698 myPlayerOwner->UpdatePvP(true);
8699 myPlayerOwner->SetContestedPvP(targetPlayerOwner);
8701 }
8702}
8703
8705{
8706 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
8707
8708 bool state = false;
8709 for (Unit* minion : m_Controlled)
8710 if (minion->IsInCombat())
8711 {
8712 state = true;
8713 break;
8714 }
8715
8716 if (state)
8718 else
8720}
8721
8722void Unit::SetInteractionAllowedWhileHostile(bool interactionAllowed)
8723{
8724 if (interactionAllowed)
8726 else
8728
8730}
8731
8732void Unit::SetInteractionAllowedInCombat(bool interactionAllowed)
8733{
8734 if (interactionAllowed)
8736 else
8738
8739 if (IsInCombat())
8741}
8742
8744{
8745 for (uint32 i = 0; i < m_unitData->NpcFlags.size(); ++i)
8746 if (m_unitData->NpcFlags[i])
8748}
8749
8750//======================================================================
8751
8753{
8754 DiminishingReturn const& diminish = m_Diminishing[group];
8755 if (!diminish.hitCount)
8756 return DIMINISHING_LEVEL_1;
8757
8758 // If last spell was cast more than 18 seconds ago - reset level.
8759 if (!diminish.stack && GetMSTimeDiffToNow(diminish.hitTime) > 18 * IN_MILLISECONDS)
8760 return DIMINISHING_LEVEL_1;
8761
8762 return DiminishingLevels(diminish.hitCount);
8763}
8764
8765void Unit::IncrDiminishing(SpellInfo const* auraSpellInfo)
8766{
8768 uint32 currentLevel = GetDiminishing(group);
8769 uint32 const maxLevel = auraSpellInfo->GetDiminishingReturnsMaxLevel();
8770
8771 DiminishingReturn& diminish = m_Diminishing[group];
8772 if (currentLevel < maxLevel)
8773 diminish.hitCount = currentLevel + 1;
8774}
8775
8776bool Unit::ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, int32& duration, WorldObject* caster, DiminishingLevels previousLevel) const
8777{
8778 DiminishingGroup const group = auraSpellInfo->GetDiminishingReturnsGroupForSpell();
8779 if (duration == -1 || group == DIMINISHING_NONE)
8780 return true;
8781
8782 int32 const limitDuration = auraSpellInfo->GetDiminishingReturnsLimitDuration();
8783
8784 // test pet/charm masters instead pets/charmeds
8785 Unit const* targetOwner = GetCharmerOrOwner();
8786 Unit const* casterOwner = caster->GetCharmerOrOwner();
8787
8788 if (limitDuration > 0 && duration > limitDuration)
8789 {
8790 Unit const* target = targetOwner ? targetOwner : this;
8791 WorldObject const* source = casterOwner ? casterOwner : caster;
8792
8793 if (target->IsAffectedByDiminishingReturns() && source->GetTypeId() == TYPEID_PLAYER)
8794 duration = limitDuration;
8795 }
8796
8797 float mod = 1.0f;
8798 switch (group)
8799 {
8800 case DIMINISHING_TAUNT:
8801 {
8802 if (GetTypeId() == TYPEID_UNIT && (ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS))
8803 {
8804 DiminishingLevels diminish = previousLevel;
8805 switch (diminish)
8806 {
8807 case DIMINISHING_LEVEL_1: break;
8808 case DIMINISHING_LEVEL_2: mod = 0.65f; break;
8809 case DIMINISHING_LEVEL_3: mod = 0.4225f; break;
8810 case DIMINISHING_LEVEL_4: mod = 0.274625f; break;
8811 case DIMINISHING_LEVEL_TAUNT_IMMUNE: mod = 0.0f; break;
8812 default: break;
8813 }
8814 }
8815 break;
8816 }
8818 {
8819 if (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_ALL ||
8820 (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_PLAYER &&
8821 (targetOwner ? targetOwner->IsAffectedByDiminishingReturns() : IsAffectedByDiminishingReturns())))
8822 {
8823 DiminishingLevels diminish = previousLevel;
8824 switch (diminish)
8825 {
8826 case DIMINISHING_LEVEL_1: break;
8827 case DIMINISHING_LEVEL_2: mod = 0.0f; break;
8828 default: break;
8829 }
8830 }
8831 break;
8832 }
8833 default:
8834 {
8835 if (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_ALL ||
8836 (auraSpellInfo->GetDiminishingReturnsGroupType() == DRTYPE_PLAYER &&
8837 (targetOwner ? targetOwner->IsAffectedByDiminishingReturns() : IsAffectedByDiminishingReturns())))
8838 {
8839 DiminishingLevels diminish = previousLevel;
8840 switch (diminish)
8841 {
8842 case DIMINISHING_LEVEL_1: break;
8843 case DIMINISHING_LEVEL_2: mod = 0.5f; break;
8844 case DIMINISHING_LEVEL_3: mod = 0.25f; break;
8845 case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f; break;
8846 default: break;
8847 }
8848 }
8849 break;
8850 }
8851 }
8852
8853 duration = int32(duration * mod);
8854 return (duration != 0);
8855}
8856
8858{
8859 // Checking for existing in the table
8860 DiminishingReturn& diminish = m_Diminishing[group];
8861
8862 if (apply)
8863 ++diminish.stack;
8864 else if (diminish.stack)
8865 {
8866 --diminish.stack;
8867
8868 // Remember time after last aura from group removed
8869 if (!diminish.stack)
8870 diminish.hitTime = GameTime::GetGameTimeMS();
8871 }
8872}
8873
8875{
8876 for (DiminishingReturn& dim : m_Diminishing)
8877 dim.Clear();
8878}
8879
8881{
8882 if (GetTypeId() == TYPEID_PLAYER)
8883 {
8885 SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form);
8886 if (ssEntry && ssEntry->CreatureType > 0)
8887 return ssEntry->CreatureType;
8888 else
8889 {
8890 ChrRacesEntry const* raceEntry = sChrRacesStore.AssertEntry(GetRace());
8891 return raceEntry->CreatureType;
8892 }
8893 }
8894 else
8895 return ToCreature()->GetCreatureTemplate()->type;
8896}
8897
8899{
8900 uint32 creatureType = GetCreatureType();
8901 return (creatureType >= 1) ? (1 << (creatureType - 1)) : 0;
8902}
8903
8905{
8907}
8908
8910{
8912 return form == FORM_CAT_FORM || form == FORM_BEAR_FORM || form == FORM_DIRE_BEAR_FORM || form == FORM_GHOST_WOLF;
8913}
8914
8916{
8918}
8919
8920bool Unit::IsDisallowedMountForm(uint32 spellId, ShapeshiftForm form, uint32 displayId) const
8921{
8922 if (SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()))
8923 if (transformSpellInfo->HasAttribute(SPELL_ATTR0_ALLOW_WHILE_MOUNTED))
8924 return false;
8925
8926 if (form)
8927 {
8928 SpellShapeshiftFormEntry const* shapeshift = sSpellShapeshiftFormStore.LookupEntry(form);
8929 if (!shapeshift)
8930 return true;
8931
8932 if (!shapeshift->GetFlags().HasFlag(SpellShapeshiftFormFlags::Stance))
8933 return true;
8934 }
8935
8936 if (displayId == GetNativeDisplayId())
8937 return false;
8938
8939 CreatureDisplayInfoEntry const* display = sCreatureDisplayInfoStore.LookupEntry(displayId);
8940 if (!display)
8941 return true;
8942
8944 if (!displayExtra)
8945 return true;
8946
8947 CreatureModelDataEntry const* model = sCreatureModelDataStore.LookupEntry(display->ModelID);
8948 ChrRacesEntry const* race = sChrRacesStore.LookupEntry(displayExtra->DisplayRaceID);
8949
8951 if (race && !race->GetFlags().HasFlag(ChrRacesFlag::CanMount))
8952 return true;
8953
8954 return false;
8955}
8956
8957/*#######################################
8958######## ########
8959######## STAT SYSTEM ########
8960######## ########
8961#######################################*/
8962
8963void Unit::HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
8964{
8965 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END)
8966 {
8967 TC_LOG_ERROR("entities.unit", "ERROR in HandleStatFlatModifier(): non-existing UnitMods or wrong UnitModifierType!");
8968 return;
8969 }
8970
8971 if (!amount)
8972 return;
8973
8974 switch (modifierType)
8975 {
8976 case BASE_VALUE:
8978 case TOTAL_VALUE:
8979 m_auraFlatModifiersGroup[unitMod][modifierType] += apply ? amount : -amount;
8980 break;
8981 default:
8982 break;
8983 }
8984
8985 UpdateUnitMod(unitMod);
8986}
8987
8988void Unit::ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float pct)
8989{
8990 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
8991 {
8992 TC_LOG_ERROR("entities.unit", "ERROR in ApplyStatPctModifier(): non-existing UnitMods or wrong UnitModifierType!");
8993 return;
8994 }
8995
8996 if (!pct)
8997 return;
8998
8999 switch (modifierType)
9000 {
9001 case BASE_PCT:
9002 case TOTAL_PCT:
9003 AddPct(m_auraPctModifiersGroup[unitMod][modifierType], pct);
9004 break;
9005 default:
9006 break;
9007 }
9008
9009 UpdateUnitMod(unitMod);
9010}
9011
9012void Unit::SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
9013{
9014 if (m_auraFlatModifiersGroup[unitMod][modifierType] == val)
9015 return;
9016
9017 m_auraFlatModifiersGroup[unitMod][modifierType] = val;
9018 UpdateUnitMod(unitMod);
9019}
9020
9021void Unit::SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
9022{
9023 if (m_auraPctModifiersGroup[unitMod][modifierType] == val)
9024 return;
9025
9026 m_auraPctModifiersGroup[unitMod][modifierType] = val;
9027 UpdateUnitMod(unitMod);
9028}
9029
9031{
9032 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END)
9033 {
9034 TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
9035 return 0.0f;
9036 }
9037
9038 return m_auraFlatModifiersGroup[unitMod][modifierType];
9039}
9040
9042{
9043 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
9044 {
9045 TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
9046 return 0.0f;
9047 }
9048
9049 return m_auraPctModifiersGroup[unitMod][modifierType];
9050}
9051
9053{
9054 if (!CanModifyStats())
9055 return;
9056
9057 switch (unitMod)
9058 {
9063
9064 case UNIT_MOD_ARMOR: UpdateArmor(); break;
9065 case UNIT_MOD_HEALTH: UpdateMaxHealth(); break;
9066
9067 case UNIT_MOD_MANA:
9068 case UNIT_MOD_RAGE:
9069 case UNIT_MOD_FOCUS:
9070 case UNIT_MOD_ENERGY:
9072 case UNIT_MOD_RUNES:
9077 case UNIT_MOD_ALTERNATE:
9078 case UNIT_MOD_MAELSTROM:
9079 case UNIT_MOD_CHI:
9080 case UNIT_MOD_INSANITY:
9084 case UNIT_MOD_FURY:
9085 case UNIT_MOD_PAIN:
9086 case UNIT_MOD_ESSENCE:
9093
9100
9103
9107
9108 default:
9109 ABORT_MSG("Not implemented UnitMod %u", unitMod);
9110 break;
9111 }
9112}
9113
9114void Unit::UpdateDamageDoneMods(WeaponAttackType attackType, int32 /*skipEnchantSlot = -1*/)
9115{
9116 UnitMods unitMod;
9117 switch (attackType)
9118 {
9119 case BASE_ATTACK:
9120 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
9121 break;
9122 case OFF_ATTACK:
9123 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
9124 break;
9125 case RANGED_ATTACK:
9126 unitMod = UNIT_MOD_DAMAGE_RANGED;
9127 break;
9128 default:
9129 ABORT();
9130 break;
9131 }
9132
9133 float amount = GetTotalAuraModifier(SPELL_AURA_MOD_DAMAGE_DONE, [&](AuraEffect const* aurEff) -> bool
9134 {
9135 if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
9136 return false;
9137
9138 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9139 });
9140
9141 SetStatFlatModifier(unitMod, TOTAL_VALUE, amount);
9142}
9143
9145{
9146 for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
9148}
9149
9151{
9152 float factor;
9153 UnitMods unitMod;
9154 switch (attackType)
9155 {
9156 case BASE_ATTACK:
9157 factor = 1.0f;
9158 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
9159 break;
9160 case OFF_ATTACK:
9161 // off hand has 50% penalty
9162 factor = 0.5f;
9163 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
9164 break;
9165 case RANGED_ATTACK:
9166 factor = 1.0f;
9167 unitMod = UNIT_MOD_DAMAGE_RANGED;
9168 break;
9169 default:
9170 ABORT();
9171 break;
9172 }
9173
9174 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, [attackType, this](AuraEffect const* aurEff) -> bool
9175 {
9176 if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
9177 return false;
9178
9179 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9180 });
9181
9182 if (attackType == OFF_ATTACK)
9183 factor *= GetTotalAuraModifier(SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT, [this, attackType](AuraEffect const* aurEff)
9184 {
9185 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9186 });
9187
9188 SetStatPctModifier(unitMod, TOTAL_PCT, factor);
9189}
9190
9192{
9193 for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
9195}
9196
9198{
9200
9201 // value = ((base_value * base_pct) + total_value) * total_pct
9202 float value = CalculatePct(GetFlatModifierValue(unitMod, BASE_VALUE), std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
9203 value += GetCreateStat(stat);
9204 value *= GetPctModifierValue(unitMod, BASE_PCT);
9205 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9206 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9207
9208 return value;
9209}
9210
9212{
9213 if (unitMod >= UNIT_MOD_END)
9214 {
9215 TC_LOG_ERROR("entities.unit", "attempt to access non-existing UnitMods in GetTotalAuraModValue()!");
9216 return 0.0f;
9217 }
9218
9219 float value = CalculatePct(GetFlatModifierValue(unitMod, BASE_VALUE), std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
9220 value *= GetPctModifierValue(unitMod, BASE_PCT);
9221 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9222 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9223
9224 return value;
9225}
9226
9228{
9230
9231 switch (unitMod)
9232 {
9233 case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break;
9234 case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break;
9235 case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break;
9236 case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break;
9237 case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break;
9238 case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break;
9239
9240 default:
9241 break;
9242 }
9243
9244 return school;
9245}
9246
9248{
9249 Stats stat = STAT_STRENGTH;
9250
9251 switch (unitMod)
9252 {
9253 case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break;
9254 case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break;
9255 case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break;
9256 case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break;
9257 default:
9258 break;
9259 }
9260
9261 return stat;
9262}
9263
9265{
9266 if (school > SPELL_SCHOOL_NORMAL)
9267 {
9268 UnitMods unitMod = UnitMods(UNIT_MOD_RESISTANCE_START + school);
9269
9270 float value = CalculatePct(GetFlatModifierValue(unitMod, BASE_VALUE), std::max(GetFlatModifierValue(unitMod, BASE_PCT_EXCLUDE_CREATE), -100.0f));
9271 value *= GetPctModifierValue(unitMod, BASE_PCT);
9272
9273 float baseValue = value;
9274
9275 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9276 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9277
9278 SetResistance(SpellSchools(school), int32(value));
9279 SetBonusResistanceMod(SpellSchools(school), int32(value - baseValue));
9280 }
9281 else
9282 UpdateArmor();
9283}
9284
9285float Unit::GetTotalAttackPowerValue(WeaponAttackType attType, bool includeWeapon /*= true*/) const
9286{
9287 if (attType == RANGED_ATTACK)
9288 {
9289 float ap = m_unitData->RangedAttackPower + m_unitData->RangedAttackPowerModPos + m_unitData->RangedAttackPowerModNeg;
9290 if (includeWeapon)
9291 ap += std::max<float>(m_unitData->MainHandWeaponAttackPower, m_unitData->RangedWeaponAttackPower);
9292 if (ap < 0)
9293 return 0.0f;
9294 return ap * (1.0f + m_unitData->RangedAttackPowerMultiplier);
9295 }
9296 else
9297 {
9298 float ap = m_unitData->AttackPower + m_unitData->AttackPowerModPos + m_unitData->AttackPowerModNeg;
9299 if (includeWeapon)
9300 {
9301 if (attType == BASE_ATTACK)
9302 ap += std::max<float>(m_unitData->MainHandWeaponAttackPower, m_unitData->RangedWeaponAttackPower);
9303 else
9304 {
9305 ap += m_unitData->OffHandWeaponAttackPower;
9306 ap /= 2;
9307 }
9308 }
9309 if (ap < 0)
9310 return 0.0f;
9311 return ap * (1.0f + m_unitData->AttackPowerMultiplier);
9312 }
9313}
9314
9316{
9317 if (attType == OFF_ATTACK && !haveOffhandWeapon())
9318 return 0.0f;
9319
9320 return m_weaponDamage[attType][type];
9321}
9322
9324{
9327}
9328
9329void Unit::SetLevel(uint8 lvl, bool sendUpdate/* = true*/)
9330{
9332
9333 if (!sendUpdate)
9334 return;
9335
9336 if (Player* player = ToPlayer())
9337 {
9338 // group update
9339 if (player->GetGroup())
9340 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL);
9341
9342 sCharacterCache->UpdateCharacterLevel(GetGUID(), lvl);
9343 }
9344}
9345
9347{
9349 val = 0;
9350 else if (GetTypeId() == TYPEID_PLAYER && getDeathState() == DEAD)
9351 val = 1;
9352 else
9353 {
9354 uint64 maxHealth = GetMaxHealth();
9355 if (maxHealth < val)
9356 val = maxHealth;
9357 }
9358
9359 uint64 oldVal = GetHealth();
9361
9362 TriggerOnHealthChangeAuras(oldVal, val);
9363
9364 // group update
9365 if (Player* player = ToPlayer())
9366 {
9367 if (player->GetGroup())
9368 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP);
9369 }
9370 else if (Pet* pet = ToCreature()->ToPet())
9371 {
9372 if (pet->isControlled())
9373 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_HP);
9374 }
9375}
9376
9378{
9379 if (!val)
9380 val = 1;
9381
9382 uint64 health = GetHealth();
9384
9385 // group update
9386 if (GetTypeId() == TYPEID_PLAYER)
9387 {
9388 if (ToPlayer()->GetGroup())
9390 }
9391 else if (Pet* pet = ToCreature()->ToPet())
9392 {
9393 if (pet->isControlled())
9394 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_HP);
9395 }
9396
9397 if (val < health)
9398 SetHealth(val);
9399}
9400
9402{
9403 uint32 powerIndex = GetPowerIndex(power);
9404 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
9405 return 0;
9406
9407 return m_unitData->Power[powerIndex];
9408}
9409
9411{
9412 uint32 powerIndex = GetPowerIndex(power);
9413 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
9414 return 0;
9415
9416 return m_unitData->MaxPower[powerIndex];
9417}
9418
9419void Unit::SetPower(Powers power, int32 val, bool withPowerUpdate /*= true*/)
9420{
9421 uint32 powerIndex = GetPowerIndex(power);
9422 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
9423 return;
9424
9425 int32 maxPower = GetMaxPower(power);
9426 if (maxPower < val)
9427 val = maxPower;
9428
9429 int32 oldPower = m_unitData->Power[powerIndex];
9431
9432 if (IsInWorld() && withPowerUpdate)
9433 {
9435 packet.Guid = GetGUID();
9437 packet.Powers.emplace_back(val, power);
9439 }
9440
9441 TriggerOnPowerChangeAuras(power, oldPower, val);
9442
9443 // group update
9444 if (Player* player = ToPlayer())
9445 {
9446 if (player->GetGroup())
9447 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
9448 }
9449 /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x
9450 {
9451 if (pet->isControlled())
9452 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_CUR_POWER);
9453 }*/
9454}
9455
9457{
9458 uint32 powerIndex = GetPowerIndex(power);
9459 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
9460 return;
9461
9462 int32 cur_power = GetPower(power);
9464
9465 // group update
9466 if (GetTypeId() == TYPEID_PLAYER)
9467 {
9468 if (ToPlayer()->GetGroup())
9470 }
9471 /*else if (Pet* pet = ToCreature()->ToPet()) TODO 6.x
9472 {
9473 if (pet->isControlled())
9474 pet->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_MAX_POWER);
9475 }*/
9476
9477 if (val < cur_power)
9478 SetPower(power, val);
9479}
9480
9482{
9483 auto processAuras = [&](AuraEffectVector const& effects)
9484 {
9485 for (AuraEffect const* effect : effects)
9486 {
9487 if (effect->GetMiscValue() == power)
9488 {
9489 uint32 effectAmount = effect->GetAmount();
9490 uint32 triggerSpell = effect->GetSpellEffectInfo().TriggerSpell;
9491
9492 float oldValueCheck = oldVal;
9493 float newValueCheck = newVal;
9494
9495 if (effect->GetAuraType() == SPELL_AURA_TRIGGER_SPELL_ON_POWER_PCT)
9496 {
9497 int32 maxPower = GetMaxPower(power);
9498 oldValueCheck = GetPctOf(oldVal, maxPower);
9499 newValueCheck = GetPctOf(newVal, maxPower);
9500 }
9501
9502 switch (AuraTriggerOnPowerChangeDirection(effect->GetMiscValueB()))
9503 {
9505 if (oldValueCheck >= effect->GetAmount() || newValueCheck < effectAmount)
9506 continue;
9507 break;
9509 if (oldValueCheck <= effect->GetAmount() || newValueCheck > effectAmount)
9510 continue;
9511 break;
9512 default:
9513 break;
9514 }
9515
9516 CastSpell(this, triggerSpell, effect);
9517 }
9518 }
9519 };
9520
9523}
9524
9526{
9527 if (UnitAI* ai = GetAI())
9528 {
9529 m_aiLocked = true;
9530 ai->UpdateAI(diff);
9531 m_aiLocked = false;
9532 }
9533}
9534
9536{
9537 i_AIs.emplace(newAI);
9538}
9539
9541{
9542 PushAI(newAI);
9543 RefreshAI();
9544}
9545
9547{
9548 if (!i_AIs.empty())
9549 {
9550 i_AIs.pop();
9551 return true;
9552 }
9553 else
9554 return false;
9555}
9556
9558{
9559 ASSERT(!m_aiLocked, "Tried to change current AI during UpdateAI()");
9560 if (i_AIs.empty())
9561 i_AI = nullptr;
9562 else
9563 i_AI = i_AIs.top();
9564}
9565
9567{
9568 bool const charmed = IsCharmed();
9569
9570 if (charmed)
9572 else
9573 {
9575 PushAI(GetScheduledChangeAI()); //This could actually be PopAI() to get the previous AI but it's required atm to trigger UpdateCharmAI()
9576 }
9577}
9578
9580{
9581 // Keep popping the stack until we either reach the bottom or find a valid AI
9582 while (PopAI())
9583 if (GetTopAI() && dynamic_cast<ScheduledChangeAI*>(GetTopAI()) == nullptr)
9584 return;
9585}
9586
9588{
9589 if (Creature* creature = ToCreature())
9590 return sCreatureAIRegistry->GetRegistryItem("ScheduledChangeAI")->Create(creature);
9591 else
9592 return nullptr;
9593}
9594
9596{
9597 if (UnitAI* ai = GetAI())
9598 return dynamic_cast<ScheduledChangeAI*>(ai) != nullptr;
9599 else
9600 return true;
9601}
9602
9604{
9606 i_motionMaster->AddToWorld();
9607
9609}
9610
9612{
9613 // cleanup
9614 ASSERT(GetGUID());
9615
9616 if (IsInWorld())
9617 {
9618 if (IsAreaSpiritHealer())
9619 {
9620 if (Creature* creature = ToCreature())
9621 creature->SummonGraveyardTeleporter();
9622 }
9623
9625 if (UnitAI* ai = GetAI())
9626 ai->OnDespawn();
9627
9628 if (IsVehicle())
9629 RemoveVehicleKit(true);
9630
9635
9639
9640 ExitVehicle(); // Remove applied auras with SPELL_AURA_CONTROL_VEHICLE
9643
9645
9647
9648 if (IsCharmed())
9649 RemoveCharmedBy(nullptr);
9650
9651 ASSERT(!GetCharmedGUID(), "Unit %u has charmed guid when removed from world", GetEntry());
9652 ASSERT(!GetCharmerGUID(), "Unit %u has charmer guid when removed from world", GetEntry());
9653
9654 if (Unit* owner = GetOwner())
9655 {
9656 if (owner->m_Controlled.find(this) != owner->m_Controlled.end())
9657 {
9658 TC_LOG_FATAL("entities.unit", "Unit {} is in controlled list of {} when removed from world", GetEntry(), owner->GetEntry());
9659 ABORT();
9660 }
9661 }
9662
9665 }
9666}
9667
9669{
9670 // This needs to be before RemoveFromWorld to make GetCaster() return a valid pointer on aura removal
9672
9673 SetVignette(0);
9674
9675 if (IsInWorld())
9677 else
9678 {
9679 // cleanup that must happen even if not in world
9680 if (IsVehicle())
9681 RemoveVehicleKit(true);
9682 }
9683
9684 ASSERT(GetGUID());
9685
9686 // A unit may be in removelist and not in world, but it is still in grid
9687 // and may have some references during delete
9690
9691 if (finalCleanup)
9692 m_cleanupDone = true;
9693
9694 CombatStop();
9695}
9696
9697void Unit::CleanupsBeforeDelete(bool finalCleanup)
9698{
9699 CleanupBeforeRemoveFromMap(finalCleanup);
9700
9702}
9703
9705{
9706 if (IsCharmed())
9707 {
9708 UnitAI* newAI = nullptr;
9709 if (GetTypeId() == TYPEID_PLAYER)
9710 {
9711 if (Unit* charmer = GetCharmer())
9712 {
9713 // first, we check if the creature's own AI specifies an override playerai for its owned players
9714 if (Creature* creatureCharmer = charmer->ToCreature())
9715 {
9716 if (CreatureAI* charmerAI = creatureCharmer->AI())
9717 newAI = charmerAI->GetAIForCharmedPlayer(ToPlayer());
9718 }
9719 else
9720 TC_LOG_ERROR("entities.unit.ai", "Attempt to assign charm AI to player {} who is charmed by non-creature {}.", GetGUID().ToString(), GetCharmerGUID().ToString());
9721 }
9722 if (!newAI) // otherwise, we default to the generic one
9723 newAI = new SimpleCharmedPlayerAI(ToPlayer());
9724 }
9725 else
9726 {
9728 if (isPossessed() || IsVehicle())
9729 newAI = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PossessedAI"))->Create(ToCreature());
9730 else
9731 newAI = ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PetAI"))->Create(ToCreature());
9732 }
9733
9734 ASSERT(newAI);
9735 SetAI(newAI);
9736 newAI->OnCharmed(true);
9737 }
9738 else
9739 {
9741 // Hack: this is required because we want to call OnCharmed(true) on the restored AI
9742 RefreshAI();
9743 if (UnitAI* ai = GetAI())
9744 ai->OnCharmed(true);
9745 }
9746}
9747
9749{
9750 if (!m_charmInfo)
9751 m_charmInfo = std::make_unique<CharmInfo>(this);
9752
9753 return m_charmInfo.get();
9754}
9755
9757{
9758 if (!m_charmInfo)
9759 return;
9760
9761 m_charmInfo->RestoreState();
9762 m_charmInfo = nullptr;
9763}
9764
9766{
9770
9772 packet.MoverGUID = target->GetGUID();
9773 ToPlayer()->SendDirectMessage(packet.Write());
9774}
9775
9777{
9778 ProcFlagsHit hitMask = PROC_HIT_NONE;
9779 // Check victim state
9780 if (missCondition != SPELL_MISS_NONE)
9781 {
9782 switch (missCondition)
9783 {
9784 case SPELL_MISS_MISS:
9785 hitMask |= PROC_HIT_MISS;
9786 break;
9787 case SPELL_MISS_DODGE:
9788 hitMask |= PROC_HIT_DODGE;
9789 break;
9790 case SPELL_MISS_PARRY:
9791 hitMask |= PROC_HIT_PARRY;
9792 break;
9793 case SPELL_MISS_BLOCK:
9794 // spells can't be partially blocked (it's damage can though)
9796 break;
9797 case SPELL_MISS_EVADE:
9798 hitMask |= PROC_HIT_EVADE;
9799 break;
9800 case SPELL_MISS_IMMUNE:
9801 case SPELL_MISS_IMMUNE2:
9802 hitMask |= PROC_HIT_IMMUNE;
9803 break;
9804 case SPELL_MISS_DEFLECT:
9805 hitMask |= PROC_HIT_DEFLECT;
9806 break;
9807 case SPELL_MISS_ABSORB:
9808 hitMask |= PROC_HIT_ABSORB;
9809 break;
9810 case SPELL_MISS_REFLECT:
9811 hitMask |= PROC_HIT_REFLECT;
9812 break;
9813 case SPELL_MISS_RESIST:
9814 hitMask |= PROC_HIT_FULL_RESIST;
9815 break;
9816 default:
9817 break;
9818 }
9819 }
9820 else
9821 {
9822 // On block
9823 if (damageInfo->blocked)
9824 {
9825 hitMask |= PROC_HIT_BLOCK;
9826 if (damageInfo->fullBlock)
9827 hitMask |= PROC_HIT_FULL_BLOCK;
9828 }
9829 // On absorb
9830 if (damageInfo->absorb)
9831 hitMask |= PROC_HIT_ABSORB;
9832
9833 // Don't set hit/crit hitMask if damage is nullified
9834 bool const damageNullified = (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || (hitMask & PROC_HIT_FULL_BLOCK) != 0;
9835 if (!damageNullified)
9836 {
9837 // On crit
9838 if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT)
9839 hitMask |= PROC_HIT_CRITICAL;
9840 else
9841 hitMask |= PROC_HIT_NORMAL;
9842 }
9843 else if ((damageInfo->HitInfo & HITINFO_FULL_RESIST) != 0)
9844 hitMask |= PROC_HIT_FULL_RESIST;
9845 }
9846
9847 return hitMask;
9848}
9849
9850void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, ProcFlagsInit const& typeMask, ProcFlagsHit hitMask, WeaponAttackType /*attType*/)
9851{
9852 // Player is loaded now - do not allow passive spell casts to proc
9853 if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetSession()->PlayerLoading())
9854 return;
9855
9856 // For melee/ranged based attack need update skills and set some Aura states if victim present
9857 if (typeMask & MELEE_BASED_TRIGGER_MASK && procTarget)
9858 {
9859 // If exist crit/parry/dodge/block need update aura state (for victim and attacker)
9861 {
9862 // for victim
9863 if (isVictim)
9864 {
9865 // if victim and dodge attack
9866 if (hitMask & PROC_HIT_DODGE)
9867 {
9868 // Update AURA_STATE on dodge
9869 if (GetClass() != CLASS_ROGUE) // skip Rogue Riposte
9870 {
9873 }
9874 }
9875 // if victim and parry attack
9876 if (hitMask & PROC_HIT_PARRY)
9877 {
9880 }
9881 // if and victim block attack
9882 if (hitMask & PROC_HIT_BLOCK)
9883 {
9886 }
9887 }
9888 }
9889 }
9890}
9891
9893{
9894 TimePoint now = GameTime::Now();
9895
9896 auto processAuraApplication = [&](AuraApplication* aurApp)
9897 {
9898 if (uint32 procEffectMask = aurApp->GetBase()->GetProcEffectMask(aurApp, eventInfo, now))
9899 {
9900 aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now);
9901 aurasTriggeringProc.emplace_back(procEffectMask, aurApp);
9902 }
9903 else
9904 {
9905 if (aurApp->GetBase()->GetSpellInfo()->HasAttribute(SPELL_ATTR0_PROC_FAILURE_BURNS_CHARGE))
9906 {
9907 if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(aurApp->GetBase()->GetSpellInfo()))
9908 {
9909 aurApp->GetBase()->PrepareProcChargeDrop(procEntry, eventInfo);
9910 aurasTriggeringProc.emplace_back(0, aurApp);
9911 }
9912 }
9913
9914 if (aurApp->GetBase()->GetSpellInfo()->HasAttribute(SPELL_ATTR2_PROC_COOLDOWN_ON_FAILURE))
9915 if (SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(aurApp->GetBase()->GetSpellInfo()))
9916 aurApp->GetBase()->AddProcCooldown(procEntry, now);
9917 }
9918 };
9919
9920 // use provided list of auras which can proc
9921 if (procAuras)
9922 {
9923 for (AuraApplication* aurApp : *procAuras)
9924 {
9925 ASSERT(aurApp->GetTarget() == this);
9926 processAuraApplication(aurApp);
9927 }
9928 }
9929 // or generate one on our own
9930 else
9931 {
9932 for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr)
9933 processAuraApplication(itr->second);
9934 }
9935}
9936
9937void Unit::TriggerAurasProcOnEvent(AuraApplicationList* myProcAuras, AuraApplicationList* targetProcAuras, Unit* actionTarget,
9938 ProcFlagsInit const& typeMaskActor, ProcFlagsInit const& typeMaskActionTarget, ProcFlagsSpellType spellTypeMask,
9939 ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
9940{
9941 // prepare data for self trigger
9942 ProcEventInfo myProcEventInfo(this, actionTarget, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
9943 AuraApplicationProcContainer myAurasTriggeringProc;
9944 if (typeMaskActor)
9945 {
9946 GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, myProcAuras, myProcEventInfo);
9947
9948 // needed for example for Cobra Strikes, pet does the attack, but aura is on owner
9949 if (Player* modOwner = GetSpellModOwner())
9950 {
9951 if (modOwner != this && spell)
9952 {
9953 AuraApplicationList modAuras;
9954 for (auto itr = modOwner->GetAppliedAuras().begin(); itr != modOwner->GetAppliedAuras().end(); ++itr)
9955 {
9956 if (spell->m_appliedMods.count(itr->second->GetBase()) != 0)
9957 modAuras.push_front(itr->second);
9958 }
9959 modOwner->GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, &modAuras, myProcEventInfo);
9960 }
9961 }
9962 }
9963
9964 // prepare data for target trigger
9965 ProcEventInfo targetProcEventInfo(this, actionTarget, this, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
9966 AuraApplicationProcContainer targetAurasTriggeringProc;
9967 if (typeMaskActionTarget && actionTarget)
9968 actionTarget->GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, targetProcAuras, targetProcEventInfo);
9969
9970 TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc);
9971
9972 if (typeMaskActionTarget && actionTarget)
9973 actionTarget->TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc);
9974}
9975
9977{
9978 Spell const* triggeringSpell = eventInfo.GetProcSpell();
9979 bool const disableProcs = triggeringSpell && triggeringSpell->IsProcDisabled();
9980
9981 int32 oldProcChainLength = std::exchange(m_procChainLength, std::max(m_procChainLength + 1, triggeringSpell ? triggeringSpell->GetProcChainLength() : 0));
9982
9983 if (disableProcs)
9984 SetCantProc(true);
9985
9986 for (auto const& [procEffectMask, aurApp] : aurasTriggeringProc)
9987 {
9988 if (aurApp->GetRemoveMode())
9989 continue;
9990
9991 aurApp->GetBase()->TriggerProcOnEvent(procEffectMask, aurApp, eventInfo);
9992 }
9993
9994 if (disableProcs)
9995 SetCantProc(false);
9996
9997 m_procChainLength = oldProcChainLength;
9998}
9999
10002{
10003 Unit* owner = GetOwner();
10004 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10005 return;
10006
10007 WorldPackets::Pet::PetActionFeedback petActionFeedback;
10008 petActionFeedback.SpellID = spellId;
10009 petActionFeedback.Response = msg;
10010 owner->ToPlayer()->SendDirectMessage(petActionFeedback.Write());
10011}
10012
10014{
10015 Unit* owner = GetOwner();
10016 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10017 return;
10018
10019 WorldPackets::Pet::PetActionSound petActionSound;
10020 petActionSound.UnitGUID = GetGUID();
10021 petActionSound.Action = pettalk;
10022 owner->ToPlayer()->SendDirectMessage(petActionSound.Write());
10023}
10024
10026{
10027 Unit* owner = GetOwner();
10028 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10029 return;
10030
10032 packet.UnitGUID = guid;
10034 owner->ToPlayer()->SendDirectMessage(packet.Write());
10035}
10036
10038
10040{
10042}
10043
10045{
10046 return IDLE_MOTION_TYPE;
10047}
10048
10050{
10052
10053 // not need send any packets if not in world or not moving
10054 if (!IsInWorld() || movespline->Finalized())
10055 return;
10056
10057 // Update position now since Stop does not start a new movement that can be updated later
10058 if (movespline->HasStarted())
10060 Movement::MoveSplineInit init(this);
10061 init.Stop();
10062}
10063
10064void Unit::PauseMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/, bool forced/* = true*/)
10065{
10066 if (IsInvalidMovementSlot(slot))
10067 return;
10068
10069 if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot)))
10070 movementGenerator->Pause(timer);
10071
10072 if (forced && GetMotionMaster()->GetCurrentSlot() == MovementSlot(slot))
10073 StopMoving();
10074}
10075
10076void Unit::ResumeMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/)
10077{
10078 if (IsInvalidMovementSlot(slot))
10079 return;
10080
10081 if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot)))
10082 movementGenerator->Resume(timer);
10083}
10084
10086{
10088 return
10092}
10093
10095{
10098}
10099
10100void Unit::SetStandState(UnitStandStateType state, uint32 animKitID /* = 0*/)
10101{
10103
10104 if (IsStandState())
10106
10107 if (GetTypeId() == TYPEID_PLAYER)
10108 {
10109 WorldPackets::Misc::StandStateUpdate packet(state, animKitID);
10110 ToPlayer()->SendDirectMessage(packet.Write());
10111 }
10112}
10113
10114void Unit::SetAnimTier(AnimTier animTier, bool notifyClient /*= true*/)
10115{
10117
10118 if (notifyClient)
10119 {
10121 setAnimTier.Unit = GetGUID();
10122 setAnimTier.Tier = AsUnderlyingType(animTier);
10123 SendMessageToSet(setAnimTier.Write(), true);
10124 }
10125}
10126
10128{
10129 uint32 transformId = GetTransformSpell();
10130 if (!transformId)
10131 return false;
10132
10133 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(transformId, GetMap()->GetDifficultyID());
10134 if (!spellInfo)
10135 return false;
10136
10137 return spellInfo->GetSpellSpecific() == SPELL_SPECIFIC_MAGE_POLYMORPH;
10138}
10139
10141{
10143 float scale = GetNativeObjectScale() + CalculatePct(1.0f, scaleAuras);
10144 float scaleMin = GetTypeId() == TYPEID_PLAYER ? 0.1 : 0.01;
10145 SetObjectScale(std::max(scale, scaleMin));
10146}
10147
10148void Unit::SetDisplayId(uint32 displayId, bool setNative /*= false*/)
10149{
10150 float displayScale = DEFAULT_PLAYER_DISPLAY_SCALE;
10151
10152 if (IsCreature() && !IsPet())
10153 if (CreatureModel const* model = ToCreature()->GetCreatureTemplate()->GetModelWithDisplayId(displayId))
10154 displayScale = model->DisplayScale;
10155
10158
10159 if (setNative)
10160 {
10163 }
10164
10165 // Set Gender by ModelInfo
10166 if (CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(displayId))
10167 SetGender(Gender(modelInfo->gender));
10168
10170}
10171
10172void Unit::RestoreDisplayId(bool ignorePositiveAurasPreventingMounting /*= false*/)
10173{
10174 AuraEffect* handledAura = nullptr;
10175 // try to receive model from transform auras
10177 if (!transforms.empty())
10178 {
10179 // iterate over already applied transform auras - from newest to oldest
10180 for (auto i = transforms.begin(); i != transforms.end(); ++i)
10181 {
10182 if (AuraApplication const* aurApp = (*i)->GetBase()->GetApplicationOfTarget(GetGUID()))
10183 {
10184 if (!handledAura)
10185 {
10186 if (!ignorePositiveAurasPreventingMounting)
10187 handledAura = (*i);
10188 else if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate((*i)->GetMiscValue()))
10190 handledAura = (*i);
10191 }
10192 // prefer negative auras
10193 if (!aurApp->IsPositive())
10194 {
10195 handledAura = (*i);
10196 break;
10197 }
10198 }
10199 }
10200 }
10201
10203
10204 // transform aura was found
10205 if (handledAura)
10206 {
10207 handledAura->HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true);
10208 return;
10209 }
10210 // we've found shapeshift
10211 else if (!shapeshiftAura.empty()) // we've found shapeshift
10212 {
10213 // only one such aura possible at a time
10214 if (uint32 modelId = GetModelForForm(GetShapeshiftForm(), shapeshiftAura.front()->GetId()))
10215 {
10216 if (!ignorePositiveAurasPreventingMounting || !IsDisallowedMountForm(0, GetShapeshiftForm(), modelId))
10217 SetDisplayId(modelId);
10218 else
10220 return;
10221 }
10222 }
10223 // no auras found - set modelid to default
10225}
10226
10228{
10229 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
10230 m_reactiveTimer[i] = 0;
10231
10236}
10237
10239{
10240 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
10241 {
10242 ReactiveType reactive = ReactiveType(i);
10243
10244 if (!m_reactiveTimer[reactive])
10245 continue;
10246
10247 if (m_reactiveTimer[reactive] <= p_time)
10248 {
10249 m_reactiveTimer[reactive] = 0;
10250
10251 switch (reactive)
10252 {
10253 case REACTIVE_DEFENSE:
10256 break;
10257 case REACTIVE_DEFENSE_2:
10260 break;
10261 default:
10262 break;
10263 }
10264 }
10265 else
10266 {
10267 m_reactiveTimer[reactive] -= p_time;
10268 }
10269 }
10270}
10271
10272Unit* Unit::SelectNearbyTarget(Unit* exclude, float dist) const
10273{
10274 std::list<Unit*> targets;
10275 Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, dist);
10277 Cell::VisitAllObjects(this, searcher, dist);
10278
10279 // remove current target
10280 if (GetVictim())
10281 targets.remove(GetVictim());
10282
10283 if (exclude)
10284 targets.remove(exclude);
10285
10286 // remove not LoS targets
10287 for (std::list<Unit*>::iterator tIter = targets.begin(); tIter != targets.end();)
10288 {
10289 if (!IsWithinLOSInMap(*tIter) || (*tIter)->IsTotem() || (*tIter)->IsSpiritService() || (*tIter)->IsCritter())
10290 targets.erase(tIter++);
10291 else
10292 ++tIter;
10293 }
10294
10295 // no appropriate targets
10296 if (targets.empty())
10297 return nullptr;
10298
10299 // select random
10301}
10302
10304{
10305 return m_baseAttackSpeed[att];
10306}
10307
10309{
10310 m_baseAttackSpeed[att] = val;
10312}
10313
10315{
10316 switch (att)
10317 {
10318 case BASE_ATTACK:
10319 case OFF_ATTACK:
10321 break;
10322 case RANGED_ATTACK:
10324 break;
10325 default:
10326 break;;
10327 }
10328}
10329
10330void ApplyPercentModFloatVar(float& var, float val, bool apply)
10331{
10332 var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
10333}
10334
10336{
10337 float remainingTimePct = float(m_attackTimer[att]) / (m_baseAttackSpeed[att] * m_modAttackSpeedPct[att]);
10338 if (val > 0.f)
10339 {
10341
10342 if (att == BASE_ATTACK)
10344 else if (att == RANGED_ATTACK)
10346 }
10347 else
10348 {
10350
10351 if (att == BASE_ATTACK)
10353 else if (att == RANGED_ATTACK)
10355 }
10356
10358 m_attackTimer[att] = uint32(m_baseAttackSpeed[att] * m_modAttackSpeedPct[att] * remainingTimePct);
10359}
10360
10362{
10363 if (val > 0.f)
10364 {
10368 }
10369 else
10370 {
10374 }
10375}
10376
10378{
10379 if (Player* player = ToPlayer())
10380 {
10381 if (player->GetGroup())
10382 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS);
10383 }
10384 else if (GetTypeId() == TYPEID_UNIT && IsPet())
10385 {
10386 Pet* pet = ((Pet*)this);
10387 if (pet->isControlled())
10389 }
10390}
10391
10393{
10394 if (apply)
10395 ++m_procDeep;
10396 else
10397 {
10399 --m_procDeep;
10400 }
10401}
10402
10403float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) const
10404{
10405 if (GetTypeId() != TYPEID_PLAYER || (IsInFeralForm() && !normalized))
10406 return GetBaseAttackTime(attType) / 1000.0f;
10407
10408 Item* weapon = ToPlayer()->GetWeaponForAttack(attType, true);
10409 if (!weapon)
10410 return 2.0f;
10411
10412 if (!normalized)
10413 return weapon->GetTemplate()->GetDelay() / 1000.0f;
10414
10415 switch (weapon->GetTemplate()->GetSubClass())
10416 {
10423 return 3.3f;
10431 return 2.4f;
10433 return 1.7f;
10435 return 2.0f;
10436 default:
10437 return weapon->GetTemplate()->GetDelay() / 1000.0f;
10438 }
10439}
10440
10441Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget, uint32 spell_id)
10442{
10443 if (GetTypeId() != TYPEID_PLAYER)
10444 return nullptr;
10445
10446 Pet* pet = new Pet(ToPlayer(), HUNTER_PET);
10447
10448 if (!pet->CreateBaseAtCreature(creatureTarget))
10449 {
10450 delete pet;
10451 return nullptr;
10452 }
10453
10454 uint8 level = creatureTarget->GetLevelForTarget(this) + 5 < GetLevel() ? (GetLevel() - 5) : creatureTarget->GetLevelForTarget(this);
10455
10456 if (!InitTamedPet(pet, level, spell_id))
10457 {
10458 delete pet;
10459 return nullptr;
10460 }
10461
10462 return pet;
10463}
10464
10466{
10467 if (GetTypeId() != TYPEID_PLAYER)
10468 return nullptr;
10469
10470 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creatureEntry);
10471 if (!creatureInfo)
10472 return nullptr;
10473
10474 Pet* pet = new Pet(ToPlayer(), HUNTER_PET);
10475
10476 if (!pet->CreateBaseAtCreatureInfo(creatureInfo, this) || !InitTamedPet(pet, GetLevel(), spell_id))
10477 {
10478 delete pet;
10479 return nullptr;
10480 }
10481
10482 return pet;
10483}
10484
10485bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
10486{
10487 Player* player = ToPlayer();
10488 PetStable& petStable = player->GetOrInitPetStable();
10489 auto freeActiveSlotItr = std::find_if(petStable.ActivePets.begin(), petStable.ActivePets.end(), [](Optional<PetStable::PetInfo> const& petInfo)
10490 {
10491 return !petInfo.has_value();
10492 });
10493
10494 if (freeActiveSlotItr == petStable.ActivePets.end())
10495 return false;
10496
10497 pet->SetCreatorGUID(GetGUID());
10498 pet->SetFaction(GetFaction());
10499 pet->SetCreatedBySpell(spell_id);
10501
10502 if (!pet->InitStatsForLevel(level))
10503 {
10504 TC_LOG_ERROR("entities.unit", "Pet::InitStatsForLevel() failed for creature (Entry: {})!", pet->GetEntry());
10505 return false;
10506 }
10507
10509
10510 pet->GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true);
10511 // this enables pet details window (Shift+P)
10512 pet->InitPetCreateSpells();
10513 //pet->InitLevelupSpellsForLevel();
10514 pet->SetFullHealth();
10515
10516 petStable.SetCurrentActivePetIndex(std::distance(petStable.ActivePets.begin(), freeActiveSlotItr));
10517 pet->FillPetInfo(&freeActiveSlotItr->emplace());
10518 player->AddPetToUpdateFields(**freeActiveSlotItr, PetSaveMode(*petStable.GetCurrentActivePetIndex()), PET_STABLE_ACTIVE);
10519 return true;
10520}
10521
10523{
10525 packet.Percent = percent;
10526 receiver->GetSession()->SendPacket(packet.Write());
10527}
10528
10530{
10531 if (!sAnimKitStore.LookupEntry(animKitId))
10532 {
10533 TC_LOG_ERROR("entities.unit", "Unit::PlayOneShotAnimKitId using invalid AnimKit ID: {}", animKitId);
10534 return;
10535 }
10536
10538 data.Unit = GetGUID();
10539 data.AnimKitID = animKitId;
10540 SendMessageToSet(data.Write(), true);
10541}
10542
10544{
10545 if (_aiAnimKitId == animKitId)
10546 return;
10547
10548 if (animKitId && !sAnimKitStore.LookupEntry(animKitId))
10549 return;
10550
10551 _aiAnimKitId = animKitId;
10552
10554 data.Unit = GetGUID();
10555 data.AnimKitID = animKitId;
10556 SendMessageToSet(data.Write(), true);
10557}
10558
10560{
10561 if (_movementAnimKitId == animKitId)
10562 return;
10563
10564 if (animKitId && !sAnimKitStore.LookupEntry(animKitId))
10565 return;
10566
10567 _movementAnimKitId = animKitId;
10568
10570 data.Unit = GetGUID();
10571 data.AnimKitID = animKitId;
10572 SendMessageToSet(data.Write(), true);
10573}
10574
10576{
10577 if (_meleeAnimKitId == animKitId)
10578 return;
10579
10580 if (animKitId && !sAnimKitStore.LookupEntry(animKitId))
10581 return;
10582
10583 _meleeAnimKitId = animKitId;
10584
10586 data.Unit = GetGUID();
10587 data.AnimKitID = animKitId;
10588 SendMessageToSet(data.Write(), true);
10589}
10590
10591/*static*/ void Unit::Kill(Unit* attacker, Unit* victim, bool durabilityLoss /*= true*/, bool skipSettingDeathState /*= false*/)
10592{
10593 // Prevent killing unit twice (and giving reward from kill twice)
10594 if (!victim->GetHealth())
10595 return;
10596
10597 if (attacker && !attacker->IsInMap(victim))
10598 attacker = nullptr;
10599
10600 // find player: owner of controlled `this` or `this` itself maybe
10601 Player* player = nullptr;
10602 if (attacker)
10603 player = attacker->GetCharmerOrOwnerPlayerOrPlayerItself();
10604
10605 Creature* creature = victim->ToCreature();
10606
10607 bool isRewardAllowed = attacker != victim;
10608 if (creature)
10609 isRewardAllowed = isRewardAllowed && !creature->GetTapList().empty();
10610
10611 std::vector<Player*> tappers;
10612 if (isRewardAllowed && creature)
10613 {
10614 for (ObjectGuid tapperGuid : creature->GetTapList())
10615 if (Player* tapper = ObjectAccessor::GetPlayer(*creature, tapperGuid))
10616 tappers.push_back(tapper);
10617
10618 if (!creature->CanHaveLoot())
10619 isRewardAllowed = false;
10620 }
10621
10622 // Exploit fix
10623 if (creature && creature->IsPet() && creature->GetOwnerGUID().IsPlayer())
10624 isRewardAllowed = false;
10625
10626 // Reward player, his pets, and group/raid members
10627 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
10628 if (isRewardAllowed)
10629 {
10630 std::unordered_set<Group*> groups;
10631 for (Player* tapper : tappers)
10632 {
10633 if (Group* tapperGroup = tapper->GetGroup())
10634 {
10635 if (groups.insert(tapperGroup).second)
10636 {
10638 partyKillLog.Player = player && tapperGroup->IsMember(player->GetGUID()) ? player->GetGUID() : tapper->GetGUID();
10639 partyKillLog.Victim = victim->GetGUID();
10640 partyKillLog.Write();
10641
10642 tapperGroup->BroadcastPacket(partyKillLog.GetRawPacket(), tapperGroup->GetMemberGroup(tapper->GetGUID()) != 0);
10643
10644 if (creature)
10645 tapperGroup->UpdateLooterGuid(creature, true);
10646 }
10647 }
10648 else
10649 {
10651 partyKillLog.Player = tapper->GetGUID();
10652 partyKillLog.Victim = victim->GetGUID();
10653 tapper->SendDirectMessage(partyKillLog.Write());
10654 }
10655 }
10656
10657 // Generate loot before updating looter
10658 if (creature)
10659 {
10660 DungeonEncounterEntry const* dungeonEncounter = nullptr;
10661 if (InstanceScript const* instance = creature->GetInstanceScript())
10662 dungeonEncounter = instance->GetBossDungeonEncounter(creature);
10663
10664 if (creature->GetMap()->IsDungeon())
10665 {
10666 if (dungeonEncounter)
10667 {
10668 creature->m_personalLoot = GenerateDungeonEncounterPersonalLoot(dungeonEncounter->ID, creature->GetLootId(),
10670 creature->GetLootMode(), creature->GetMap()->GetMapDifficulty(), tappers);
10671 }
10672 else if (!tappers.empty())
10673 {
10674 Group* group = !groups.empty() ? *groups.begin() : nullptr;
10675 Player* looter = group ? ASSERT_NOTNULL(ObjectAccessor::GetPlayer(*creature, group->GetLooterGuid())) : tappers[0];
10676
10677 Loot* loot = new Loot(creature->GetMap(), creature->GetGUID(), LOOT_CORPSE, dungeonEncounter ? group : nullptr);
10678
10679 if (uint32 lootid = creature->GetLootId())
10680 loot->FillLoot(lootid, LootTemplates_Creature, looter, dungeonEncounter != nullptr, false, creature->GetLootMode(), ItemBonusMgr::GetContextForPlayer(creature->GetMap()->GetMapDifficulty(), looter));
10681
10682 if (creature->GetLootMode() > 0)
10684
10685 if (group)
10686 loot->NotifyLootList(creature->GetMap());
10687
10688 creature->m_personalLoot[looter->GetGUID()].reset(loot); // trash mob loot is personal, generated with round robin rules
10689
10690 // Update round robin looter only if the creature had loot
10691 if (!loot->isLooted())
10692 for (Group* tapperGroup : groups)
10693 tapperGroup->UpdateLooterGuid(creature);
10694 }
10695 }
10696 else
10697 {
10698 for (Player* tapper : tappers)
10699 {
10700 Loot* loot = new Loot(creature->GetMap(), creature->GetGUID(), LOOT_CORPSE, nullptr);
10701
10702 if (dungeonEncounter)
10703 loot->SetDungeonEncounterId(dungeonEncounter->ID);
10704
10705 if (uint32 lootid = creature->GetLootId())
10706 loot->FillLoot(lootid, LootTemplates_Creature, tapper, true, false, creature->GetLootMode(), ItemBonusMgr::GetContextForPlayer(creature->GetMap()->GetMapDifficulty(), tapper));
10707
10708 if (creature->GetLootMode() > 0)
10710
10711 creature->m_personalLoot[tapper->GetGUID()].reset(loot);
10712 }
10713 }
10714 }
10715
10716 if (Vignettes::VignetteData const* vignette = victim->GetVignette())
10717 {
10718 for (Player* tapper : tappers)
10719 {
10720 if (Quest const* reward = sObjectMgr->GetQuestTemplate(vignette->Data->RewardQuestID))
10721 tapper->RewardQuest(reward, LootItemType::Item, 0, victim, false);
10722
10723 if (vignette->Data->VisibleTrackingQuestID)
10724 tapper->SetRewardedQuest(vignette->Data->VisibleTrackingQuestID);
10725 }
10726 }
10727
10728 KillRewarder(Trinity::IteratorPair(tappers.data(), tappers.data() + tappers.size()), victim, false).Reward();
10729 }
10730
10731 // 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
10732 if (attacker && (attacker->IsPet() || attacker->IsTotem()))
10733 {
10734 // proc only once for victim
10735 if (Unit* owner = attacker->GetOwner())
10737 }
10738
10739 if (!victim->IsCritter())
10740 {
10742
10743 for (Player* tapper : tappers)
10744 if (tapper->IsAtGroupRewardDistance(victim))
10746 }
10747
10748 // Proc auras on death - must be before aura/combat remove
10750
10751 // update get killing blow achievements, must be done before setDeathState to be able to require auras on target
10752 // and before Spirit of Redemption as it also removes auras
10753 if (attacker)
10754 if (Player* killerPlayer = attacker->GetCharmerOrOwnerPlayerOrPlayerItself())
10755 killerPlayer->UpdateCriteria(CriteriaType::DeliveredKillingBlow, 1, 0, 0, victim);
10756
10757 if (!skipSettingDeathState)
10758 {
10759 TC_LOG_DEBUG("entities.unit", "SET JUST_DIED");
10760 victim->setDeathState(JUST_DIED);
10761 }
10762
10763 // Inform pets (if any) when player kills target)
10764 // MUST come after victim->setDeathState(JUST_DIED); or pet next target
10765 // selection will get stuck on same target and break pet react state
10766 for (Player* tapper : tappers)
10767 {
10768 Pet* pet = tapper->GetPet();
10769 if (pet && pet->IsAlive() && pet->isControlled())
10770 {
10771 if (pet->IsAIEnabled())
10772 pet->AI()->KilledUnit(victim);
10773 else
10774 TC_LOG_ERROR("entities.unit", "Pet doesn't have any AI in Unit::Kill(). {}", pet->GetDebugInfo());
10775 }
10776 }
10777
10778 // 10% durability loss on death
10779 if (Player* plrVictim = victim->ToPlayer())
10780 {
10781 // remember victim PvP death for corpse type and corpse reclaim delay
10782 // at original death (not at SpiritOfRedemtionTalent timeout)
10783 plrVictim->SetPvPDeath(player != nullptr);
10784
10785 // only if not player and not controlled by player pet. And not at BG
10786 if ((durabilityLoss && !player && !victim->ToPlayer()->InBattleground()) || (player && sWorld->getBoolConfig(CONFIG_DURABILITY_LOSS_IN_PVP)))
10787 {
10788 double baseLoss = sWorld->getRate(RATE_DURABILITY_LOSS_ON_DEATH);
10789 uint32 loss = uint32(baseLoss - (baseLoss * plrVictim->GetTotalAuraMultiplier(SPELL_AURA_MOD_DURABILITY_LOSS)));
10790 TC_LOG_DEBUG("entities.unit", "We are dead, losing {} percent durability", loss);
10791 // Durability loss is calculated more accurately again for each item in Player::DurabilityLoss
10792 plrVictim->DurabilityLossAll(baseLoss, false);
10793 // durability lost message
10794 plrVictim->SendDurabilityLoss(plrVictim, loss);
10795 }
10796 // Call KilledUnit for creatures
10797 if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())
10798 attacker->ToCreature()->AI()->KilledUnit(victim);
10799
10800 // last damage from non duel opponent or opponent controlled creature
10801 if (plrVictim->duel)
10802 {
10803 plrVictim->duel->Opponent->CombatStopWithPets(true);
10804 plrVictim->CombatStopWithPets(true);
10805 plrVictim->DuelComplete(DUEL_INTERRUPTED);
10806 }
10807 }
10808 else // creature died
10809 {
10810 TC_LOG_DEBUG("entities.unit", "DealDamageNotPlayer");
10811 ASSERT_NODEBUGINFO(creature);
10812
10813 if (!creature->IsPet())
10814 {
10815 // must be after setDeathState which resets dynamic flags
10816 if (!creature->IsFullyLooted())
10818 else
10819 creature->AllLootRemovedFromCorpse();
10820
10822 {
10825 }
10826 }
10827
10828 // Call KilledUnit for creatures, this needs to be called after the lootable flag is set
10829 if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())
10830 attacker->ToCreature()->AI()->KilledUnit(victim);
10831
10832 // Call creature just died function
10833 if (CreatureAI* ai = creature->AI())
10834 {
10835 ai->OnHealthDepleted(attacker, true);
10836 ai->JustDied(attacker);
10837 }
10838
10839 if (TempSummon * summon = creature->ToTempSummon())
10840 {
10841 if (WorldObject * summoner = summon->GetSummoner())
10842 {
10843 if (summoner->ToCreature() && summoner->ToCreature()->IsAIEnabled())
10844 summoner->ToCreature()->AI()->SummonedCreatureDies(creature, attacker);
10845 else if (summoner->ToGameObject() && summoner->ToGameObject()->AI())
10846 summoner->ToGameObject()->AI()->SummonedCreatureDies(creature, attacker);
10847 }
10848 }
10849 }
10850
10851 // outdoor pvp things, do these after setting the death state, else the player activity notify won't work... doh...
10852 // handle player kill only if not suicide (spirit of redemption for example)
10853 if (player && attacker != victim)
10854 {
10855 if (OutdoorPvP* pvp = player->GetOutdoorPvP())
10856 pvp->HandleKill(player, victim);
10857
10858 if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetMap(), player->GetZoneId()))
10859 bf->HandleKill(player, victim);
10860 }
10861
10862 //if (victim->GetTypeId() == TYPEID_PLAYER)
10863 // if (OutdoorPvP* pvp = victim->ToPlayer()->GetOutdoorPvP())
10864 // pvp->HandlePlayerActivityChangedpVictim->ToPlayer();
10865
10866 // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
10867 if (attacker)
10868 {
10869 if (BattlegroundMap* bgMap = victim->GetMap()->ToBattlegroundMap())
10870 {
10871 if (Battleground* bg = bgMap->GetBG())
10872 {
10873 if (Player* playerVictim = victim->ToPlayer())
10874 {
10875 if (player)
10876 bg->HandleKillPlayer(playerVictim, player);
10877 }
10878 else
10879 bg->HandleKillUnit(victim->ToCreature(), attacker);
10880 }
10881 }
10882 }
10883
10884 // achievement stuff
10885 if (attacker && victim->GetTypeId() == TYPEID_PLAYER)
10886 {
10887 if (attacker->GetTypeId() == TYPEID_UNIT)
10889 else if (attacker->GetTypeId() == TYPEID_PLAYER && victim != attacker)
10891 }
10892
10893 // Hook for OnPVPKill Event
10894 if (attacker)
10895 {
10896 if (Player* killerPlr = attacker->ToPlayer())
10897 {
10898 if (Player* killedPlr = victim->ToPlayer())
10899 sScriptMgr->OnPVPKill(killerPlr, killedPlr);
10900 else if (Creature* killedCre = victim->ToCreature())
10901 sScriptMgr->OnCreatureKill(killerPlr, killedCre);
10902 }
10903 else if (Creature* killerCre = attacker->ToCreature())
10904 {
10905 if (Player* killed = victim->ToPlayer())
10906 sScriptMgr->OnPlayerKilledByCreature(killerCre, killed);
10907 }
10908 }
10909}
10910
10912{
10913 if (apply)
10914 {
10915 if (HasUnitState(state))
10916 return;
10917
10918 if (state & UNIT_STATE_CONTROLLED)
10919 CastStop();
10920
10921 AddUnitState(state);
10922 switch (state)
10923 {
10924 case UNIT_STATE_STUNNED:
10925 SetStunned(true);
10926 break;
10927 case UNIT_STATE_ROOT:
10929 SetRooted(true);
10930 break;
10933 {
10935 // SendAutoRepeatCancel ?
10936 SetConfused(true);
10937 }
10938 break;
10939 case UNIT_STATE_FLEEING:
10941 {
10943 // SendAutoRepeatCancel ?
10944 SetFeared(true);
10945 }
10946 break;
10947 default:
10948 break;
10949 }
10950 }
10951 else
10952 {
10953 switch (state)
10954 {
10955 case UNIT_STATE_STUNNED:
10957 return;
10958
10959 ClearUnitState(state);
10960 SetStunned(false);
10961 break;
10962 case UNIT_STATE_ROOT:
10964 return;
10965
10966 ClearUnitState(state);
10968 SetRooted(false);
10969 break;
10972 return;
10973
10974 ClearUnitState(state);
10975 SetConfused(false);
10976 break;
10977 case UNIT_STATE_FLEEING:
10979 return;
10980
10981 ClearUnitState(state);
10982 SetFeared(false);
10983 break;
10984 default:
10985 return;
10986 }
10987
10989 }
10990}
10991
10993{
10994 // Unit States might have been already cleared but auras still present. I need to check with HasAuraType
10996 SetStunned(true);
10997
10999 SetRooted(true);
11000
11002 SetConfused(true);
11003
11005 SetFeared(true);
11006}
11007
11009{
11010 if (apply)
11011 {
11014
11015 StopMoving();
11016
11017 if (GetTypeId() == TYPEID_PLAYER)
11019
11020 SetRooted(true);
11021
11022 CastStop();
11023 }
11024 else
11025 {
11026 if (IsAlive() && GetVictim())
11028
11029 // don't remove UNIT_FLAG_STUNNED for pet when owner is mounted (disabled pet's interface)
11030 Unit* owner = GetCharmerOrOwner();
11031 if (!owner || owner->GetTypeId() != TYPEID_PLAYER || !owner->ToPlayer()->IsMounted())
11033
11034 if (!HasUnitState(UNIT_STATE_ROOT)) // prevent moving if it also has root effect
11035 SetRooted(false);
11036 }
11037}
11038
11039void Unit::SetRooted(bool apply, bool packetOnly /*= false*/)
11040{
11041 if (!packetOnly)
11042 {
11043 if (apply)
11044 {
11045 // MOVEMENTFLAG_ROOT cannot be used in conjunction with MOVEMENTFLAG_MASK_MOVING (tested 3.3.5a)
11046 // this will freeze clients. That's why we remove MOVEMENTFLAG_MASK_MOVING before
11047 // setting MOVEMENTFLAG_ROOT
11050 StopMoving();
11051 }
11052 else
11054 }
11055
11056 static OpcodeServer const rootOpcodeTable[2][2] =
11057 {
11060 };
11061
11062 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved())) // unit controlled by a player.
11063 {
11064 WorldPackets::Movement::MoveSetFlag packet(rootOpcodeTable[apply][1]);
11065 packet.MoverGUID = GetGUID();
11067 playerMover->SendDirectMessage(packet.Write());
11068
11070 moveUpdate.Status = &m_movementInfo;
11071 SendMessageToSet(moveUpdate.Write(), playerMover);
11072 }
11073 else
11074 {
11075 WorldPackets::Movement::MoveSplineSetFlag packet(rootOpcodeTable[apply][0]);
11076 packet.MoverGUID = GetGUID();
11077 SendMessageToSet(packet.Write(), true);
11078 }
11079}
11080
11082{
11083 if (apply)
11084 {
11086
11087 Unit* caster = nullptr;
11089 if (!fearAuras.empty())
11090 caster = ObjectAccessor::GetUnit(*this, fearAuras.front()->GetCasterGUID());
11091 if (!caster)
11092 caster = getAttackerForHelper();
11093 GetMotionMaster()->MoveFleeing(caster, fearAuras.empty() ? Milliseconds(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY)) : 0ms); // caster == NULL processed in MoveFleeing
11095 }
11096 else
11097 {
11099 if (IsAlive())
11100 {
11102 if (Unit const* victim = GetVictim())
11103 SetTarget(victim->GetGUID());
11104 if (!IsPlayer() && !IsInCombat())
11106 }
11107 }
11108
11109 // block / allow control to real player in control (eg charmer)
11110 if (GetTypeId() == TYPEID_PLAYER)
11111 {
11112 if (m_playerMovingMe)
11114 }
11115}
11116
11118{
11119 if (apply)
11120 {
11123 }
11124 else
11125 {
11126 if (IsAlive())
11127 {
11129 if (GetVictim())
11131 }
11132 }
11133
11134 // block / allow control to real player in control (eg charmer)
11135 if (GetTypeId() == TYPEID_PLAYER)
11136 {
11137 if (m_playerMovingMe)
11139 }
11140}
11141
11142bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* aurApp)
11143{
11144 if (!charmer)
11145 return false;
11146
11147 // dismount players when charmed
11148 if (GetTypeId() == TYPEID_PLAYER)
11150
11151 if (charmer->GetTypeId() == TYPEID_PLAYER)
11153
11154 ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
11155 ASSERT((type == CHARM_TYPE_VEHICLE) == (GetVehicleKit() && GetVehicleKit()->IsControllableVehicle()));
11156
11157 TC_LOG_DEBUG("entities.unit", "SetCharmedBy: charmer {}, charmed {}, type {}.", charmer->GetGUID().ToString(), GetGUID().ToString(), uint32(type));
11158
11159 if (this == charmer)
11160 {
11161 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: Unit {} is trying to charm itself!", GetGUID().ToString());
11162 return false;
11163 }
11164
11165 //if (HasUnitState(UNIT_STATE_UNATTACKABLE))
11166 // return false;
11167
11169 {
11170 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} is trying to charm Player {} on transport", charmer->GetGUID().ToString(), GetGUID().ToString());
11171 return false;
11172 }
11173
11174 // Already charmed
11175 if (!GetCharmerGUID().IsEmpty())
11176 {
11177 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} has already been charmed but {} is trying to charm it!", GetGUID().ToString(), charmer->GetGUID().ToString());
11178 return false;
11179 }
11180
11181 CastStop();
11182 AttackStop();
11183
11184 Player* playerCharmer = charmer->ToPlayer();
11185
11186 // Charmer stop charming
11187 if (playerCharmer)
11188 {
11189 playerCharmer->StopCastingCharm();
11190 playerCharmer->StopCastingBindSight();
11191 }
11192
11193 // Charmed stop charming
11194 if (GetTypeId() == TYPEID_PLAYER)
11195 {
11198 }
11199
11200 // StopCastingCharm may remove a possessed pet?
11201 if (!IsInWorld())
11202 {
11203 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} is not in world but {} is trying to charm it!", GetGUID().ToString(), charmer->GetGUID().ToString());
11204 return false;
11205 }
11206
11207 // charm is set by aura, and aura effect remove handler was called during apply handler execution
11208 // prevent undefined behaviour
11209 if (aurApp && aurApp->GetRemoveMode())
11210 return false;
11211
11213 SetFaction(charmer->GetFaction());
11214
11215 // Pause any Idle movement
11216 PauseMovement(0, 0, false);
11217
11218 // Remove any active voluntary movement
11220
11221 // Stop any remaining spline, if no involuntary movement is found
11222 auto criteria = [](MovementGenerator const* movement) -> bool
11223 {
11224 return movement->Priority == MOTION_PRIORITY_HIGHEST;
11225 };
11226 if (!GetMotionMaster()->HasMovementGenerator(criteria))
11227 StopMoving();
11228
11229 // Set charmed
11230 charmer->SetCharm(this, true);
11231
11232 if (Player* player = ToPlayer())
11233 {
11234 if (player->isAFK())
11235 player->ToggleAFK();
11236
11237 player->SetClientControl(this, false);
11238 }
11239
11240 // charm is set by aura, and aura effect remove handler was called during apply handler execution
11241 // prevent undefined behaviour
11242 if (aurApp && aurApp->GetRemoveMode())
11243 {
11244 // properly clean up charm changes up to this point to avoid leaving the unit in partially charmed state
11247 charmer->SetCharm(this, false);
11248 return false;
11249 }
11250
11251 // Pets already have a properly initialized CharmInfo, don't overwrite it.
11252 if (type != CHARM_TYPE_VEHICLE && !GetCharmInfo())
11253 {
11254 InitCharmInfo();
11255 if (type == CHARM_TYPE_POSSESS)
11257 else
11259 }
11260
11261 if (playerCharmer)
11262 {
11263 switch (type)
11264 {
11265 case CHARM_TYPE_VEHICLE:
11267 playerCharmer->SetClientControl(this, true);
11268 playerCharmer->VehicleSpellInitialize();
11269 break;
11270 case CHARM_TYPE_POSSESS:
11273 playerCharmer->SetClientControl(this, true);
11274 playerCharmer->PossessSpellInitialize();
11276 break;
11277 case CHARM_TYPE_CHARM:
11278 if (GetTypeId() == TYPEID_UNIT && charmer->GetClass() == CLASS_WARLOCK)
11279 {
11281 if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
11282 {
11283 // to prevent client crash
11285
11286 // just to enable stat window
11287 if (GetCharmInfo())
11288 GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true);
11289
11290 // if charmed two demons the same session, the 2nd gets the 1st one's name
11292 }
11293 }
11294 playerCharmer->CharmSpellInitialize();
11295 break;
11296 default:
11297 case CHARM_TYPE_CONVERT:
11298 break;
11299 }
11300 }
11301
11303
11304 if ((GetTypeId() != TYPEID_PLAYER) || (charmer->GetTypeId() != TYPEID_PLAYER))
11305 {
11306 // AI will schedule its own change if appropriate
11307 if (UnitAI* ai = GetAI())
11308 ai->OnCharmed(false);
11309 else
11311 }
11312 return true;
11313}
11314
11316{
11317 if (!IsCharmed())
11318 return;
11319
11320 if (charmer)
11321 ASSERT(charmer == GetCharmer());
11322 else
11323 charmer = GetCharmer();
11324
11325 ASSERT(charmer);
11326
11327 CharmType type;
11329 type = CHARM_TYPE_POSSESS;
11330 else if (charmer->IsOnVehicle(this))
11331 type = CHARM_TYPE_VEHICLE;
11332 else
11333 type = CHARM_TYPE_CHARM;
11334
11335 CastStop();
11336 AttackStop();
11337
11338 if (_oldFactionId)
11339 {
11341 _oldFactionId = 0;
11342 }
11343 else
11345
11348
11349 // Vehicle should not attack its passenger after he exists the seat
11350 if (type != CHARM_TYPE_VEHICLE)
11351 LastCharmerGUID = charmer->GetGUID();
11352
11353 ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
11355
11356 charmer->SetCharm(this, false);
11358
11359 Player* playerCharmer = charmer->ToPlayer();
11360 if (playerCharmer)
11361 {
11362 switch (type)
11363 {
11364 case CHARM_TYPE_VEHICLE:
11365 playerCharmer->SetClientControl(this, false);
11366 playerCharmer->SetClientControl(charmer, true);
11368 break;
11369 case CHARM_TYPE_POSSESS:
11371 playerCharmer->SetClientControl(this, false);
11372 playerCharmer->SetClientControl(charmer, true);
11375 break;
11376 case CHARM_TYPE_CHARM:
11377 if (GetTypeId() == TYPEID_UNIT && charmer->GetClass() == CLASS_WARLOCK)
11378 {
11380 if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
11381 {
11382 SetClass(uint8(cinfo->unit_class));
11383 if (GetCharmInfo())
11384 GetCharmInfo()->SetPetNumber(0, true);
11385 else
11386 TC_LOG_ERROR("entities.unit", "Aura::HandleModCharm: {} has a charm aura but no charm info!", GetGUID().ToString());
11387 }
11388 }
11389 break;
11390 case CHARM_TYPE_CONVERT:
11391 break;
11392 }
11393 }
11394
11395 if (Player* player = ToPlayer())
11396 player->SetClientControl(this, true);
11397
11398 if (playerCharmer && this != charmer->GetFirstControlled())
11399 playerCharmer->SendRemoveControlBar();
11400
11401 // a guardian should always have charminfo
11402 if (!IsGuardian())
11404
11405 // reset confused movement for example
11407
11408 if (GetTypeId() != TYPEID_PLAYER || charmer->GetTypeId() == TYPEID_UNIT)
11409 {
11410 if (UnitAI* charmedAI = GetAI())
11411 charmedAI->OnCharmed(false); // AI will potentially schedule a charm ai update
11412 else
11414 }
11415}
11416
11418{
11420 {
11421 SetFaction(GetAuraEffectsByType(SPELL_AURA_MOD_FACTION).front()->GetMiscValue());
11422 return;
11423 }
11424
11425 if (GetTypeId() == TYPEID_PLAYER)
11427 else
11428 {
11430 {
11431 if (Unit* owner = GetOwner())
11432 {
11433 SetFaction(owner->GetFaction());
11434 return;
11435 }
11436 }
11437
11438 if (CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate()) // normal creature
11439 SetFaction(cinfo->faction);
11440 }
11441}
11442
11443bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry, bool loading /*= false*/)
11444{
11445 VehicleEntry const* vehInfo = sVehicleStore.LookupEntry(id);
11446 if (!vehInfo)
11447 return false;
11448
11449 m_vehicleKit = Trinity::make_unique_trackable<Vehicle>(this, vehInfo, creatureEntry);
11450 m_updateFlag.Vehicle = true;
11452
11453 if (!loading)
11455
11456 return true;
11457}
11458
11459void Unit::RemoveVehicleKit(bool onRemoveFromWorld /*= false*/)
11460{
11461 if (!m_vehicleKit)
11462 return;
11463
11464 if (!onRemoveFromWorld)
11466
11468 m_vehicleKit = nullptr;
11469
11470 m_updateFlag.Vehicle = false;
11471 m_unitTypeMask &= ~UNIT_MASK_VEHICLE;
11473}
11474
11475bool Unit::IsOnVehicle(Unit const* vehicle) const
11476{
11477 return m_vehicle && m_vehicle == vehicle->GetVehicleKit();
11478}
11479
11481{
11482 return m_vehicle ? m_vehicle->GetBase() : nullptr;
11483}
11484
11486{
11487 Unit* vehicleRoot = GetVehicleBase();
11488
11489 if (!vehicleRoot)
11490 return nullptr;
11491
11492 for (;;)
11493 {
11494 if (!vehicleRoot->GetVehicleBase())
11495 return vehicleRoot;
11496
11497 vehicleRoot = vehicleRoot->GetVehicleBase();
11498 }
11499}
11500
11502{
11503 if (Unit* veh = GetVehicleBase())
11504 if (Creature* c = veh->ToCreature())
11505 return c;
11506
11507 return nullptr;
11508}
11509
11511{
11512 if (GetVehicle())
11513 return GetVehicleBase()->GetGUID();
11514 if (GetTransport())
11515 return GetTransport()->GetTransportGUID();
11516
11517 return ObjectGuid::Empty;
11518}
11519
11521{
11522 if (Vehicle* veh = GetVehicle())
11523 return veh;
11524 return GetTransport();
11525}
11526
11527bool Unit::IsInPartyWith(Unit const* unit) const
11528{
11529 if (this == unit)
11530 return true;
11531
11532 Unit const* u1 = GetCharmerOrOwnerOrSelf();
11533 Unit const* u2 = unit->GetCharmerOrOwnerOrSelf();
11534 if (u1 == u2)
11535 return true;
11536
11537 if (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
11538 return u1->ToPlayer()->IsInSameGroupWith(u2->ToPlayer());
11539 else if ((u2->GetTypeId() == TYPEID_PLAYER && u1->GetTypeId() == TYPEID_UNIT && u1->ToCreature()->IsTreatedAsRaidUnit()) ||
11541 return true;
11542
11543 return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
11544}
11545
11546bool Unit::IsInRaidWith(Unit const* unit) const
11547{
11548 if (this == unit)
11549 return true;
11550
11551 Unit const* u1 = GetCharmerOrOwnerOrSelf();
11552 Unit const* u2 = unit->GetCharmerOrOwnerOrSelf();
11553 if (u1 == u2)
11554 return true;
11555
11556 if (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
11557 return u1->ToPlayer()->IsInSameRaidWith(u2->ToPlayer());
11558 else if ((u2->GetTypeId() == TYPEID_PLAYER && u1->GetTypeId() == TYPEID_UNIT && u1->ToCreature()->IsTreatedAsRaidUnit()) ||
11560 return true;
11561
11562 return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
11563}
11564
11565void Unit::GetPartyMembers(std::list<Unit*> &TagUnitMap)
11566{
11567 Unit* owner = GetCharmerOrOwnerOrSelf();
11568 Group* group = nullptr;
11569 if (owner->GetTypeId() == TYPEID_PLAYER)
11570 group = owner->ToPlayer()->GetGroup();
11571
11572 if (group)
11573 {
11574 uint8 subgroup = owner->ToPlayer()->GetSubGroup();
11575
11576 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
11577 {
11578 Player* Target = itr->GetSource();
11579
11580 // IsHostileTo check duel and controlled by enemy
11581 if (Target && Target->IsInMap(owner) && Target->GetSubGroup() == subgroup && !IsHostileTo(Target))
11582 {
11583 if (Target->IsAlive())
11584 TagUnitMap.push_back(Target);
11585
11586 if (Guardian* pet = Target->GetGuardianPet())
11587 if (pet->IsAlive())
11588 TagUnitMap.push_back(pet);
11589 }
11590 }
11591 }
11592 else
11593 {
11594 if ((owner == this || IsInMap(owner)) && owner->IsAlive())
11595 TagUnitMap.push_back(owner);
11596 if (Guardian* pet = owner->GetGuardianPet())
11597 if ((pet == this || IsInMap(pet)) && pet->IsAlive())
11598 TagUnitMap.push_back(pet);
11599 }
11600}
11601
11603{
11604 if (FactionTemplateEntry const* entry = GetFactionTemplateEntry())
11605 return entry->IsContestedGuardFaction();
11606
11607 return false;
11608}
11609
11610void Unit::SetPvP(bool state)
11611{
11612 if (state)
11614 else
11616}
11617
11618Aura* Unit::AddAura(uint32 spellId, Unit* target)
11619{
11620 if (!target)
11621 return nullptr;
11622
11623 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID());
11624 if (!spellInfo)
11625 return nullptr;
11626
11627 return AddAura(spellInfo, MAX_EFFECT_MASK, target);
11628}
11629
11630Aura* Unit::AddAura(SpellInfo const* spellInfo, uint32 effMask, Unit* target)
11631{
11632 if (!spellInfo)
11633 return nullptr;
11634
11635 if (!target->IsAlive() && !spellInfo->IsPassive() && !spellInfo->HasAttribute(SPELL_ATTR2_ALLOW_DEAD_TARGET))
11636 return nullptr;
11637
11638 if (target->IsImmunedToSpell(spellInfo, this))
11639 return nullptr;
11640
11641 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
11642 {
11643 if (!(effMask & (1 << spellEffectInfo.EffectIndex)))
11644 continue;
11645
11646 if (target->IsImmunedToSpellEffect(spellInfo, spellEffectInfo, this))
11647 effMask &= ~(1 << spellEffectInfo.EffectIndex);
11648 }
11649
11650 if (!effMask)
11651 return nullptr;
11652
11653 ObjectGuid castId = ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellInfo->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>());
11654 AuraCreateInfo createInfo(castId, spellInfo, GetMap()->GetDifficultyID(), effMask, target);
11655 createInfo.SetCaster(this);
11656
11657 if (Aura* aura = Aura::TryRefreshStackOrCreate(createInfo))
11658 {
11659 aura->ApplyForTargets();
11660 return aura;
11661 }
11662 return nullptr;
11663}
11664
11665void Unit::SetAuraStack(uint32 spellId, Unit* target, uint32 stack)
11666{
11667 Aura* aura = target->GetAura(spellId, GetGUID());
11668 if (!aura)
11669 aura = AddAura(spellId, target);
11670 if (aura && stack)
11671 aura->SetStackAmount(stack);
11672}
11673
11674void Unit::SendPlaySpellVisual(Unit* target, uint32 spellVisualId, uint16 missReason, uint16 reflectStatus, float travelSpeed, bool speedAsTime /*= false*/, float launchDelay /*= 0.0f*/)
11675{
11677 playSpellVisual.Source = GetGUID();
11678 playSpellVisual.Target = target->GetGUID();
11679 playSpellVisual.TargetPosition = target->GetPosition();
11680 playSpellVisual.SpellVisualID = spellVisualId;
11681 playSpellVisual.TravelSpeed = travelSpeed;
11682 playSpellVisual.MissReason = missReason;
11683 playSpellVisual.ReflectStatus = reflectStatus;
11684 playSpellVisual.SpeedAsTime = speedAsTime;
11685 playSpellVisual.LaunchDelay = launchDelay;
11686 SendMessageToSet(playSpellVisual.Write(), true);
11687}
11688
11689void Unit::SendPlaySpellVisual(Position const& targetPosition, uint32 spellVisualId, uint16 missReason, uint16 reflectStatus, float travelSpeed, bool speedAsTime /*= false*/, float launchDelay /*= 0.0f*/)
11690{
11692 playSpellVisual.Source = GetGUID();
11693 playSpellVisual.TargetPosition = targetPosition;
11694 playSpellVisual.SpellVisualID = spellVisualId;
11695 playSpellVisual.TravelSpeed = travelSpeed;
11696 playSpellVisual.MissReason = missReason;
11697 playSpellVisual.ReflectStatus = reflectStatus;
11698 playSpellVisual.SpeedAsTime = speedAsTime;
11699 playSpellVisual.LaunchDelay = launchDelay;
11700 SendMessageToSet(playSpellVisual.Write(), true);
11701}
11702
11704{
11706 cancelSpellVisual.Source = GetGUID();
11707 cancelSpellVisual.SpellVisualID = id;
11708 SendMessageToSet(cancelSpellVisual.Write(), true);
11709}
11710
11711void Unit::SendPlaySpellVisualKit(uint32 id, uint32 type, uint32 duration) const
11712{
11714 playSpellVisualKit.Unit = GetGUID();
11715 playSpellVisualKit.KitRecID = id;
11716 playSpellVisualKit.KitType = type;
11717 playSpellVisualKit.Duration = duration;
11718 SendMessageToSet(playSpellVisualKit.Write(), true);
11719}
11720
11722{
11723 WorldPackets::Spells::CancelSpellVisualKit cancelSpellVisualKit;
11724 cancelSpellVisualKit.Source = GetGUID();
11725 cancelSpellVisualKit.SpellVisualKitID = id;
11726 SendMessageToSet(cancelSpellVisualKit.Write(), true);
11727}
11728
11729void Unit::CancelSpellMissiles(uint32 spellId, bool reverseMissile /*= false*/, bool abortSpell /*= false*/)
11730{
11731 bool hasMissile = false;
11732 if (abortSpell)
11733 {
11734 for (std::pair<uint64 const, BasicEvent*> const& itr : m_Events.GetEvents())
11735 {
11736 if (Spell const* spell = Spell::ExtractSpellFromEvent(itr.second))
11737 {
11738 if (spell->GetSpellInfo()->Id == spellId)
11739 {
11740 itr.second->ScheduleAbort();
11741 hasMissile = true;
11742 }
11743 }
11744 }
11745 }
11746 else
11747 hasMissile = true;
11748
11749 if (hasMissile)
11750 {
11752 packet.OwnerGUID = GetGUID();
11753 packet.SpellID = spellId;
11754 packet.Reverse = reverseMissile;
11755 SendMessageToSet(packet.Write(), false);
11756 }
11757}
11758
11760{
11761 return !IsVehicle() && GetOwnerGUID().IsPlayer();
11762}
11763
11764/*static*/ void Unit::ApplyResilience(Unit const* victim, int32* damage)
11765{
11766 // player mounted on multi-passenger mount is also classified as vehicle
11767 if (victim->IsVehicle() && victim->GetTypeId() != TYPEID_PLAYER)
11768 return;
11769
11770 Unit const* target = nullptr;
11771 if (victim->GetTypeId() == TYPEID_PLAYER)
11772 target = victim;
11773 else // victim->GetTypeId() == TYPEID_UNIT
11774 {
11775 if (Unit* owner = victim->GetOwner())
11776 if (owner->GetTypeId() == TYPEID_PLAYER)
11777 target = owner;
11778 }
11779
11780 if (!target)
11781 return;
11782
11783 *damage -= target->GetDamageReduction(*damage);
11784}
11785
11786int32 Unit::CalculateAOEAvoidance(int32 damage, uint32 schoolMask, bool npcCaster) const
11787{
11788 damage = int32(float(damage) * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, schoolMask));
11789 if (npcCaster)
11791
11792 return damage;
11793}
11794
11795// Melee based spells can be miss, parry or dodge on this step
11796// Crit or block - determined on damage calculation phase! (and can be both in some time)
11797float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, SpellInfo const* spellInfo) const
11798{
11799 if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR7_NO_ATTACK_MISS))
11800 return 0.f;
11801
11802 //calculate miss chance
11803 float missChance = victim->GetUnitMissChance();
11804
11805 // melee attacks while dual wielding have +19% chance to miss
11807 missChance += 19.0f;
11808
11809 // Spellmod from SpellModOp::HitChance
11810 float resistMissChance = 100.0f;
11811 if (spellInfo)
11812 if (Player* modOwner = GetSpellModOwner())
11813 modOwner->ApplySpellMod(spellInfo, SpellModOp::HitChance, resistMissChance);
11814
11815 missChance -= resistMissChance - 100.0f;
11816
11817 if (attType == RANGED_ATTACK)
11818 missChance -= m_modRangedHitChance;
11819 else
11820 missChance -= m_modMeleeHitChance;
11821
11822 // miss chance from auras after calculating skill based miss
11824 if (attType == RANGED_ATTACK)
11826 else
11828
11829 return std::max(missChance, 0.f);
11830}
11831
11833{
11834}
11835
11837{
11838 if (!forced)
11840 else
11841 {
11843 // call MoveInLineOfSight for nearby creatures
11844 Trinity::AIRelocationNotifier notifier(*this);
11845 Cell::VisitAllObjects(this, notifier, GetVisibilityRange());
11846 }
11847}
11848
11849void Unit::SendMoveKnockBack(Player* player, float speedXY, float speedZ, float vcos, float vsin)
11850{
11852 moveKnockBack.MoverGUID = GetGUID();
11853 moveKnockBack.SequenceIndex = m_movementCounter++;
11854 moveKnockBack.Speeds.HorzSpeed = speedXY;
11855 moveKnockBack.Speeds.VertSpeed = speedZ;
11856 moveKnockBack.Direction = Position(vcos, vsin);
11857 player->GetSession()->SendPacket(moveKnockBack.Write());
11858}
11859
11860void Unit::KnockbackFrom(Position const& origin, float speedXY, float speedZ, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
11861{
11862 Player* player = ToPlayer();
11863 if (!player)
11864 {
11865 if (Unit* charmer = GetCharmer())
11866 {
11867 player = charmer->ToPlayer();
11868 if (player && player->GetUnitBeingMoved() != this)
11869 player = nullptr;
11870 }
11871 }
11872
11873 if (!player)
11874 GetMotionMaster()->MoveKnockbackFrom(origin, speedXY, speedZ, spellEffectExtraData);
11875 else
11876 {
11877 float o = GetPosition() == origin ? GetOrientation() + M_PI : origin.GetAbsoluteAngle(this);
11878 if (speedXY < 0)
11879 {
11880 speedXY = -speedXY;
11881 o = o - M_PI;
11882 }
11883
11884 float vcos = std::cos(o);
11885 float vsin = std::sin(o);
11886 SendMoveKnockBack(player, speedXY, -speedZ, vcos, vsin);
11887 }
11888}
11889
11891{
11892 if (Player const* player = ToPlayer())
11893 return player->GetRatingBonusValue(cr);
11894 // Player's pet get resilience from owner
11895 else if (IsPet() && GetOwner())
11896 if (Player* owner = GetOwner()->ToPlayer())
11897 return owner->GetRatingBonusValue(cr);
11898
11899 return 0.0f;
11900}
11901
11902uint32 Unit::GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const
11903{
11904 float percent = std::min(GetCombatRatingReduction(cr) * rate, cap);
11905 return CalculatePct(damage, percent);
11906}
11907
11909{
11910 // Hardcoded cases
11911 switch (spellId)
11912 {
11913 case 7090: // Bear Form
11914 return 29414;
11915 case 35200: // Roc Form
11916 return 4877;
11917 case 24858: // Moonkin Form
11918 {
11919 if (HasAura(114301)) // Glyph of Stars
11920 return 0;
11921 break;
11922 }
11923 default:
11924 break;
11925 }
11926
11927 if (Player const* player = ToPlayer())
11928 {
11930 if (Item* artifact = player->GetItemByGuid(artifactAura->GetCastItemGUID()))
11931 if (ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifact->GetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID)))
11932 if (ShapeshiftForm(artifactAppearance->OverrideShapeshiftFormID) == form)
11933 return artifactAppearance->OverrideShapeshiftDisplayID;
11934
11935 if (ShapeshiftFormModelData const* formModelData = sDB2Manager.GetShapeshiftFormModelData(GetRace(), player->GetNativeGender(), form))
11936 {
11937 bool useRandom = false;
11938 switch (form)
11939 {
11940 case FORM_CAT_FORM: useRandom = HasAura(210333); break; // Glyph of the Feral Chameleon
11941 case FORM_TRAVEL_FORM: useRandom = HasAura(344336); break; // Glyph of the Swift Chameleon
11942 case FORM_AQUATIC_FORM: useRandom = HasAura(344338); break; // Glyph of the Aquatic Chameleon
11943 case FORM_BEAR_FORM: useRandom = HasAura(107059); break; // Glyph of the Ursol Chameleon
11945 case FORM_FLIGHT_FORM: useRandom = HasAura(344342); break; // Glyph of the Aerial Chameleon
11946 default:
11947 break;
11948 }
11949
11950 if (useRandom)
11951 {
11952 std::vector<uint32> displayIds;
11953 displayIds.reserve(formModelData->Choices->size());
11954
11955 for (std::size_t i = 0; i < formModelData->Choices->size(); ++i)
11956 {
11957 if (ChrCustomizationDisplayInfoEntry const* displayInfo = formModelData->Displays[i])
11958 {
11959 ChrCustomizationReqEntry const* choiceReq = sChrCustomizationReqStore.LookupEntry((*formModelData->Choices)[i]->ChrCustomizationReqID);
11960 if (!choiceReq || player->GetSession()->MeetsChrCustomizationReq(choiceReq, Races(GetRace()), Classes(GetClass()), false,
11961 MakeChrCustomizationChoiceRange(player->m_playerData->Customizations)))
11962 displayIds.push_back(displayInfo->DisplayID);
11963 }
11964 }
11965
11966 if (!displayIds.empty())
11968 }
11969 else
11970 {
11971 if (uint32 formChoice = player->GetCustomizationChoice(formModelData->OptionID))
11972 {
11973 auto choiceItr = std::find_if(formModelData->Choices->begin(), formModelData->Choices->end(), [formChoice](ChrCustomizationChoiceEntry const* choice)
11974 {
11975 return choice->ID == formChoice;
11976 });
11977
11978 if (choiceItr != formModelData->Choices->end())
11979 if (ChrCustomizationDisplayInfoEntry const* displayInfo = formModelData->Displays[std::distance(formModelData->Choices->begin(), choiceItr)])
11980 return displayInfo->DisplayID;
11981 }
11982 }
11983 }
11984 switch (form)
11985 {
11986 case FORM_GHOST_WOLF:
11987 {
11988 if (HasAura(58135)) // Glyph of Spectral Wolf
11989 return 60247;
11990 break;
11991 }
11992 default:
11993 break;
11994 }
11995 }
11996
11997 SpellShapeshiftFormEntry const* formEntry = sSpellShapeshiftFormStore.LookupEntry(form);
11998 if (formEntry && formEntry->CreatureDisplayID)
11999 return formEntry->CreatureDisplayID;
12000
12001 return 0;
12002}
12003
12004void Unit::JumpTo(float speedXY, float speedZ, float angle, Optional<Position> dest)
12005{
12006 if (dest)
12007 angle += GetRelativeAngle(*dest);
12008
12009 if (GetTypeId() == TYPEID_UNIT)
12010 GetMotionMaster()->MoveJumpTo(angle, speedXY, speedZ);
12011 else
12012 {
12013 float vcos = std::cos(angle+GetOrientation());
12014 float vsin = std::sin(angle+GetOrientation());
12015 SendMoveKnockBack(ToPlayer(), speedXY, -speedZ, vcos, vsin);
12016 }
12017}
12018
12019void Unit::JumpTo(WorldObject* obj, float speedZ, bool withOrientation)
12020{
12021 float x, y, z;
12022 obj->GetContactPoint(this, x, y, z);
12023 float speedXY = GetExactDist2d(x, y) * 10.0f / speedZ;
12024 GetMotionMaster()->MoveJump(x, y, z, GetAbsoluteAngle(obj), speedXY, speedZ, EVENT_JUMP, withOrientation);
12025}
12026
12027void Unit::HandleSpellClick(Unit* clicker, int8 seatId /*= -1*/)
12028{
12029 bool spellClickHandled = false;
12030 uint32 spellClickEntry = GetVehicleKit() ? GetVehicleKit()->GetCreatureEntry() : GetEntry();
12032
12033 auto clickBounds = sObjectMgr->GetSpellClickInfoMapBounds(spellClickEntry);
12034 for (auto const& clickPair : clickBounds)
12035 {
12037 if (!clickPair.second.IsFitToRequirements(clicker, this))
12038 continue;
12039
12041 if (!sConditionMgr->IsObjectMeetingSpellClickConditions(spellClickEntry, clickPair.second.spellId, clicker, this))
12042 continue;
12043
12044 Unit* caster = (clickPair.second.castFlags & NPC_CLICK_CAST_CASTER_CLICKER) ? clicker : this;
12045 Unit* target = (clickPair.second.castFlags & NPC_CLICK_CAST_TARGET_CLICKER) ? clicker : this;
12046 ObjectGuid origCasterGUID = (clickPair.second.castFlags & NPC_CLICK_CAST_ORIG_CASTER_OWNER) ? GetOwnerGUID() : clicker->GetGUID();
12047
12048 SpellInfo const* spellEntry = sSpellMgr->AssertSpellInfo(clickPair.second.spellId, caster->GetMap()->GetDifficultyID());
12049 // if (!spellEntry) should be checked at npc_spellclick load
12050
12051 if (seatId > -1)
12052 {
12053 uint8 i = 0;
12054 bool valid = false;
12055 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
12056 {
12057 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_CONTROL_VEHICLE)
12058 {
12059 valid = true;
12060 break;
12061 }
12062 ++i;
12063 }
12064
12065 if (!valid)
12066 {
12067 TC_LOG_ERROR("sql.sql", "Spell {} specified in npc_spellclick_spells is not a valid vehicle enter aura!", clickPair.second.spellId);
12068 continue;
12069 }
12070
12071 if (IsInMap(caster))
12072 {
12074 args.OriginalCaster = origCasterGUID;
12075 args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + i), seatId + 1);
12076 caster->CastSpell(target, clickPair.second.spellId, args);
12077 }
12078 else // This can happen during Player::_LoadAuras
12079 {
12080 int32 bp[MAX_SPELL_EFFECTS] = { };
12081 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
12082 bp[spellEffectInfo.EffectIndex] = int32(spellEffectInfo.BasePoints);
12083
12084 bp[i] = seatId;
12085
12086 AuraCreateInfo createInfo(ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), spellEntry, GetMap()->GetDifficultyID(), MAX_EFFECT_MASK, this);
12087 createInfo
12088 .SetCaster(clicker)
12089 .SetBaseAmount(bp)
12090 .SetCasterGUID(origCasterGUID);
12091
12093 }
12094 }
12095 else
12096 {
12097 if (IsInMap(caster))
12098 caster->CastSpell(target, spellEntry->Id, CastSpellExtraArgs().SetOriginalCaster(origCasterGUID));
12099 else
12100 {
12101 AuraCreateInfo createInfo(ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellEntry->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>()), spellEntry, GetMap()->GetDifficultyID(), MAX_EFFECT_MASK, this);
12102 createInfo
12103 .SetCaster(clicker)
12104 .SetCasterGUID(origCasterGUID);
12105
12107 }
12108 }
12109
12110 spellClickHandled = true;
12111 }
12112
12113 Creature* creature = ToCreature();
12114 if (creature && creature->IsAIEnabled())
12115 creature->AI()->OnSpellClick(clicker, spellClickHandled);
12116}
12117
12118void Unit::EnterVehicle(Unit* base, int8 seatId /*= -1*/)
12119{
12121 args.AddSpellMod(SPELLVALUE_BASE_POINT0, seatId + 1);
12123}
12124
12125void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* aurApp)
12126{
12127 // Must be called only from aura handler
12128 ASSERT(aurApp);
12129
12130 if (!IsAlive() || GetVehicleKit() == vehicle || vehicle->GetBase()->IsOnVehicle(this))
12131 return;
12132
12133 if (m_vehicle)
12134 {
12135 if (m_vehicle != vehicle)
12136 {
12137 TC_LOG_DEBUG("entities.vehicle", "EnterVehicle: {} exit {} and enter {}.", GetEntry(), m_vehicle->GetBase()->GetEntry(), vehicle->GetBase()->GetEntry());
12138 ExitVehicle();
12139 }
12140 else if (seatId >= 0 && seatId == GetTransSeat())
12141 return;
12142 else
12143 {
12144 //Exit the current vehicle because unit will reenter in a new seat.
12146 }
12147 }
12148
12149 if (aurApp->GetRemoveMode())
12150 return;
12151
12152 if (Player* player = ToPlayer())
12153 {
12154 if (vehicle->GetBase()->GetTypeId() == TYPEID_PLAYER && player->IsInCombat())
12155 {
12156 vehicle->GetBase()->RemoveAura(const_cast<AuraApplication*>(aurApp));
12157 return;
12158 }
12159
12160 if (vehicle->GetBase()->GetTypeId() == TYPEID_UNIT)
12161 {
12162 // If a player entered a vehicle that is part of a formation, remove it from said formation
12163 if (CreatureGroup* creatureGroup = vehicle->GetBase()->ToCreature()->GetFormation())
12164 creatureGroup->RemoveMember(vehicle->GetBase()->ToCreature());
12165 }
12166 }
12167
12168 ASSERT(!m_vehicle);
12169 (void)vehicle->AddVehiclePassenger(this, seatId);
12170}
12171
12172void Unit::ChangeSeat(int8 seatId, bool next)
12173{
12174 if (!m_vehicle)
12175 return;
12176
12177 // Don't change if current and new seat are identical
12178 if (seatId == GetTransSeat())
12179 return;
12180
12181 SeatMap::const_iterator seat = (seatId < 0 ? m_vehicle->GetNextEmptySeat(GetTransSeat(), next) : m_vehicle->Seats.find(seatId));
12182 // The second part of the check will only return true if seatId >= 0. @Vehicle::GetNextEmptySeat makes sure of that.
12183 if (seat == m_vehicle->Seats.end() || !seat->second.IsEmpty())
12184 return;
12185
12186 AuraEffect* rideVehicleEffect = nullptr;
12188 for (AuraEffectList::const_iterator itr = vehicleAuras.begin(); itr != vehicleAuras.end(); ++itr)
12189 {
12190 if ((*itr)->GetCasterGUID() != GetGUID())
12191 continue;
12192
12193 // Make sure there is only one ride vehicle aura on target cast by the unit changing seat
12194 ASSERT(!rideVehicleEffect);
12195 rideVehicleEffect = *itr;
12196 }
12197
12198 // Unit riding a vehicle must always have control vehicle aura on target
12199 ASSERT(rideVehicleEffect);
12200
12201 rideVehicleEffect->ChangeAmount(seat->first + 1);
12202}
12203
12204void Unit::ExitVehicle(Position const* /*exitPosition*/)
12205{
12207 if (!m_vehicle)
12208 return;
12209
12214 /*_ExitVehicle(exitPosition);*/
12221}
12222
12223void Unit::_ExitVehicle(Position const* exitPosition)
12224{
12228 if (!m_vehicle)
12229 return;
12230
12231 // This should be done before dismiss, because there may be some aura removal
12233 Vehicle* vehicle = m_vehicle->RemovePassenger(this);
12234
12235 if (!vehicle)
12236 {
12237 TC_LOG_ERROR("entities.vehicle", "RemovePassenger() couldn't remove current unit from vehicle. Debug info: {}", GetDebugInfo());
12238 return;
12239 }
12240
12241 Player* player = ToPlayer();
12242
12243 // If the player is on mounted duel and exits the mount, he should immediatly lose the duel
12244 if (player && player->duel && player->duel->IsMounted)
12245 player->DuelComplete(DUEL_FLED);
12246
12247 SetControlled(false, UNIT_STATE_ROOT); // SMSG_MOVE_FORCE_UNROOT, ~MOVEMENTFLAG_ROOT
12248
12250
12251 if (player)
12252 player->SetFallInformation(0, GetPositionZ());
12253
12254 Position pos;
12255 // If we ask for a specific exit position, use that one. Otherwise allow scripts to modify it
12256 if (exitPosition)
12257 pos = *exitPosition;
12258 else
12259 {
12260 // Set exit position to vehicle position and use the current orientation
12261 pos = vehicle->GetBase()->GetPosition();
12263
12264 // Change exit position based on seat entry addon data
12265 if (seatAddon)
12266 {
12268 pos.RelocateOffset({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
12270 pos.Relocate({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
12271 }
12272 }
12273
12274 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this, vehicleCollisionHeight = vehicle->GetBase()->GetCollisionHeight()](Movement::MoveSplineInit& init)
12275 {
12276 float height = pos.GetPositionZ() + vehicleCollisionHeight;
12277
12278 // Creatures without inhabit type air should begin falling after exiting the vehicle
12279 if (GetTypeId() == TYPEID_UNIT && !CanFly() && height > GetMap()->GetWaterOrGroundLevel(GetPhaseShift(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() + vehicleCollisionHeight, &height))
12280 init.SetFall();
12281
12282 init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), height, false);
12283 init.SetFacing(pos.GetOrientation());
12284 init.SetTransportExit();
12285 };
12287
12288 if (player)
12290
12291 if (vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION) && vehicle->GetBase()->GetTypeId() == TYPEID_UNIT)
12292 if (((Minion*)vehicle->GetBase())->GetOwner() == this)
12293 vehicle->GetBase()->ToCreature()->DespawnOrUnsummon(vehicle->GetDespawnDelay());
12294
12296 {
12297 // Vehicle just died, we die too
12298 if (vehicle->GetBase()->getDeathState() == JUST_DIED)
12300 // If for other reason we as minion are exiting the vehicle (ejected, master dismounted) - unsummon
12301 else
12302 ToTempSummon()->UnSummon(2000); // Approximation
12303 }
12304
12306}
12307
12309{
12311}
12312
12313bool Unit::CanSwim() const
12314{
12315 // 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
12317 return false;
12318 if (HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) // is player
12319 return true;
12321 return false;
12323 return true;
12325}
12326
12327void Unit::NearTeleportTo(Position const& pos, bool casting /*= false*/)
12328{
12329 DisableSpline();
12330 if (GetTypeId() == TYPEID_PLAYER)
12331 {
12332 WorldLocation target(GetMapId(), pos);
12334 }
12335 else
12336 {
12337 SendTeleportPacket(pos);
12338 UpdatePosition(pos, true);
12340 }
12341}
12342
12344{
12345 // SMSG_MOVE_UPDATE_TELEPORT is sent to nearby players to signal the teleport
12346 // SMSG_MOVE_TELEPORT is sent to self in order to trigger CMSG_MOVE_TELEPORT_ACK and update the position server side
12347
12349 moveUpdateTeleport.Status = &m_movementInfo;
12350 if (_movementForces)
12351 moveUpdateTeleport.MovementForces = _movementForces->GetForces();
12352 Unit* broadcastSource = this;
12353
12354 // should this really be the unit _being_ moved? not the unit doing the moving?
12355 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
12356 {
12357 float x, y, z, o;
12358 pos.GetPosition(x, y, z, o);
12359 if (TransportBase* transportBase = GetDirectTransport())
12360 transportBase->CalculatePassengerOffset(x, y, z, &o);
12361
12363 moveTeleport.MoverGUID = GetGUID();
12364 moveTeleport.Pos = Position(x, y, z);
12365 moveTeleport.TransportGUID = GetTransGUID();
12366 moveTeleport.Facing = o;
12367 moveTeleport.SequenceIndex = m_movementCounter++;
12368 playerMover->SendDirectMessage(moveTeleport.Write());
12369
12370 broadcastSource = playerMover;
12371 }
12372 else
12373 {
12374 // This is the only packet sent for creatures which contains MovementInfo structure
12375 // we do not update m_movementInfo for creatures so it needs to be done manually here
12376 moveUpdateTeleport.Status->guid = GetGUID();
12377 moveUpdateTeleport.Status->pos.Relocate(pos);
12378 moveUpdateTeleport.Status->time = getMSTime();
12379 if (TransportBase* transportBase = GetDirectTransport())
12380 {
12381 float tx, ty, tz, to;
12382 pos.GetPosition(tx, ty, tz, to);
12383 transportBase->CalculatePassengerOffset(tx, ty, tz, &to);
12384 moveUpdateTeleport.Status->transport.pos.Relocate(tx, ty, tz, to);
12385 }
12386 }
12387
12388 // Broadcast the packet to everyone except self.
12389 broadcastSource->SendMessageToSet(moveUpdateTeleport.Write(), false);
12390}
12391
12392bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool teleport)
12393{
12394 // prevent crash when a bad coord is sent by the client
12395 if (!Trinity::IsValidMapCoord(x, y, z, orientation))
12396 {
12397 TC_LOG_DEBUG("entities.unit", "Unit::UpdatePosition({}, {}, {}) .. bad coordinates!", x, y, z);
12398 return false;
12399 }
12400
12401 // Check if angular distance changed
12402 bool const turn = G3D::fuzzyGt(M_PI - fabs(fabs(GetOrientation() - orientation) - M_PI), 0.0f);
12403
12404 // G3D::fuzzyEq won't help here, in some cases magnitudes differ by a little more than G3D::eps, but should be considered equal
12405 bool const relocated = (teleport ||
12406 std::fabs(GetPositionX() - x) > 0.001f ||
12407 std::fabs(GetPositionY() - y) > 0.001f ||
12408 std::fabs(GetPositionZ() - z) > 0.001f);
12409
12410 if (relocated)
12411 {
12412 // move and update visible state if need
12413 if (GetTypeId() == TYPEID_PLAYER)
12414 GetMap()->PlayerRelocation(ToPlayer(), x, y, z, orientation);
12415 else
12416 GetMap()->CreatureRelocation(ToCreature(), x, y, z, orientation);
12417 }
12418 else if (turn)
12419 UpdateOrientation(orientation);
12420
12421 _positionUpdateInfo.Relocated = relocated;
12423
12424 if (IsFalling())
12426
12427 bool isInWater = IsInWater();
12428 if (!IsFalling() || isInWater || IsFlying())
12430
12431 if (isInWater)
12433
12434 // TODO: on heartbeat
12435 if (m_vignette)
12437
12438 return (relocated || turn);
12439}
12440
12441bool Unit::UpdatePosition(Position const& pos, bool teleport)
12442{
12443 return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport);
12444}
12445
12447void Unit::UpdateOrientation(float orientation)
12448{
12449 SetOrientation(orientation);
12450 if (IsVehicle())
12452}
12453
12455void Unit::UpdateHeight(float newZ)
12456{
12458 if (IsVehicle())
12460}
12461
12462// baseRage means damage taken when attacker = false
12464{
12465 float addRage = baseRage;
12466
12467 // talent who gave more rage on attack
12469
12470 addRage *= sWorld->getRate(RATE_POWER_RAGE_INCOME);
12471
12472 ModifyPower(POWER_RAGE, uint32(addRage * 10));
12473}
12474
12476{
12477 if (Unit* victim = GetVictim())
12478 {
12479 if (victim->GetFactionTemplateEntry()->Faction == faction_id)
12480 {
12481 AttackStop();
12482 if (IsNonMeleeSpellCast(false))
12484
12485 // melee and ranged forced attack cancel
12486 if (GetTypeId() == TYPEID_PLAYER)
12488 }
12489 }
12490
12491 AttackerSet const& attackers = getAttackers();
12492 for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end();)
12493 {
12494 if ((*itr)->GetFactionTemplateEntry()->Faction == faction_id)
12495 {
12496 (*itr)->AttackStop();
12497 itr = attackers.begin();
12498 }
12499 else
12500 ++itr;
12501 }
12502
12503 std::vector<CombatReference*> refsToEnd;
12504 for (auto const& pair : m_combatManager.GetPvECombatRefs())
12505 if (pair.second->GetOther(this)->GetFactionTemplateEntry()->Faction == faction_id)
12506 refsToEnd.push_back(pair.second);
12507 for (CombatReference* ref : refsToEnd)
12508 ref->EndCombat();
12509
12510 for (Unit* minion : m_Controlled)
12511 minion->StopAttackFaction(faction_id);
12512}
12513
12515{
12516 TC_LOG_ERROR("entities.unit", "Unit::OutDebugInfo");
12517 TC_LOG_DEBUG("entities.unit", "{} name {}", GetGUID().ToString(), GetName());
12518 TC_LOG_DEBUG("entities.unit", "Owner {}, Minion {}, Charmer {}, Charmed {}", GetOwnerGUID().ToString(), GetMinionGUID().ToString(), GetCharmerGUID().ToString(), GetCharmedGUID().ToString());
12519 TC_LOG_DEBUG("entities.unit", "In world {}, unit type mask {}", (uint32)(IsInWorld() ? 1 : 0), m_unitTypeMask);
12520 if (IsInWorld())
12521 TC_LOG_DEBUG("entities.unit", "Mapid {}", GetMapId());
12522
12523 std::ostringstream o;
12524 o << "Summon Slot: ";
12525 for (uint32 i = 0; i < MAX_SUMMON_SLOT; ++i)
12526 o << m_SummonSlot[i].ToString() << ", ";
12527
12528 TC_LOG_DEBUG("entities.unit", "{}", o.str());
12529 o.str("");
12530
12531 o << "Controlled List: ";
12532 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
12533 o << (*itr)->GetGUID().ToString() << ", ";
12534 TC_LOG_DEBUG("entities.unit", "{}", o.str());
12535 o.str("");
12536
12537 o << "Aura List: ";
12538 for (AuraApplicationMap::const_iterator itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
12539 o << itr->first << ", ";
12540 TC_LOG_DEBUG("entities.unit", "{}", o.str());
12541 o.str("");
12542
12543 if (IsVehicle())
12544 {
12545 o << "Passenger List: ";
12546 for (SeatMap::iterator itr = GetVehicleKit()->Seats.begin(); itr != GetVehicleKit()->Seats.end(); ++itr)
12547 if (Unit* passenger = ObjectAccessor::GetUnit(*GetVehicleBase(), itr->second.Passenger.Guid))
12548 o << passenger->GetGUID().ToString() << ", ";
12549 TC_LOG_DEBUG("entities.unit", "{}", o.str());
12550 }
12551
12552 if (GetVehicle())
12553 TC_LOG_DEBUG("entities.unit", "On vehicle {}.", GetVehicleBase()->GetEntry());
12554}
12555
12557{
12559 breakTarget.UnitGUID = GetGUID();
12560 SendMessageToSet(breakTarget.Write(), false);
12561}
12562
12564{
12565 Optional<int32> resist;
12566 for (int32 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
12567 {
12568 int32 schoolResistance = GetResistance(SpellSchools(i));
12569 if (mask & (1 << i) && (!resist || *resist > schoolResistance))
12570 resist = schoolResistance;
12571 }
12572
12573 return resist.value_or(0);
12574}
12575
12577{
12578 _isCommandAttack = val;
12579}
12580
12582{
12583 return _isCommandAttack;
12584}
12585
12587{
12588 _isCommandFollow = val;
12589}
12590
12592{
12593 return _isCommandFollow;
12594}
12595
12597{
12599 G3D::Vector3 stayPos = _unit->movespline->FinalDestination();
12600
12601 if (_unit->movespline->onTransport)
12602 if (TransportBase* transport = _unit->GetDirectTransport())
12603 transport->CalculatePassengerPosition(stayPos.x, stayPos.y, stayPos.z);
12604
12605 _stayX = stayPos.x;
12606 _stayY = stayPos.y;
12607 _stayZ = stayPos.z;
12608}
12609
12610void CharmInfo::GetStayPosition(float &x, float &y, float &z)
12611{
12612 x = _stayX;
12613 y = _stayY;
12614 z = _stayZ;
12615}
12616
12618{
12619 _isAtStay = val;
12620}
12621
12623{
12624 return _isAtStay;
12625}
12626
12628{
12629 _isFollowing = val;
12630}
12631
12633{
12634 return _isFollowing;
12635}
12636
12638{
12639 _isReturning = val;
12640}
12641
12643{
12644 return _isReturning;
12645}
12646
12648{
12651}
12652
12653void Unit::SetFacingTo(float ori, bool force)
12654{
12655 // do not face when already moving
12656 if (!force && (!IsStopped() || !movespline->Finalized()))
12657 return;
12658
12659 Movement::MoveSplineInit init(this);
12660 init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false);
12661 if (GetTransport())
12662 init.DisableTransportPathTransformations(); // It makes no sense to target global orientation
12663 init.SetFacing(ori);
12664
12665 //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_PRIORITY_HIGHEST);
12667 if (Creature* creature = ToCreature())
12668 creature->AI()->MovementInform(EFFECT_MOTION_TYPE, EVENT_FACE);
12669}
12670
12671void Unit::SetFacingToObject(WorldObject const* object, bool force)
12672{
12673 // do not face when already moving
12674 if (!force && (!IsStopped() || !movespline->Finalized()))
12675 return;
12676
12678 Movement::MoveSplineInit init(this);
12679 init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false);
12680 init.SetFacing(GetAbsoluteAngle(object)); // when on transport, GetAbsoluteAngle will still return global coordinates (and angle) that needs transforming
12681
12682 //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_PRIORITY_HIGHEST);
12684 if (Creature* creature = ToCreature())
12685 creature->AI()->MovementInform(EFFECT_MOTION_TYPE, EVENT_FACE);
12686}
12687
12688void Unit::SetFacingToPoint(Position const& point, bool force)
12689{
12690 // do not face when already moving
12691 if (!force && (!IsStopped() || !movespline->Finalized()))
12692 return;
12693
12695 Movement::MoveSplineInit init(this);
12696 init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false);
12697 if (GetTransport())
12698 init.DisableTransportPathTransformations(); // It makes no sense to target global orientation
12699 init.SetFacing(point.GetPositionX(), point.GetPositionY(), point.GetPositionZ());
12700
12701 //GetMotionMaster()->LaunchMoveSpline(std::move(init), EVENT_FACE, MOTION_PRIORITY_HIGHEST);
12703 if (Creature* creature = ToCreature())
12704 creature->AI()->MovementInform(EFFECT_MOTION_TYPE, EVENT_FACE);
12705}
12706
12707bool Unit::SetWalk(bool enable)
12708{
12709 if (enable == IsWalking())
12710 return false;
12711
12712 if (enable)
12714 else
12716
12718
12719 WorldPackets::Movement::MoveSplineSetFlag packet(walkModeTable[enable]);
12720 packet.MoverGUID = GetGUID();
12721 SendMessageToSet(packet.Write(), true);
12722 return true;
12723}
12724
12725bool Unit::SetDisableGravity(bool disable, bool updateAnimTier /*= true*/)
12726{
12727 if (disable == IsGravityDisabled())
12728 return false;
12729
12730 if (disable)
12731 {
12734 }
12735 else
12737
12738 static OpcodeServer const gravityOpcodeTable[2][2] =
12739 {
12742 };
12743
12744 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
12745 {
12746 WorldPackets::Movement::MoveSetFlag packet(gravityOpcodeTable[disable][1]);
12747 packet.MoverGUID = GetGUID();
12749 playerMover->SendDirectMessage(packet.Write());
12750
12752 moveUpdate.Status = &m_movementInfo;
12753 SendMessageToSet(moveUpdate.Write(), playerMover);
12754 }
12755 else
12756 {
12757 WorldPackets::Movement::MoveSplineSetFlag packet(gravityOpcodeTable[disable][0]);
12758 packet.MoverGUID = GetGUID();
12759 SendMessageToSet(packet.Write(), true);
12760 }
12761
12762 if (IsCreature() && updateAnimTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT))
12763 {
12764 if (IsGravityDisabled())
12766 else if (IsHovering())
12768 else
12770 }
12771
12772 if (IsAlive())
12773 {
12774 if (IsGravityDisabled() || IsHovering())
12775 SetPlayHoverAnim(true);
12776 else
12777 SetPlayHoverAnim(false);
12778 }
12779 else if (IsPlayer()) // To update player who dies while flying/hovering
12780 SetPlayHoverAnim(false, false);
12781
12782 return true;
12783}
12784
12785bool Unit::SetFall(bool enable)
12786{
12788 return false;
12789
12790 if (enable)
12791 {
12794 }
12795 else
12797
12798 return true;
12799}
12800
12801bool Unit::SetSwim(bool enable)
12802{
12804 return false;
12805
12806 if (enable)
12808 else
12810
12811 static OpcodeServer const swimOpcodeTable[2] = { SMSG_MOVE_SPLINE_STOP_SWIM, SMSG_MOVE_SPLINE_START_SWIM};
12812
12813 WorldPackets::Movement::MoveSplineSetFlag packet(swimOpcodeTable[enable]);
12814 packet.MoverGUID = GetGUID();
12815 SendMessageToSet(packet.Write(), true);
12816
12817 return true;
12818}
12819
12820bool Unit::SetCanFly(bool enable)
12821{
12823 return false;
12824
12825 if (enable)
12826 {
12829 }
12830 else
12832
12833 static OpcodeServer const flyOpcodeTable[2][2] =
12834 {
12837 };
12838
12839 if (!enable && GetTypeId() == TYPEID_PLAYER)
12841
12842 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
12843 {
12844 WorldPackets::Movement::MoveSetFlag packet(flyOpcodeTable[enable][1]);
12845 packet.MoverGUID = GetGUID();
12847 playerMover->SendDirectMessage(packet.Write());
12848
12850 moveUpdate.Status = &m_movementInfo;
12851 SendMessageToSet(moveUpdate.Write(), playerMover);
12852 }
12853 else
12854 {
12855 WorldPackets::Movement::MoveSplineSetFlag packet(flyOpcodeTable[enable][0]);
12856 packet.MoverGUID = GetGUID();
12857 SendMessageToSet(packet.Write(), true);
12858 }
12859
12860 return true;
12861}
12862
12863bool Unit::SetWaterWalking(bool enable)
12864{
12866 return false;
12867
12868 if (enable)
12870 else
12872
12873 static OpcodeServer const waterWalkingOpcodeTable[2][2] =
12874 {
12877 };
12878
12879 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
12880 {
12881 WorldPackets::Movement::MoveSetFlag packet(waterWalkingOpcodeTable[enable][1]);
12882 packet.MoverGUID = GetGUID();
12884 playerMover->SendDirectMessage(packet.Write());
12885
12887 moveUpdate.Status = &m_movementInfo;
12888 SendMessageToSet(moveUpdate.Write(), playerMover);
12889 }
12890 else
12891 {
12892 WorldPackets::Movement::MoveSplineSetFlag packet(waterWalkingOpcodeTable[enable][0]);
12893 packet.MoverGUID = GetGUID();
12894 SendMessageToSet(packet.Write(), true);
12895 }
12896
12897 return true;
12898}
12899
12900bool Unit::SetFeatherFall(bool enable)
12901{
12902 // Temporarily disabled for short lived auras that unapply before client had time to ACK applying
12903 //if (enable == HasUnitMovementFlag(MOVEMENTFLAG_FALLING_SLOW))
12904 // return false;
12905
12906 if (enable)
12908 else
12910
12911 static OpcodeServer const featherFallOpcodeTable[2][2] =
12912 {
12915 };
12916
12917 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
12918 {
12919 WorldPackets::Movement::MoveSetFlag packet(featherFallOpcodeTable[enable][1]);
12920 packet.MoverGUID = GetGUID();
12922 playerMover->SendDirectMessage(packet.Write());
12923
12925 moveUpdate.Status = &m_movementInfo;
12926 SendMessageToSet(moveUpdate.Write(), playerMover);
12927 }
12928 else
12929 {
12930 WorldPackets::Movement::MoveSplineSetFlag packet(featherFallOpcodeTable[enable][0]);
12931 packet.MoverGUID = GetGUID();
12932 SendMessageToSet(packet.Write(), true);
12933 }
12934
12935 return true;
12936}
12937
12938bool Unit::SetHover(bool enable, bool updateAnimTier /*= true*/)
12939{
12941 return false;
12942
12943 float hoverHeight = m_unitData->HoverHeight;
12944
12945 if (enable)
12946 {
12949 if (hoverHeight && GetPositionZ() - GetFloorZ() < hoverHeight)
12950 UpdateHeight(GetPositionZ() + hoverHeight);
12951 }
12952 else
12953 {
12956 if (hoverHeight && (!isDying() || GetTypeId() != TYPEID_UNIT))
12957 {
12958 float newZ = std::max<float>(GetFloorZ(), GetPositionZ() - hoverHeight);
12960 UpdateHeight(newZ);
12961 }
12962 }
12963
12964 static OpcodeServer const hoverOpcodeTable[2][2] =
12965 {
12968 };
12969
12970 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
12971 {
12972 WorldPackets::Movement::MoveSetFlag packet(hoverOpcodeTable[enable][1]);
12973 packet.MoverGUID = GetGUID();
12975 playerMover->SendDirectMessage(packet.Write());
12976
12978 moveUpdate.Status = &m_movementInfo;
12979 SendMessageToSet(moveUpdate.Write(), playerMover);
12980 }
12981 else
12982 {
12983 WorldPackets::Movement::MoveSplineSetFlag packet(hoverOpcodeTable[enable][0]);
12984 packet.MoverGUID = GetGUID();
12985 SendMessageToSet(packet.Write(), true);
12986 }
12987
12988 if (IsCreature() && updateAnimTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT))
12989 {
12990 if (IsGravityDisabled())
12992 else if (IsHovering())
12994 else
12996 }
12997
12998 if (IsAlive())
12999 {
13000 if (IsGravityDisabled() || IsHovering())
13001 SetPlayHoverAnim(true);
13002 else
13003 SetPlayHoverAnim(false);
13004 }
13005 else if (IsPlayer()) // To update player who dies while flying/hovering
13006 SetPlayHoverAnim(false, false);
13007
13008 return true;
13009}
13010
13011bool Unit::SetCollision(bool disable)
13012{
13014 return false;
13015
13016 if (disable)
13018 else
13020
13021 static OpcodeServer const collisionOpcodeTable[2][2] =
13022 {
13025 };
13026
13027 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13028 {
13029 WorldPackets::Movement::MoveSetFlag packet(collisionOpcodeTable[disable][1]);
13030 packet.MoverGUID = GetGUID();
13032 playerMover->SendDirectMessage(packet.Write());
13033
13035 moveUpdate.Status = &m_movementInfo;
13036 SendMessageToSet(moveUpdate.Write(), playerMover);
13037 }
13038 else
13039 {
13040 WorldPackets::Movement::MoveSplineSetFlag packet(collisionOpcodeTable[disable][0]);
13041 packet.MoverGUID = GetGUID();
13042 SendMessageToSet(packet.Write(), true);
13043 }
13044
13045 return true;
13046}
13047
13049{
13050 if (GetTypeId() != TYPEID_PLAYER)
13051 return false;
13052
13054 return false;
13055
13056 if (enable)
13058 else
13060
13061 static OpcodeServer const swimToFlyTransOpcodeTable[2] =
13062 {
13065 };
13066
13067 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13068 {
13069 WorldPackets::Movement::MoveSetFlag packet(swimToFlyTransOpcodeTable[enable]);
13070 packet.MoverGUID = GetGUID();
13072 playerMover->SendDirectMessage(packet.Write());
13073
13075 moveUpdate.Status = &m_movementInfo;
13076 SendMessageToSet(moveUpdate.Write(), playerMover);
13077 }
13078
13079 return true;
13080}
13081
13083{
13084 // Temporarily disabled for short lived auras that unapply before client had time to ACK applying
13085 //if (enable == HasExtraUnitMovementFlag(MOVEMENTFLAG2_CAN_TURN_WHILE_FALLING))
13086 // return false;
13087
13088 if (enable)
13090 else
13092
13093 static OpcodeServer const canTurnWhileFallingOpcodeTable[2] =
13094 {
13097 };
13098
13099 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13100 {
13101 WorldPackets::Movement::MoveSetFlag packet(canTurnWhileFallingOpcodeTable[enable]);
13102 packet.MoverGUID = GetGUID();
13104 playerMover->SendDirectMessage(packet.Write());
13105
13107 moveUpdate.Status = &m_movementInfo;
13108 SendMessageToSet(moveUpdate.Write(), playerMover);
13109 }
13110
13111 return true;
13112}
13113
13114bool Unit::SetCanDoubleJump(bool enable)
13115{
13117 return false;
13118
13119 if (enable)
13121 else
13123
13124 static OpcodeServer const doubleJumpOpcodeTable[2] =
13125 {
13128 };
13129
13130 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13131 {
13132 WorldPackets::Movement::MoveSetFlag packet(doubleJumpOpcodeTable[enable]);
13133 packet.MoverGUID = GetGUID();
13135 playerMover->SendDirectMessage(packet.Write());
13136
13138 moveUpdate.Status = &m_movementInfo;
13139 SendMessageToSet(moveUpdate.Write(), playerMover);
13140 }
13141
13142 return true;
13143}
13144
13145bool Unit::SetDisableInertia(bool disable)
13146{
13148 return false;
13149
13150 if (disable)
13152 else
13154
13155 static OpcodeServer const disableInertiaOpcodeTable[2] =
13156 {
13159 };
13160
13161 if (Player* playerMover = Unit::ToPlayer(GetUnitBeingMoved()))
13162 {
13163 WorldPackets::Movement::MoveSetFlag packet(disableInertiaOpcodeTable[disable]);
13164 packet.MoverGUID = GetGUID();
13166 playerMover->SendDirectMessage(packet.Write());
13167
13169 moveUpdate.Status = &m_movementInfo;
13170 SendMessageToSet(moveUpdate.Write(), playerMover);
13171 }
13172
13173 return true;
13174}
13175
13177{
13178 if (Player* player = ToPlayer())
13179 {
13181 moveSetVehicleRec.MoverGUID = GetGUID();
13182 moveSetVehicleRec.SequenceIndex = m_movementCounter++;
13183 moveSetVehicleRec.VehicleRecID = vehicleId;
13184 player->SendDirectMessage(moveSetVehicleRec.Write());
13185 }
13186
13188 setVehicleRec.VehicleGUID = GetGUID();
13189 setVehicleRec.VehicleRecID = vehicleId;
13190 SendMessageToSet(setVehicleRec.Write(), true);
13191}
13192
13193void Unit::ApplyMovementForce(ObjectGuid id, Position origin, float magnitude, MovementForceType type, Position direction /*= {}*/, ObjectGuid transportGuid /*= ObjectGuid::Empty*/)
13194{
13195 if (!_movementForces)
13196 _movementForces = std::make_unique<MovementForces>();
13197
13198 MovementForce force;
13199 force.ID = id;
13200 force.Origin = origin;
13201 force.Direction = direction;
13202 if (transportGuid.IsMOTransport())
13203 force.TransportID = transportGuid.GetCounter();
13204
13205 force.Magnitude = magnitude;
13206 force.Type = type;
13207
13208 if (_movementForces->Add(force))
13209 {
13210 if (Player const* movingPlayer = GetPlayerMovingMe())
13211 {
13213 applyMovementForce.MoverGUID = GetGUID();
13214 applyMovementForce.SequenceIndex = m_movementCounter++;
13215 applyMovementForce.Force = &force;
13216 movingPlayer->SendDirectMessage(applyMovementForce.Write());
13217 }
13218 else
13219 {
13221 updateApplyMovementForce.Status = &m_movementInfo;
13222 updateApplyMovementForce.Force = &force;
13223 SendMessageToSet(updateApplyMovementForce.Write(), true);
13224 }
13225 }
13226}
13227
13229{
13230 if (!_movementForces)
13231 return;
13232
13233 if (_movementForces->Remove(id))
13234 {
13235 if (Player const* movingPlayer = GetPlayerMovingMe())
13236 {
13238 moveRemoveMovementForce.MoverGUID = GetGUID();
13239 moveRemoveMovementForce.SequenceIndex = m_movementCounter++;
13240 moveRemoveMovementForce.ID = id;
13241 movingPlayer->SendDirectMessage(moveRemoveMovementForce.Write());
13242 }
13243 else
13244 {
13246 updateRemoveMovementForce.Status = &m_movementInfo;
13247 updateRemoveMovementForce.TriggerGUID = id;
13248 SendMessageToSet(updateRemoveMovementForce.Write(), true);
13249 }
13250 }
13251
13252 if (_movementForces->IsEmpty())
13253 _movementForces.reset();
13254}
13255
13257{
13259 return false;
13260
13261 if (ignore)
13263 else
13265
13266 static OpcodeServer const ignoreMovementForcesOpcodeTable[2] =
13267 {
13270 };
13271
13272 if (Player const* movingPlayer = GetPlayerMovingMe())
13273 {
13274 WorldPackets::Movement::MoveSetFlag packet(ignoreMovementForcesOpcodeTable[ignore]);
13275 packet.MoverGUID = GetGUID();
13277 movingPlayer->SendDirectMessage(packet.Write());
13278
13280 moveUpdate.Status = &m_movementInfo;
13281 SendMessageToSet(moveUpdate.Write(), movingPlayer);
13282 }
13283
13284 return true;
13285}
13286
13288{
13290
13291 if (Player* movingPlayer = GetPlayerMovingMe())
13292 {
13294 setModMovementForceMagnitude.MoverGUID = GetGUID();
13295 setModMovementForceMagnitude.SequenceIndex = m_movementCounter++;
13296 setModMovementForceMagnitude.Speed = modMagnitude;
13297 movingPlayer->SendDirectMessage(setModMovementForceMagnitude.Write());
13298 ++movingPlayer->m_movementForceModMagnitudeChanges;
13299 }
13300 else
13301 {
13303 updateModMovementForceMagnitude.Status = &m_movementInfo;
13304 updateModMovementForceMagnitude.Speed = modMagnitude;
13305 SendMessageToSet(updateModMovementForceMagnitude.Write(), true);
13306 }
13307
13308 if (modMagnitude != 1.0f && !_movementForces)
13309 _movementForces = std::make_unique<MovementForces>();
13310
13311 if (_movementForces)
13312 {
13313 _movementForces->SetModMagnitude(modMagnitude);
13314 if (_movementForces->IsEmpty())
13315 _movementForces.reset();
13316 }
13317}
13318
13319void Unit::SetPlayHoverAnim(bool enable, bool sendUpdate /*= true*/)
13320{
13321 if (IsPlayingHoverAnim() == enable)
13322 return;
13323
13324 _playHoverAnim = enable;
13325
13326 if (!sendUpdate)
13327 return;
13328
13330 data.UnitGUID = GetGUID();
13331 data.PlayHoverAnim = enable;
13332
13333 SendMessageToSet(data.Write(), true);
13334}
13335
13337{
13338 float hoverHeight = DEFAULT_PLAYER_HOVER_HEIGHT;
13339 float displayScale = DEFAULT_PLAYER_DISPLAY_SCALE;
13340
13341 uint32 displayId = IsMounted() ? GetMountDisplayId() : GetDisplayId();
13342
13343 // Get DisplayScale for creatures
13344 if (IsCreature())
13345 if (CreatureModel const* model = ToCreature()->GetCreatureTemplate()->GetModelWithDisplayId(displayId))
13346 displayScale = model->DisplayScale;
13347
13348 if (CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(displayId))
13349 if (CreatureModelDataEntry const* modelData = sCreatureModelDataStore.LookupEntry(displayInfo->ModelID))
13350 hoverHeight = modelData->HoverHeight * modelData->ModelScale * displayInfo->CreatureModelScale * displayScale;
13351
13352 SetHoverHeight(hoverHeight ? hoverHeight : DEFAULT_PLAYER_HOVER_HEIGHT);
13353}
13354
13356{
13357 return movespline->Initialized() && !movespline->Finalized();
13358}
13359
13361{
13363 if (target == this || GetOwnerGUID() == target->GetGUID())
13365
13369
13370 return flags;
13371}
13372
13373void Unit::BuildValuesCreate(ByteBuffer* data, Player const* target) const
13374{
13376 std::size_t sizePos = data->wpos();
13377 *data << uint32(0);
13378 *data << uint8(flags);
13379 m_objectData->WriteCreate(*data, flags, this, target);
13380 m_unitData->WriteCreate(*data, flags, this, target);
13381 data->put<uint32>(sizePos, data->wpos() - sizePos - 4);
13382}
13383
13384void Unit::BuildValuesUpdate(ByteBuffer* data, Player const* target) const
13385{
13387 std::size_t sizePos = data->wpos();
13388 *data << uint32(0);
13390
13392 m_objectData->WriteUpdate(*data, flags, this, target);
13393
13395 m_unitData->WriteUpdate(*data, flags, this, target);
13396
13397 data->put<uint32>(sizePos, data->wpos() - sizePos - 4);
13398}
13399
13401{
13403 valuesMask.Set(TYPEID_UNIT);
13404
13405 std::size_t sizePos = data->wpos();
13406 *data << uint32(0);
13407 *data << uint32(valuesMask.GetBlock(0));
13408
13409 UF::UnitData::Mask mask;
13410 m_unitData->AppendAllowedFieldsMaskForFlag(mask, flags);
13411 m_unitData->WriteUpdate(*data, mask, true, this, target);
13412
13413 data->put<uint32>(sizePos, data->wpos() - sizePos - 4);
13414}
13415
13417 UF::UnitData::Mask const& requestedUnitMask, Player const* target) const
13418{
13421 if (requestedObjectMask.IsAnySet())
13422 valuesMask.Set(TYPEID_OBJECT);
13423
13424 UF::UnitData::Mask unitMask = requestedUnitMask;
13425 m_unitData->FilterDisallowedFieldsMaskForFlag(unitMask, flags);
13426 if (unitMask.IsAnySet())
13427 valuesMask.Set(TYPEID_UNIT);
13428
13429 ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
13430 std::size_t sizePos = buffer.wpos();
13431 buffer << uint32(0);
13432 buffer << uint32(valuesMask.GetBlock(0));
13433
13434 if (valuesMask[TYPEID_OBJECT])
13435 m_objectData->WriteUpdate(buffer, requestedObjectMask, true, this, target);
13436
13437 if (valuesMask[TYPEID_UNIT])
13438 m_unitData->WriteUpdate(buffer, unitMask, true, this, target);
13439
13440 buffer.put<uint32>(sizePos, buffer.wpos() - sizePos - 4);
13441
13442 data->AddUpdateBlock();
13443}
13444
13446{
13447 UpdateData udata(Owner->GetMapId());
13448 WorldPacket packet;
13449
13451
13452 udata.BuildPacket(&packet);
13453 player->SendDirectMessage(&packet);
13454}
13455
13457{
13458 if (Battleground* bg = target->GetBattleground())
13459 {
13460 if (bg->isArena())
13461 {
13463 destroyArenaUnit.Guid = GetGUID();
13464 target->GetSession()->SendPacket(destroyArenaUnit.Write());
13465 }
13466 }
13467
13469}
13470
13471void Unit::ClearUpdateMask(bool remove)
13472{
13475}
13476
13477int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const
13478{
13479 int32 val = 0;
13480 SpellSpellGroupMapBounds spellGroup = sSpellMgr->GetSpellSpellGroupMapBounds(aurEff->GetSpellInfo()->GetFirstRankSpell()->Id);
13481 for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second ; ++itr)
13482 {
13483 if (sSpellMgr->GetSpellGroupStackRule(itr->second) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
13484 {
13485 AuraEffectList const& auraEffList = GetAuraEffectsByType(auraType);
13486 for (AuraEffectList::const_iterator auraItr = auraEffList.begin(); auraItr != auraEffList.end(); ++auraItr)
13487 {
13488 if (aurEff != (*auraItr) && (!checkMiscValue || (*auraItr)->GetMiscValue() == miscValue) &&
13489 sSpellMgr->IsSpellMemberOfSpellGroup((*auraItr)->GetSpellInfo()->Id, itr->second))
13490 {
13491 // absolute value only
13492 if (abs(val) < abs((*auraItr)->GetAmount()))
13493 val = (*auraItr)->GetAmount();
13494 }
13495 }
13496 }
13497 }
13498 return val;
13499}
13500
13501bool Unit::IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications /*= false*/)
13502{
13503 for (AuraEffect const* aurEff : aura->GetAuraEffects())
13504 {
13505 if (!aurEff)
13506 continue;
13507
13508 if (!IsHighestExclusiveAuraEffect(aura->GetSpellInfo(), aurEff->GetAuraType(), aurEff->GetAmount(), aura->GetEffectMask(), removeOtherAuraApplications))
13509 return false;
13510 }
13511
13512 return true;
13513}
13514
13515bool Unit::IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType auraType, int32 effectAmount, uint32 auraEffectMask, bool removeOtherAuraApplications /*= false*/)
13516{
13517 AuraEffectList const& auras = GetAuraEffectsByType(auraType);
13518 for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();)
13519 {
13520 AuraEffect const* existingAurEff = (*itr);
13521 ++itr;
13522
13523 if (sSpellMgr->CheckSpellGroupStackRules(spellInfo, existingAurEff->GetSpellInfo()) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST)
13524 {
13525 int64 diff = int64(abs(effectAmount)) - int64(abs(existingAurEff->GetAmount()));
13526 if (!diff)
13527 for (int32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
13528 diff += int64((auraEffectMask & (1 << i)) >> i) - int64((existingAurEff->GetBase()->GetEffectMask() & (1 << i)) >> i);
13529
13530 if (diff > 0)
13531 {
13532 Aura const* base = existingAurEff->GetBase();
13533 // no removing of area auras from the original owner, as that completely cancels them
13534 if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this))
13535 {
13536 if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID()))
13537 {
13538 bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType);
13539 uint32 removedAuras = m_removedAurasCount;
13540 RemoveAura(aurApp);
13541 if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1)
13542 itr = auras.begin();
13543 }
13544 }
13545 }
13546 else if (diff < 0)
13547 return false;
13548 }
13549 }
13550
13551 return true;
13552}
13553
13554void Unit::Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const* target)
13555{
13556 Trinity::CustomChatTextBuilder builder(this, msgType, text, language, target);
13559 Cell::VisitWorldObjects(this, worker, textRange);
13560}
13561
13562void Unit::Say(std::string_view text, Language language, WorldObject const* target /*= nullptr*/)
13563{
13564 Talk(text, CHAT_MSG_MONSTER_SAY, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
13565}
13566
13567void Unit::Yell(std::string_view text, Language language, WorldObject const* target /*= nullptr*/)
13568{
13569 Talk(text, CHAT_MSG_MONSTER_YELL, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target);
13570}
13571
13572void Unit::TextEmote(std::string_view text, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/)
13573{
13575}
13576
13577void Unit::Whisper(std::string_view text, Language language, Player* target, bool isBossWhisper /*= false*/)
13578{
13579 if (!target)
13580 return;
13581
13584 packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, language, this, target, text, 0, "", locale);
13585 target->SendDirectMessage(packet.Write());
13586}
13587
13589{
13590 if (slot >= MAX_EQUIPMENT_ITEMS)
13591 return 0;
13592
13593 return m_unitData->VirtualItems[slot].ItemID;
13594}
13595
13597{
13598 if (slot >= MAX_EQUIPMENT_ITEMS)
13599 return 0;
13600
13601 return m_unitData->VirtualItems[slot].ItemAppearanceModID;
13602}
13603
13604void Unit::SetVirtualItem(uint32 slot, uint32 itemId, uint16 appearanceModId /*= 0*/, uint16 itemVisual /*= 0*/)
13605{
13606 if (slot >= MAX_EQUIPMENT_ITEMS)
13607 return;
13608
13609 auto virtualItemField = m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::VirtualItems, slot);
13610 SetUpdateFieldValue(virtualItemField.ModifyValue(&UF::VisibleItem::ItemID), itemId);
13611 SetUpdateFieldValue(virtualItemField.ModifyValue(&UF::VisibleItem::ItemAppearanceModID), appearanceModId);
13612 SetUpdateFieldValue(virtualItemField.ModifyValue(&UF::VisibleItem::ItemVisual), itemVisual);
13613}
13614
13615void Unit::Talk(uint32 textId, ChatMsg msgType, float textRange, WorldObject const* target)
13616{
13617 if (!sBroadcastTextStore.LookupEntry(textId))
13618 {
13619 TC_LOG_ERROR("entities.unit", "WorldObject::MonsterText: `broadcast_text` (ID: {}) was not found", textId);
13620 return;
13621 }
13622
13623 Trinity::BroadcastTextBuilder builder(this, msgType, textId, GetGender(), target);
13626 Cell::VisitWorldObjects(this, worker, textRange);
13627}
13628
13629void Unit::Say(uint32 textId, WorldObject const* target /*= nullptr*/)
13630{
13631 Talk(textId, CHAT_MSG_MONSTER_SAY, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
13632}
13633
13634void Unit::Yell(uint32 textId, WorldObject const* target /*= nullptr*/)
13635{
13636 Talk(textId, CHAT_MSG_MONSTER_YELL, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target);
13637}
13638
13639void Unit::TextEmote(uint32 textId, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/)
13640{
13641 Talk(textId, isBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), target);
13642}
13643
13644void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/)
13645{
13646 if (!target)
13647 return;
13648
13649 BroadcastTextEntry const* bct = sBroadcastTextStore.LookupEntry(textId);
13650 if (!bct)
13651 {
13652 TC_LOG_ERROR("entities.unit", "WorldObject::Whisper: `broadcast_text` was not {} found", textId);
13653 return;
13654 }
13655
13658 packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, DB2Manager::GetBroadcastTextValue(bct, locale, GetGender()), 0, "", locale);
13659 target->SendDirectMessage(packet.Write());
13660}
13661
13662void Unit::ClearBossEmotes(Optional<uint32> zoneId, Player const* target) const
13663{
13665 clearBossEmotes.Write();
13666
13667 if (target)
13668 {
13669 target->SendDirectMessage(clearBossEmotes.GetRawPacket());
13670 return;
13671 }
13672
13673 for (MapReference const& ref : GetMap()->GetPlayers())
13674 if (!zoneId || DB2Manager::IsInArea(ref.GetSource()->GetAreaId(), *zoneId))
13675 ref.GetSource()->SendDirectMessage(clearBossEmotes.GetRawPacket());
13676}
13677
13678SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo, TriggerCastFlags& triggerFlag) const
13679{
13680 auto findMatchingAuraEffectIn = [this, spellInfo, &triggerFlag](AuraType type) -> SpellInfo const*
13681 {
13682 for (AuraEffect const* auraEffect : GetAuraEffectsByType(type))
13683 {
13684 bool matches = auraEffect->GetMiscValue() ? uint32(auraEffect->GetMiscValue()) == spellInfo->Id : auraEffect->IsAffectingSpell(spellInfo);
13685 if (matches)
13686 {
13687 if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(auraEffect->GetAmount(), GetMap()->GetDifficultyID()))
13688 {
13689 if (auraEffect->GetSpellInfo()->HasAttribute(SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST))
13691
13692 return newInfo;
13693 }
13694 }
13695 }
13696
13697 return nullptr;
13698 };
13699
13700 if (SpellInfo const* newInfo = findMatchingAuraEffectIn(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS))
13701 return newInfo;
13702
13703 if (SpellInfo const* newInfo = findMatchingAuraEffectIn(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_TRIGGERED))
13704 return newInfo;
13705
13706 return spellInfo;
13707}
13708
13710{
13712 for (AuraEffect const* effect : visualOverrides)
13713 {
13714 if (uint32(effect->GetMiscValue()) == spellInfo->Id)
13715 {
13716 if (SpellInfo const* visualSpell = sSpellMgr->GetSpellInfo(effect->GetMiscValueB(), GetMap()->GetDifficultyID()))
13717 {
13718 spellInfo = visualSpell;
13719 break;
13720 }
13721 }
13722 }
13723
13725}
13726
13728{
13729 return left->GetSlot() < right->GetSlot();
13730}
13731
13732// Returns collisionheight of the unit. If it is 0, it returns DEFAULT_COLLISION_HEIGHT.
13734{
13735 float scaleMod = GetObjectScale(); // 99% sure about this
13736
13737 if (IsMounted())
13738 {
13739 if (CreatureDisplayInfoEntry const* mountDisplayInfo = sCreatureDisplayInfoStore.LookupEntry(GetMountDisplayId()))
13740 {
13741 if (CreatureModelDataEntry const* mountModelData = sCreatureModelDataStore.LookupEntry(mountDisplayInfo->ModelID))
13742 {
13743 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId());
13744 CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelID);
13745 float const collisionHeight = scaleMod * ((mountModelData->MountHeight * mountDisplayInfo->CreatureModelScale) + (modelData->CollisionHeight * modelData->ModelScale * displayInfo->CreatureModelScale * 0.5f));
13746 return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
13747 }
13748 }
13749 }
13750
13752 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId());
13753 CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelID);
13754
13755 float const collisionHeight = scaleMod * modelData->CollisionHeight * modelData->ModelScale * displayInfo->CreatureModelScale;
13756 return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
13757}
13758
13760{
13761 if (m_vignette)
13762 {
13763 if (m_vignette->Data->ID == vignetteId)
13764 return;
13765
13767 m_vignette = nullptr;
13768 }
13769
13770 if (VignetteEntry const* vignette = sVignetteStore.LookupEntry(vignetteId))
13771 m_vignette = Vignettes::Create(vignette, this);
13772}
13773
13774std::string Unit::GetDebugInfo() const
13775{
13776 std::stringstream sstr;
13777 sstr << WorldObject::GetDebugInfo() << "\n"
13778 << std::boolalpha
13779 << "IsAIEnabled: " << IsAIEnabled() << " DeathState: " << std::to_string(getDeathState())
13780 << " UnitMovementFlags: " << GetUnitMovementFlags() << " ExtraUnitMovementFlags: " << GetExtraUnitMovementFlags()
13781 << " Class: " << std::to_string(GetClass()) << "\n"
13782 << "" << (movespline ? movespline->ToString() : "Movespline: <none>\n")
13783 << "GetCharmedGUID(): " << GetCharmedGUID().ToString() << "\n"
13784 << "GetCharmerGUID(): " << GetCharmerGUID().ToString() << "\n"
13785 << "" << (GetVehicleKit() ? GetVehicleKit()->GetDebugInfo() : "No vehicle kit") << "\n"
13786 << "m_Controlled size: " << m_Controlled.size();
13787
13788 size_t controlledCount = 0;
13789 for (Unit* controlled : m_Controlled)
13790 {
13791 ++controlledCount;
13792 sstr << "\n" << "m_Controlled " << controlledCount << " : " << controlled->GetGUID().ToString();
13793 }
13794
13795 return sstr.str();
13796}
13797
13799{
13800 for (std::size_t i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
13801 name[i] = uf.Name[i];
13802}
#define sBattlefieldMgr
@ SCORE_DAMAGE_DONE
@ SCORE_HEALING_DONE
#define sCharacterCache
CharmType
Definition: CharmInfo.h:69
@ CHARM_TYPE_CHARM
Definition: CharmInfo.h:70
@ CHARM_TYPE_POSSESS
Definition: CharmInfo.h:71
@ CHARM_TYPE_CONVERT
Definition: CharmInfo.h:73
@ CHARM_TYPE_VEHICLE
Definition: CharmInfo.h:72
LocaleConstant
Definition: Common.h:48
@ IN_MILLISECONDS
Definition: Common.h:35
@ MINUTE
Definition: Common.h:29
@ SEC_PLAYER
Definition: Common.h:40
@ SEC_GAMEMASTER
Definition: Common.h:42
#define M_PI
Definition: Common.h:115
#define sConditionMgr
Definition: ConditionMgr.h:365
#define sCreatureAIRegistry
@ CREATURE_FLAG_EXTRA_NO_BLOCK
Definition: CreatureData.h:338
@ CREATURE_FLAG_EXTRA_NO_CRUSHING_BLOWS
Definition: CreatureData.h:339
@ CREATURE_FLAG_EXTRA_NO_CRIT
Definition: CreatureData.h:351
@ CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN
Definition: CreatureData.h:337
@ CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS
Definition: CreatureData.h:353
@ CREATURE_FLAG_EXTRA_NO_PARRY
Definition: CreatureData.h:336
@ CREATURE_STATIC_FLAG_UNKILLABLE
Definition: CreatureData.h:41
DB2Storage< ArtifactAppearanceEntry > sArtifactAppearanceStore("ArtifactAppearance.db2", &ArtifactAppearanceLoadInfo::Instance)
DB2Storage< CreatureModelDataEntry > sCreatureModelDataStore("CreatureModelData.db2", &CreatureModelDataLoadInfo::Instance)
DB2Storage< LiquidTypeEntry > sLiquidTypeStore("LiquidType.db2", &LiquidTypeLoadInfo::Instance)
DB2Storage< AnimKitEntry > sAnimKitStore("AnimKit.db2", &AnimKitLoadInfo::Instance)
DB2Storage< ChrClassesEntry > sChrClassesStore("ChrClasses.db2", &ChrClassesLoadInfo::Instance)
DB2Storage< SpellShapeshiftFormEntry > sSpellShapeshiftFormStore("SpellShapeshiftForm.db2", &SpellShapeshiftFormLoadInfo::Instance)
DB2Storage< CreatureDisplayInfoExtraEntry > sCreatureDisplayInfoExtraStore("CreatureDisplayInfoExtra.db2", &CreatureDisplayInfoExtraLoadInfo::Instance)
DB2Storage< EmotesEntry > sEmotesStore("Emotes.db2", &EmotesLoadInfo::Instance)
DB2Storage< BroadcastTextEntry > sBroadcastTextStore("BroadcastText.db2", &BroadcastTextLoadInfo::Instance)
DB2Storage< VignetteEntry > sVignetteStore("Vignette.db2", &VignetteLoadInfo::Instance)
DB2Storage< ChrRacesEntry > sChrRacesStore("ChrRaces.db2", &ChrRacesLoadInfo::Instance)
DB2Storage< PlayerConditionEntry > sPlayerConditionStore("PlayerCondition.db2", &PlayerConditionLoadInfo::Instance)
DB2Storage< ChrCustomizationReqEntry > sChrCustomizationReqStore("ChrCustomizationReq.db2", &ChrCustomizationReqLoadInfo::Instance)
DB2Storage< CreatureDisplayInfoEntry > sCreatureDisplayInfoStore("CreatureDisplayInfo.db2", &CreatureDisplayInfoLoadInfo::Instance)
DB2Storage< PowerDisplayEntry > sPowerDisplayStore("PowerDisplay.db2", &PowerDisplayLoadInfo::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:538
AreaMountFlags
Definition: DBCEnums.h:169
@ AllowUnderwaterSwimmingMounts
@ AllowSurfaceSwimmingMounts
@ DIFFICULTY_NONE
Definition: DBCEnums.h:874
#define MAX_EFFECT_MASK
Definition: DBCEnums.h:1954
#define MAX_SPELL_EFFECTS
Definition: DBCEnums.h:1953
@ MOUNT_CAPABILITY_FLAG_FLYING
Definition: DBCEnums.h:1711
@ MOUNT_CAPABIILTY_FLAG_IGNORE_RESTRICTIONS
Definition: DBCEnums.h:1714
@ MOUNT_CAPABILITY_FLAG_UNDERWATER
Definition: DBCEnums.h:1713
@ MOUNT_CAPABILITY_FLAG_GROUND
Definition: DBCEnums.h:1710
@ MOUNT_CAPABILITY_FLAG_FLOAT
Definition: DBCEnums.h:1712
#define TC_GAME_API
Definition: Define.h:123
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
#define UI64LIT(N)
Definition: Define.h:127
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
uint16 flags
Definition: DisableMgr.cpp:49
std::chrono::steady_clock::time_point TimePoint
time_point shorthand typedefs
Definition: Duration.h:41
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:29
#define ABORT_MSG
Definition: Errors.h:75
#define ABORT
Definition: Errors.h:74
#define ASSERT_NODEBUGINFO
Definition: Errors.h:69
#define ASSERT_NOTNULL(pointer)
Definition: Errors.h:84
#define ASSERT
Definition: Errors.h:68
@ GROUP_UPDATE_FLAG_CUR_HP
Definition: Group.h:126
@ GROUP_UPDATE_FLAG_POWER_TYPE
Definition: Group.h:124
@ GROUP_UPDATE_FLAG_MAX_HP
Definition: Group.h:127
@ GROUP_UPDATE_FLAG_MAX_POWER
Definition: Group.h:129
@ GROUP_UPDATE_FLAG_AURAS
Definition: Group.h:137
@ GROUP_UPDATE_FLAG_LEVEL
Definition: Group.h:130
@ GROUP_UPDATE_FLAG_CUR_POWER
Definition: Group.h:128
@ GROUP_UPDATE_FLAG_PET_CUR_HP
Definition: Group.h:155
@ GROUP_UPDATE_FLAG_PET_AURAS
Definition: Group.h:157
@ GROUP_UPDATE_FLAG_PET_MAX_HP
Definition: Group.h:156
@ ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID
Definition: ItemDefines.h:219
@ ITEM_SUBCLASS_WEAPON_AXE2
Definition: ItemTemplate.h:481
@ ITEM_SUBCLASS_WEAPON_STAFF
Definition: ItemTemplate.h:490
@ ITEM_SUBCLASS_WEAPON_MACE
Definition: ItemTemplate.h:484
@ ITEM_SUBCLASS_WEAPON_EXOTIC2
Definition: ItemTemplate.h:492
@ ITEM_SUBCLASS_WEAPON_WARGLAIVES
Definition: ItemTemplate.h:489
@ ITEM_SUBCLASS_WEAPON_FISHING_POLE
Definition: ItemTemplate.h:500
@ ITEM_SUBCLASS_WEAPON_MACE2
Definition: ItemTemplate.h:485
@ ITEM_SUBCLASS_WEAPON_DAGGER
Definition: ItemTemplate.h:495
@ ITEM_SUBCLASS_WEAPON_SWORD
Definition: ItemTemplate.h:487
@ ITEM_SUBCLASS_WEAPON_AXE
Definition: ItemTemplate.h:480
@ ITEM_SUBCLASS_WEAPON_FIST_WEAPON
Definition: ItemTemplate.h:493
@ ITEM_SUBCLASS_WEAPON_EXOTIC
Definition: ItemTemplate.h:491
@ ITEM_SUBCLASS_WEAPON_THROWN
Definition: ItemTemplate.h:496
@ ITEM_SUBCLASS_WEAPON_SWORD2
Definition: ItemTemplate.h:488
@ ITEM_SUBCLASS_WEAPON_POLEARM
Definition: ItemTemplate.h:486
@ INVTYPE_SHIELD
Definition: ItemTemplate.h:393
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define TC_LOG_FATAL(filterType__,...)
Definition: Log.h:168
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:914
@ LOOT_CORPSE
Definition: Loot.h:101
ZLiquidStatus
Definition: MapDefines.h:125
@ LIQUID_MAP_UNDER_WATER
Definition: MapDefines.h:130
@ LIQUID_MAP_OCEAN_FLOOR
Definition: MapDefines.h:131
@ LIQUID_MAP_IN_WATER
Definition: MapDefines.h:129
bool IsInvalidMovementSlot(uint8 const slot)
@ MOTION_PRIORITY_HIGHEST
@ MOTION_PRIORITY_NORMAL
MovementSlot
MovementGeneratorType
@ IDLE_MOTION_TYPE
@ FLEEING_MOTION_TYPE
@ CONFUSED_MOTION_TYPE
@ POINT_MOTION_TYPE
@ FOLLOW_MOTION_TYPE
@ EFFECT_MOTION_TYPE
MovementForceType
Definition: MovementInfo.h:143
#define DEFAULT_PLAYER_HOVER_HEIGHT
Definition: ObjectDefines.h:42
#define DEFAULT_PLAYER_DISPLAY_SCALE
Definition: ObjectDefines.h:41
#define NOMINAL_MELEE_RANGE
Definition: ObjectDefines.h:44
#define MIN_MELEE_REACH
Definition: ObjectDefines.h:43
@ NOTIFY_VISIBILITY_CHANGED
Definition: ObjectDefines.h:77
@ TYPEID_OBJECT
Definition: ObjectGuid.h:35
@ TYPEID_GAMEOBJECT
Definition: ObjectGuid.h:43
@ TYPEID_UNIT
Definition: ObjectGuid.h:40
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
@ TYPEMASK_UNIT
Definition: ObjectGuid.h:60
#define sObjectMgr
Definition: ObjectMgr.h:1946
float const DEFAULT_COLLISION_HEIGHT
Definition: Object.h:147
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
@ PETSPELL_REMOVED
Definition: PetDefines.h:72
PetActionFeedback
Definition: PetDefines.h:83
#define PET_FOLLOW_DIST
Definition: PetDefines.h:97
@ 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:629
@ EQUIPMENT_SLOT_END
Definition: Player.h:650
@ EQUIPMENT_SLOT_OFFHAND
Definition: Player.h:647
@ TELE_TO_SPELL
Definition: Player.h:806
@ TELE_TO_NOT_LEAVE_COMBAT
Definition: Player.h:804
@ TELE_TO_NOT_UNSUMMON_PET
Definition: Player.h:805
@ TELE_TO_NONE
Definition: Player.h:801
@ TELE_TO_NOT_LEAVE_TRANSPORT
Definition: Player.h:803
std::unordered_map< uint32, PlayerSpell > PlayerSpellMap
Definition: Player.h:276
@ CHEAT_GOD
Definition: Player.h:949
@ PLAYERSPELL_REMOVED
Definition: Player.h:189
#define INVENTORY_SLOT_BAG_0
Definition: Player.h:625
Trinity::IteratorPair< UF::ChrCustomizationChoice const * > MakeChrCustomizationChoiceRange(Container const &container)
Definition: Player.h:3247
Races
Definition: RaceMask.h:26
float rand_norm()
Definition: Random.cpp:75
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
bool roll_chance_f(float chance)
Definition: Random.h:53
bool roll_chance_i(int chance)
Definition: Random.h:59
if(posix_memalign(&__mallocedMemory, __align, __size)) return NULL
#define sScriptMgr
Definition: ScriptMgr.h:1418
@ SERVERSIDE_VISIBILITY_GM
@ SERVERSIDE_VISIBILITY_GHOST
@ EFFECT_1
Definition: SharedDefines.h:31
@ EFFECT_0
Definition: SharedDefines.h:30
@ SPELL_ATTR10_RESET_COOLDOWN_ON_ENCOUNTER_END
#define MAX_STATS
#define MAX_POWERS_PER_CLASS
@ SPELL_ATTR7_DONT_CAUSE_SPELL_PUSHBACK
@ SPELL_ATTR7_DISPEL_REMOVES_CHARGES
@ SPELL_ATTR7_NO_ATTACK_PARRY
@ SPELL_ATTR7_DO_NOT_COUNT_FOR_PVP_SCOREBOARD
@ SPELL_ATTR7_NO_ATTACK_MISS
@ SPELL_ATTR7_NO_ATTACK_DODGE
Classes
@ CLASS_WARRIOR
@ CLASS_WARLOCK
@ CLASS_MAGE
@ CLASS_ROGUE
Language
@ LANG_UNIVERSAL
Gender
@ SPELL_ATTR5_ALLOW_ACTIONS_DURING_CHANNEL
@ SPELL_ATTR5_REMOVE_ENTERING_ARENA
SpellMissInfo
@ SPELL_MISS_PARRY
@ SPELL_MISS_IMMUNE
@ SPELL_MISS_ABSORB
@ SPELL_MISS_DODGE
@ SPELL_MISS_IMMUNE2
@ SPELL_MISS_NONE
@ SPELL_MISS_RESIST
@ SPELL_MISS_MISS
@ SPELL_MISS_EVADE
@ SPELL_MISS_REFLECT
@ SPELL_MISS_BLOCK
@ SPELL_MISS_DEFLECT
@ NPC_CLICK_CAST_TARGET_CLICKER
@ NPC_CLICK_CAST_ORIG_CASTER_OWNER
@ NPC_CLICK_CAST_CASTER_CLICKER
Emote
@ EMOTE_ONESHOT_NONE
SpellSchoolMask
@ SPELL_SCHOOL_MASK_NORMAL
@ SPELL_SCHOOL_MASK_MAGIC
@ SPELL_SCHOOL_MASK_NONE
@ SPELL_SCHOOL_MASK_HOLY
@ EVENT_FACE
@ EVENT_JUMP
@ EVENT_VEHICLE_EXIT
@ SPELL_ATTR2_ALLOW_WHILE_INVISIBLE
@ SPELL_ATTR2_PROC_COOLDOWN_ON_FAILURE
@ SPELL_ATTR2_ALLOW_DEAD_TARGET
@ SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS
@ SPELL_ATTR2_NO_SCHOOL_IMMUNITIES
@ ANIM_MOUNT_SPECIAL
@ ANIM_MOUNT_SELF_SPECIAL
SummonTitle
@ CREATURE_TYPE_DEMON
@ SPELL_ATTR1_ALLOW_WHILE_STEALTHED
@ SPELL_ATTR1_AURA_STAYS_AFTER_COMBAT
@ SPELL_ATTR1_IMMUNITY_PURGES_EFFECT
@ SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS
@ UNIT_DYNFLAG_SPECIALINFO
@ UNIT_DYNFLAG_LOOTABLE
@ UNIT_DYNFLAG_CAN_SKIN
@ SPELL_ATTR3_TREAT_AS_PERIODIC
@ SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD
@ SPELL_ATTR3_SUPPRESS_TARGET_PROCS
@ SPELL_ATTR3_NO_DURABILITY_LOSS
@ SPELL_ATTR3_ALWAYS_HIT
@ SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON
@ SPELL_ATTR3_SUPPRESS_CASTER_PROCS
@ SPELL_ATTR3_NO_AVOIDANCE
@ SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON
@ SPELL_ATTR3_IGNORE_CASTER_MODIFIERS
@ SPELL_DAMAGE_CLASS_RANGED
@ SPELL_DAMAGE_CLASS_MAGIC
@ SPELL_DAMAGE_CLASS_NONE
@ SPELL_DAMAGE_CLASS_MELEE
@ AI_REACTION_HOSTILE
@ SPELL_EFFECT_HEALTH_LEECH
@ SPELL_EFFECT_NORMALIZED_WEAPON_DMG
@ SPELL_EFFECT_SUMMON
@ MAX_SUMMON_SLOT
WeaponAttackType
@ OFF_ATTACK
@ MAX_ATTACK
@ BASE_ATTACK
@ RANGED_ATTACK
#define PER_CASTER_AURA_STATE_MASK
Mechanics
@ MECHANIC_NONE
@ MECHANIC_ROOT
@ MECHANIC_BLEED
@ MECHANIC_DAZE
@ MECHANIC_SNARE
SpellImmunity
@ IMMUNITY_STATE
@ IMMUNITY_EFFECT
@ IMMUNITY_ID
@ IMMUNITY_DAMAGE
@ IMMUNITY_MECHANIC
@ IMMUNITY_SCHOOL
@ IMMUNITY_OTHER
@ IMMUNITY_DISPEL
Powers
@ MAX_POWERS
@ POWER_RAGE
@ POWER_ENERGY
@ POWER_MANA
@ POWER_FOCUS
@ SPELL_ATTR0_NO_ACTIVE_DEFENSE
@ SPELL_ATTR0_ALLOW_WHILE_MOUNTED
@ SPELL_ATTR0_NO_IMMUNITIES
@ SPELL_ATTR0_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_CAST_OK
@ GHOST_VISIBILITY_ALIVE
@ SPELL_HIT_TYPE_CRIT
Stats
@ STAT_INTELLECT
@ STAT_AGILITY
@ STAT_STRENGTH
@ STAT_STAMINA
AuraStateType
@ AURA_STATE_WOUNDED_20_PERCENT
@ AURA_STATE_HEALTHY_75_PERCENT
@ AURA_STATE_FROZEN
@ AURA_STATE_WOUNDED_35_PERCENT
@ AURA_STATE_ENRAGED
@ AURA_STATE_WOUND_HEALTH_35_80
@ AURA_STATE_DEFENSIVE_2
@ AURA_STATE_WOUND_HEALTH_20_80
@ AURA_STATE_WOUNDED_25_PERCENT
@ AURA_STATE_DEFENSIVE
@ DRTYPE_PLAYER
@ DRTYPE_ALL
SpellFamilyNames
@ SPELLFAMILY_WARLOCK
@ SPELLFAMILY_MAGE
@ SPELLFAMILY_POTION
@ SPELLFAMILY_ROGUE
@ SPELLFAMILY_DRUID
SpellSchools
@ SPELL_SCHOOL_SHADOW
@ SPELL_SCHOOL_NORMAL
@ SPELL_SCHOOL_NATURE
@ SPELL_SCHOOL_FROST
@ SPELL_SCHOOL_ARCANE
@ SPELL_SCHOOL_FIRE
@ SPELL_SCHOOL_HOLY
@ MAX_SPELL_SCHOOL
@ DISPEL_DISEASE
@ DISPEL_INVISIBILITY
@ DISPEL_STEALTH
#define MAX_GAMEOBJECT_SLOT
ChatMsg
@ CHAT_MSG_MONSTER_WHISPER
@ CHAT_MSG_RAID_BOSS_WHISPER
@ CHAT_MSG_RAID_BOSS_EMOTE
@ CHAT_MSG_MONSTER_EMOTE
@ CHAT_MSG_MONSTER_SAY
@ CHAT_MSG_MONSTER_YELL
@ SPELL_ATTR4_NO_HARMFUL_THREAT
@ SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS
@ SPELL_ATTR4_NO_PARTIAL_IMMUNITY
@ SPELL_ATTR4_REACTIVE_DAMAGE_PROC
@ SPELL_ATTR4_ALLOW_ENTERING_ARENA
@ SPELL_ATTR8_IGNORE_SPELLCAST_OVERRIDE_COST
@ SPELL_ATTR8_NO_ATTACK_BLOCK
@ SKILL_RIDING
@ SPELL_ATTR6_NO_PUSHBACK
@ SPELL_ATTR6_IGNORE_CASTER_DAMAGE_MODIFIERS
@ SPELL_ATTR6_IGNORE_HEALING_MODIFIERS
@ SPELL_ATTR6_ABSORB_CANNOT_BE_IGNORE
@ SPELL_ATTR6_DELAY_COMBAT_TIMER_DURING_CAST
AuraTriggerOnHealthChangeDirection
@ AURA_EFFECT_HANDLE_STAT
@ AURA_EFFECT_HANDLE_SEND_FOR_CLIENT
AuraRemoveMode
@ AURA_REMOVE_BY_CANCEL
@ AURA_REMOVE_NONE
@ AURA_REMOVE_BY_DEFAULT
@ AURA_REMOVE_BY_DEATH
@ AURA_REMOVE_BY_EXPIRE
@ AURA_REMOVE_BY_ENEMY_SPELL
@ AURA_REMOVE_BY_INTERRUPT
AuraType
@ SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
@ SPELL_AURA_MANA_SHIELD
@ SPELL_AURA_MOD_SCHOOL_MASK_DAMAGE_FROM_CASTER
@ SPELL_AURA_CLONE_CASTER
@ SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE
@ SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL
@ SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE
@ SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
@ SPELL_AURA_MOD_PERIODIC_DAMAGE_TAKEN
@ SPELL_AURA_PERIODIC_DAMAGE
@ SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
@ SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS
@ SPELL_AURA_MOD_AUTOATTACK_RANGE
@ SPELL_AURA_MOD_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_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_CRIT_CHANCE_VERSUS_TARGET_HEALTH
@ SPELL_AURA_CAST_WHILE_WALKING_BY_SPELL_LABEL
@ SPELL_AURA_LINKED
@ SPELL_AURA_TRIGGER_SPELL_ON_HEALTH_PCT
@ SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
@ SPELL_AURA_SHARE_DAMAGE_PCT
@ SPELL_AURA_CAST_WHILE_WALKING
@ SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
@ SPELL_AURA_MOD_HEALING_TAKEN_FROM_CASTER
@ SPELL_AURA_TRIGGER_SPELL_ON_POWER_AMOUNT
@ SPELL_AURA_CONTROL_VEHICLE
@ SPELL_AURA_IGNORE_HIT_DIRECTION
@ SPELL_AURA_IGNORE_COMBAT_RESULT
@ SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
@ SPELL_AURA_EMPATHY
@ SPELL_AURA_MOD_SPEED_NOT_STACK
@ SPELL_AURA_MOD_HEALING_DONE_PCT_VERSUS_TARGET_HEALTH
@ SPELL_AURA_MOD_STALKED
@ SPELL_AURA_SCHOOL_HEAL_ABSORB
@ SPELL_AURA_MOD_ROOT_2
@ SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED
@ SPELL_AURA_COSMETIC_MOUNTED
@ SPELL_AURA_BYPASS_ARMOR_FOR_CASTER
@ SPELL_AURA_MOD_HIT_CHANCE
@ SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
@ SPELL_AURA_PERIODIC_HEAL
@ SPELL_AURA_MOD_ENEMY_DODGE
@ SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE
@ SPELL_AURA_PERIODIC_DAMAGE_PERCENT
@ SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
@ SPELL_AURA_MOD_STUN_DISABLE_GRAVITY
@ SPELL_AURA_MOD_DODGE_PERCENT
@ SPELL_AURA_MOD_INCREASE_SWIM_SPEED
@ SPELL_AURA_SPLIT_DAMAGE_PCT
@ SPELL_AURA_SCHOOL_ABSORB_OVERKILL
@ SPELL_AURA_DEFLECT_SPELLS
@ SPELL_AURA_MOD_STAT
@ SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
@ SPELL_AURA_MOD_HEALING_DONE
@ SPELL_AURA_MOD_HEALING_RECEIVED
@ SPELL_AURA_MOD_HEALING_PCT
@ SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
@ SPELL_AURA_MOD_CHARM
@ SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT
@ SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER_PET
@ SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE
@ SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
@ SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_TRIGGERED
@ SPELL_AURA_MOD_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_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_DURABILITY_LOSS
@ SPELL_AURA_MOD_DAMAGE_TAKEN_FROM_CASTER_BY_LABEL
@ SPELL_AURA_PERIODIC_LEECH
@ SPELL_AURA_MOD_AUTOATTACK_CRIT_CHANCE
@ SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT
@ SPELL_AURA_MOD_PERCENT_STAT
@ 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_RANGED_DAMAGE_TAKEN_PCT
@ SPELL_AURA_MOD_MECHANIC_RESISTANCE
@ SPELL_AURA_MOD_UNATTACKABLE
@ SPELL_AURA_NONE
@ SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
@ SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
@ SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
@ SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
@ SPELL_AURA_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
SpellAuraInterruptFlags2
Definition: SpellDefines.h:117
@ PeriodicHealingAndDamage
@ CritDamageAndHealing
TriggerCastFlags
Definition: SpellDefines.h:245
@ TRIGGERED_IGNORE_POWER_AND_REAGENT_COST
Will ignore power and reagent cost.
Definition: SpellDefines.h:249
@ TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE
Will ignore mounted/on vehicle restrictions.
Definition: SpellDefines.h:260
@ TRIGGERED_IGNORE_GCD
Will ignore GCD.
Definition: SpellDefines.h:247
@ TRIGGERED_NONE
Not triggered.
Definition: SpellDefines.h:246
SpellValueMod
Definition: SpellDefines.h:195
@ SPELLVALUE_BASE_POINT0
Definition: SpellDefines.h:196
SpellAuraInterruptFlags
Definition: SpellDefines.h:76
std::vector< AuraEffect * > AuraEffectVector
Definition: SpellInfo.h:302
@ SPELL_ATTR0_CU_IGNORE_ARMOR
Definition: SpellInfo.h:163
@ SPELL_ATTR0_CU_ENCHANT_PROC
Definition: SpellInfo.h:148
@ SPELL_ATTR0_CU_CAN_CRIT
Definition: SpellInfo.h:155
@ SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET
Definition: SpellInfo.h:165
@ SPELL_ATTR0_CU_AURA_CC
Definition: SpellInfo.h:153
@ SPELL_ATTR0_CU_BINARY_SPELL
Definition: SpellInfo.h:168
@ SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC
Definition: SpellInfo.h:169
@ SPELL_SPECIFIC_MAGE_POLYMORPH
Definition: SpellInfo.h:130
#define MELEE_BASED_TRIGGER_MASK
Definition: SpellMgr.h:240
std::pair< SpellSpellGroupMap::const_iterator, SpellSpellGroupMap::const_iterator > SpellSpellGroupMapBounds
Definition: SpellMgr.h:375
ProcFlagsSpellPhase
Definition: SpellMgr.h:261
@ PROC_SPELL_PHASE_NONE
Definition: SpellMgr.h:262
@ PROC_SPELL_PHASE_HIT
Definition: SpellMgr.h:264
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT
Definition: SpellMgr.h:386
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST
Definition: SpellMgr.h:387
#define sSpellMgr
Definition: SpellMgr.h:849
ProcFlagsSpellType
Definition: SpellMgr.h:250
@ PROC_SPELL_TYPE_NONE
Definition: SpellMgr.h:251
@ PROC_SPELL_TYPE_MASK_ALL
Definition: SpellMgr.h:255
@ PROC_SPELL_TYPE_DAMAGE
Definition: SpellMgr.h:252
@ PROC_FLAG_MAIN_HAND_WEAPON_SWING
Definition: SpellMgr.h:171
@ PROC_FLAG_TAKE_MELEE_SWING
Definition: SpellMgr.h:141
@ PROC_FLAG_TAKE_ANY_DAMAGE
Definition: SpellMgr.h:167
@ PROC_FLAG_ENCOUNTER_START
Definition: SpellMgr.h:182
@ PROC_FLAG_DEAL_MELEE_SWING
Definition: SpellMgr.h:140
@ PROC_FLAG_TAKE_HARMFUL_SPELL
Definition: SpellMgr.h:162
@ PROC_FLAG_DEATH
Definition: SpellMgr.h:174
@ PROC_FLAG_OFF_HAND_WEAPON_SWING
Definition: SpellMgr.h:172
@ PROC_FLAG_ENTER_COMBAT
Definition: SpellMgr.h:180
@ PROC_FLAG_KILL
Definition: SpellMgr.h:138
@ PROC_FLAG_NONE
Definition: SpellMgr.h:135
@ PROC_FLAG_2_TARGET_DIES
Definition: SpellMgr.h:233
ProcFlagsHit
Definition: SpellMgr.h:272
@ PROC_HIT_BLOCK
Definition: SpellMgr.h:280
@ PROC_HIT_FULL_RESIST
Definition: SpellMgr.h:277
@ PROC_HIT_FULL_BLOCK
Definition: SpellMgr.h:287
@ PROC_HIT_MISS
Definition: SpellMgr.h:276
@ PROC_HIT_NONE
Definition: SpellMgr.h:273
@ PROC_HIT_DEFLECT
Definition: SpellMgr.h:283
@ PROC_HIT_EVADE
Definition: SpellMgr.h:281
@ PROC_HIT_DODGE
Definition: SpellMgr.h:278
@ PROC_HIT_IMMUNE
Definition: SpellMgr.h:282
@ PROC_HIT_ABSORB
Definition: SpellMgr.h:284
@ PROC_HIT_PARRY
Definition: SpellMgr.h:279
@ PROC_HIT_CRITICAL
Definition: SpellMgr.h:275
@ PROC_HIT_NORMAL
Definition: SpellMgr.h:274
@ PROC_HIT_REFLECT
Definition: SpellMgr.h:285
SpellOtherImmunity
Definition: SpellMgr.h:599
@ SPELL_CAST_SOURCE_NORMAL
Definition: Spell.h:146
@ SPELL_STATE_DELAYED
Definition: Spell.h:239
@ SPELL_STATE_FINISHED
Definition: Spell.h:237
@ SPELL_STATE_PREPARING
Definition: Spell.h:235
@ SPELL_STATE_CASTING
Definition: Spell.h:236
@ SPELL_STATE_IDLE
Definition: Spell.h:238
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition: Timer.h:57
uint32 getMSTime()
Definition: Timer.h:33
@ TOTEM_PASSIVE
Definition: Totem.h:25
UnitMoveType
Definition: UnitDefines.h:116
@ MOVE_FLIGHT
Definition: UnitDefines.h:123
@ MOVE_SWIM
Definition: UnitDefines.h:120
@ MOVE_FLIGHT_BACK
Definition: UnitDefines.h:124
@ MOVE_SWIM_BACK
Definition: UnitDefines.h:121
@ MOVE_RUN
Definition: UnitDefines.h:118
@ MOVE_RUN_BACK
Definition: UnitDefines.h:119
@ MOVE_WALK
Definition: UnitDefines.h:117
@ UNIT_FLAG2_AI_WILL_ONLY_SWIM_IF_TARGET_SWIMS
Definition: UnitDefines.h:218
@ UNIT_FLAG2_INTERACT_WHILE_HOSTILE
Definition: UnitDefines.h:208
@ UNIT_FLAG2_CANNOT_TURN
Definition: UnitDefines.h:209
@ UNIT_FLAG2_DISARM_OFFHAND
Definition: UnitDefines.h:201
@ UNIT_FLAG2_DISARM_RANGED
Definition: UnitDefines.h:204
HitInfo
Definition: UnitDefines.h:447
@ HITINFO_PARTIAL_ABSORB
Definition: UnitDefines.h:455
@ HITINFO_FULL_RESIST
Definition: UnitDefines.h:456
@ HITINFO_NORMALSWING
Definition: UnitDefines.h:448
@ HITINFO_BLOCK
Definition: UnitDefines.h:462
@ HITINFO_CRUSHING
Definition: UnitDefines.h:466
@ HITINFO_FAKE_DAMAGE
Definition: UnitDefines.h:473
@ HITINFO_SWINGNOHITSOUND
Definition: UnitDefines.h:470
@ HITINFO_MISS
Definition: UnitDefines.h:453
@ HITINFO_FULL_ABSORB
Definition: UnitDefines.h:454
@ HITINFO_NO_ANIMATION
Definition: UnitDefines.h:467
@ HITINFO_OFFHAND
Definition: UnitDefines.h:451
@ HITINFO_GLANCING
Definition: UnitDefines.h:465
@ HITINFO_CRITICALHIT
Definition: UnitDefines.h:458
@ HITINFO_PARTIAL_RESIST
Definition: UnitDefines.h:457
@ HITINFO_AFFECTS_VICTIM
Definition: UnitDefines.h:450
@ REACT_PASSIVE
Definition: UnitDefines.h:506
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
@ MOVEMENTFLAG_FORWARD
Definition: UnitDefines.h:358
@ MOVEMENTFLAG_WATERWALKING
Definition: UnitDefines.h:384
@ MOVEMENTFLAG_MASK_MOVING
Definition: UnitDefines.h:389
@ MOVEMENTFLAG_DISABLE_GRAVITY
Definition: UnitDefines.h:367
@ MOVEMENTFLAG_FALLING_SLOW
Definition: UnitDefines.h:385
@ MOVEMENTFLAG_CAN_FLY
Definition: UnitDefines.h:381
@ MOVEMENTFLAG_ROOT
Definition: UnitDefines.h:368
@ MOVEMENTFLAG_FALLING
Definition: UnitDefines.h:369
@ MOVEMENTFLAG_MASK_MOVING_FLY
Definition: UnitDefines.h:396
@ MOVEMENTFLAG_FALLING_FAR
Definition: UnitDefines.h:370
@ MOVEMENTFLAG_SWIMMING
Definition: UnitDefines.h:378
@ MOVEMENTFLAG_HOVER
Definition: UnitDefines.h:386
@ MOVEMENTFLAG_SPLINE_ELEVATION
Definition: UnitDefines.h:383
@ MOVEMENTFLAG_WALKING
Definition: UnitDefines.h:366
@ MOVEMENTFLAG_DISABLE_COLLISION
Definition: UnitDefines.h:387
#define MAX_MOVE_TYPE
Definition: UnitDefines.h:128
@ MOVEMENTFLAG2_CAN_DOUBLE_JUMP
Definition: UnitDefines.h:429
@ MOVEMENTFLAG2_CAN_SWIM_TO_FLY_TRANS
Definition: UnitDefines.h:425
@ MOVEMENTFLAG2_CAN_TURN_WHILE_FALLING
Definition: UnitDefines.h:427
@ MOVEMENTFLAG2_IGNORE_MOVEMENT_FORCES
Definition: UnitDefines.h:428
#define MAX_DECLINED_NAME_CASES
Definition: UnitDefines.h:484
@ UNIT_NPC_FLAG_TABARDDESIGNER
Definition: UnitDefines.h:316
@ UNIT_NPC_FLAG_SPIRIT_HEALER
Definition: UnitDefines.h:311
@ UNIT_NPC_FLAG_BANKER
Definition: UnitDefines.h:314
@ UNIT_NPC_FLAG_AUCTIONEER
Definition: UnitDefines.h:318
@ UNIT_NPC_FLAG_AREA_SPIRIT_HEALER
Definition: UnitDefines.h:312
@ UNIT_NPC_FLAG_VENDOR
Definition: UnitDefines.h:304
@ UNIT_NPC_FLAG_BATTLEMASTER
Definition: UnitDefines.h:317
@ UNIT_NPC_FLAG_INNKEEPER
Definition: UnitDefines.h:313
@ UNIT_NPC_FLAG_SPELLCLICK
Definition: UnitDefines.h:321
@ UNIT_NPC_FLAG_PLAYER_VEHICLE
Definition: UnitDefines.h:322
@ UNIT_NPC_FLAG_FLIGHTMASTER
Definition: UnitDefines.h:310
@ UNIT_NPC_FLAG_TRAINER
Definition: UnitDefines.h:301
@ UNIT_NPC_FLAG_PETITIONER
Definition: UnitDefines.h:315
DamageEffectType
Definition: UnitDefines.h:131
@ SELF_DAMAGE
Definition: UnitDefines.h:137
@ DIRECT_DAMAGE
Definition: UnitDefines.h:132
@ NODAMAGE
Definition: UnitDefines.h:136
@ DOT
Definition: UnitDefines.h:134
@ SPELL_DIRECT_DAMAGE
Definition: UnitDefines.h:133
#define BASE_MAXDAMAGE
Definition: UnitDefines.h:34
@ UNIT_FLAG3_ALLOW_INTERACTION_WHILE_IN_COMBAT
Definition: UnitDefines.h:266
SheathState
Definition: UnitDefines.h:81
@ SHEATH_STATE_UNARMED
Definition: UnitDefines.h:82
@ MOVEMENTFLAG3_DISABLE_INERTIA
Definition: UnitDefines.h:441
#define MAX_EQUIPMENT_ITEMS
Definition: UnitDefines.h:37
@ UNIT_BYTE2_FLAG_PVP
Definition: UnitDefines.h:93
@ UNIT_BYTE2_FLAG_NONE
Definition: UnitDefines.h:92
AnimTier
Definition: UnitDefines.h:69
@ COMMAND_FOLLOW
Definition: UnitDefines.h:527
#define BASE_MINDAMAGE
Definition: UnitDefines.h:33
@ UNIT_FLAG_STUNNED
Definition: UnitDefines.h:162
@ UNIT_FLAG_NON_ATTACKABLE
Definition: UnitDefines.h:145
@ UNIT_FLAG_IMMUNE_TO_NPC
Definition: UnitDefines.h:153
@ UNIT_FLAG_POSSESSED
Definition: UnitDefines.h:168
@ UNIT_FLAG_DISARMED
Definition: UnitDefines.h:165
@ UNIT_FLAG_PACIFIED
Definition: UnitDefines.h:161
@ UNIT_FLAG_CAN_SWIM
Definition: UnitDefines.h:159
@ UNIT_FLAG_REMOVE_CLIENT_CONTROL
Definition: UnitDefines.h:146
@ UNIT_FLAG_FLEEING
Definition: UnitDefines.h:167
@ UNIT_FLAG_CANT_SWIM
Definition: UnitDefines.h:158
@ UNIT_FLAG_RENAME
Definition: UnitDefines.h:148
@ UNIT_FLAG_UNINTERACTIBLE
Definition: UnitDefines.h:169
@ UNIT_FLAG_IMMUNE_TO_PC
Definition: UnitDefines.h:152
@ UNIT_FLAG_PLAYER_CONTROLLED
Definition: UnitDefines.h:147
@ UNIT_FLAG_SKINNABLE
Definition: UnitDefines.h:170
@ UNIT_FLAG_MOUNT
Definition: UnitDefines.h:171
@ UNIT_FLAG_PET_IN_COMBAT
Definition: UnitDefines.h:155
float baseMoveSpeed[MAX_MOVE_TYPE]
Definition: Unit.cpp:97
ProcFlagsHit createProcHitMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
Definition: Unit.cpp:9776
bool IsInterruptFlagIgnoredForSpell(InterruptFlag, Unit const *, SpellInfo const *, SpellInfo const *)
Definition: Unit.cpp:4070
void ApplyPercentModFloatVar(float &var, float val, bool apply)
Definition: Unit.cpp:10330
float playerBaseMoveSpeed[MAX_MOVE_TYPE]
Definition: Unit.cpp:110
UnitModifierFlatType
Definition: Unit.h:151
@ BASE_VALUE
Definition: Unit.h:152
@ MODIFIER_TYPE_FLAT_END
Definition: Unit.h:155
@ TOTAL_VALUE
Definition: Unit.h:154
@ BASE_PCT_EXCLUDE_CREATE
Definition: Unit.h:153
std::unordered_multimap< uint32, uint32 > SpellImmuneContainer
Definition: Unit.h:148
@ UNIT_MASK_NONE
Definition: Unit.h:349
@ UNIT_MASK_CONTROLABLE_GUARDIAN
Definition: Unit.h:358
@ UNIT_MASK_ACCESSORY
Definition: Unit.h:359
@ UNIT_MASK_VEHICLE
Definition: Unit.h:355
@ UNIT_MASK_GUARDIAN
Definition: Unit.h:352
@ UNIT_MASK_MINION
Definition: Unit.h:351
VictimState
Definition: Unit.h:47
@ VICTIMSTATE_INTACT
Definition: Unit.h:48
@ VICTIMSTATE_HIT
Definition: Unit.h:49
@ VICTIMSTATE_DODGE
Definition: Unit.h:50
@ VICTIMSTATE_IS_IMMUNE
Definition: Unit.h:55
@ VICTIMSTATE_PARRY
Definition: Unit.h:51
@ VICTIMSTATE_BLOCKS
Definition: Unit.h:53
@ VICTIMSTATE_EVADES
Definition: Unit.h:54
WeaponDamageRange
Definition: Unit.h:166
@ MINDAMAGE
Definition: Unit.h:167
@ MAXDAMAGE
Definition: Unit.h:168
UnitMods
Definition: Unit.h:172
@ UNIT_MOD_DAMAGE_OFFHAND
Definition: Unit.h:214
@ UNIT_MOD_COMBO_POINTS
Definition: Unit.h:182
@ UNIT_MOD_STAT_INTELLECT
Definition: Unit.h:176
@ UNIT_MOD_ARMOR
Definition: Unit.h:204
@ UNIT_MOD_RESISTANCE_SHADOW
Definition: Unit.h:209
@ UNIT_MOD_RESISTANCE_FROST
Definition: Unit.h:208
@ UNIT_MOD_END
Definition: Unit.h:216
@ UNIT_MOD_ATTACK_POWER
Definition: Unit.h:211
@ UNIT_MOD_RESISTANCE_HOLY
Definition: Unit.h:205
@ UNIT_MOD_RESISTANCE_START
Definition: Unit.h:220
@ UNIT_MOD_SOUL_SHARDS
Definition: Unit.h:185
@ UNIT_MOD_RESISTANCE_ARCANE
Definition: Unit.h:210
@ UNIT_MOD_ESSENCE
Definition: Unit.h:197
@ UNIT_MOD_ARCANE_CHARGES
Definition: Unit.h:194
@ UNIT_MOD_ENERGY
Definition: Unit.h:181
@ UNIT_MOD_HEALTH
Definition: Unit.h:177
@ UNIT_MOD_RUNES
Definition: Unit.h:183
@ UNIT_MOD_DAMAGE_RANGED
Definition: Unit.h:215
@ UNIT_MOD_HOLY_POWER
Definition: Unit.h:187
@ UNIT_MOD_PAIN
Definition: Unit.h:196
@ UNIT_MOD_BURNING_EMBERS
Definition: Unit.h:192
@ UNIT_MOD_RUNE_UNHOLY
Definition: Unit.h:200
@ UNIT_MOD_POWER_START
Definition: Unit.h:222
@ UNIT_MOD_RUNE_BLOOD
Definition: Unit.h:198
@ UNIT_MOD_CHI
Definition: Unit.h:190
@ UNIT_MOD_RESISTANCE_FIRE
Definition: Unit.h:206
@ UNIT_MOD_STAT_STRENGTH
Definition: Unit.h:173
@ UNIT_MOD_RUNE_FROST
Definition: Unit.h:199
@ UNIT_MOD_FURY
Definition: Unit.h:195
@ UNIT_MOD_ALTERNATE
Definition: Unit.h:188
@ UNIT_MOD_RESISTANCE_NATURE
Definition: Unit.h:207
@ UNIT_MOD_ALTERNATE_ENCOUNTER
Definition: Unit.h:202
@ UNIT_MOD_LUNAR_POWER
Definition: Unit.h:186
@ UNIT_MOD_MAELSTROM
Definition: Unit.h:189
@ UNIT_MOD_DEMONIC_FURY
Definition: Unit.h:193
@ UNIT_MOD_ALTERNATE_QUEST
Definition: Unit.h:201
@ UNIT_MOD_STAT_AGILITY
Definition: Unit.h:174
@ UNIT_MOD_ALTERNATE_MOUNT
Definition: Unit.h:203
@ UNIT_MOD_INSANITY
Definition: Unit.h:191
@ UNIT_MOD_FOCUS
Definition: Unit.h:180
@ UNIT_MOD_DAMAGE_MAINHAND
Definition: Unit.h:213
@ UNIT_MOD_MANA
Definition: Unit.h:178
@ UNIT_MOD_STAT_START
Definition: Unit.h:218
@ UNIT_MOD_RAGE
Definition: Unit.h:179
@ UNIT_MOD_STAT_STAMINA
Definition: Unit.h:175
@ UNIT_MOD_RUNIC_POWER
Definition: Unit.h:184
@ UNIT_MOD_ATTACK_POWER_RANGED
Definition: Unit.h:212
DeathState
Definition: Unit.h:245
@ CORPSE
Definition: Unit.h:248
@ DEAD
Definition: Unit.h:249
@ ALIVE
Definition: Unit.h:246
@ JUST_RESPAWNED
Definition: Unit.h:250
@ JUST_DIED
Definition: Unit.h:247
#define CURRENT_FIRST_NON_MELEE_SPELL
Definition: Unit.h:595
CurrentSpellTypes
Definition: Unit.h:588
@ CURRENT_CHANNELED_SPELL
Definition: Unit.h:591
@ CURRENT_GENERIC_SPELL
Definition: Unit.h:590
@ CURRENT_MELEE_SPELL
Definition: Unit.h:589
@ CURRENT_AUTOREPEAT_SPELL
Definition: Unit.h:592
UnitState
Definition: Unit.h:254
@ UNIT_STATE_DISTRACTED
Definition: Unit.h:267
@ UNIT_STATE_DIED
Definition: Unit.h:255
@ UNIT_STATE_ATTACK_PLAYER
Definition: Unit.h:269
@ UNIT_STATE_POSSESSED
Definition: Unit.h:271
@ UNIT_STATE_UNATTACKABLE
Definition: Unit.h:293
@ UNIT_STATE_LOST_CONTROL
Definition: Unit.h:296
@ UNIT_STATE_CANNOT_AUTOATTACK
Definition: Unit.h:297
@ UNIT_STATE_CONFUSED
Definition: Unit.h:266
@ UNIT_STATE_ROOT
Definition: Unit.h:265
@ UNIT_STATE_CHARGING
Definition: Unit.h:272
@ UNIT_STATE_CONTROLLED
Definition: Unit.h:295
@ UNIT_STATE_FLEEING
Definition: Unit.h:262
@ UNIT_STATE_CANNOT_TURN
Definition: Unit.h:299
@ UNIT_STATE_MOVING
Definition: Unit.h:294
@ UNIT_STATE_MOVE
Definition: Unit.h:275
@ UNIT_STATE_MELEE_ATTACKING
Definition: Unit.h:256
@ UNIT_STATE_IN_FLIGHT
Definition: Unit.h:263
@ UNIT_STATE_FOCUSING
Definition: Unit.h:261
@ UNIT_STATE_CASTING
Definition: Unit.h:270
@ UNIT_STATE_STUNNED
Definition: Unit.h:258
@ UNIT_STATE_CHARMED
Definition: Unit.h:257
MeleeHitOutcome
Definition: Unit.h:379
@ MELEE_HIT_CRUSHING
Definition: Unit.h:381
@ MELEE_HIT_BLOCK
Definition: Unit.h:380
@ MELEE_HIT_CRIT
Definition: Unit.h:381
@ MELEE_HIT_NORMAL
Definition: Unit.h:381
@ MELEE_HIT_EVADE
Definition: Unit.h:380
@ MELEE_HIT_DODGE
Definition: Unit.h:380
@ MELEE_HIT_MISS
Definition: Unit.h:380
@ MELEE_HIT_PARRY
Definition: Unit.h:380
@ MELEE_HIT_GLANCING
Definition: Unit.h:381
#define MAX_AGGRO_RESET_TIME
Definition: Unit.h:43
#define ATTACK_DISPLAY_DELAY
Definition: Unit.h:623
std::vector< DispelableAura > DispelChargesList
Definition: Unit.h:146
#define CURRENT_MAX_SPELL
Definition: Unit.h:596
CombatRating
Definition: Unit.h:310
@ CR_VERSATILITY_DAMAGE_TAKEN
Definition: Unit.h:341
@ CR_ARMOR_PENETRATION
Definition: Unit.h:335
@ CR_VERSATILITY_DAMAGE_DONE
Definition: Unit.h:339
ReactiveType
Definition: Unit.h:604
@ MAX_REACTIVE
Definition: Unit.h:607
@ REACTIVE_DEFENSE
Definition: Unit.h:605
@ REACTIVE_DEFENSE_2
Definition: Unit.h:606
#define ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE
Definition: Unit.h:37
UnitModifierPctType
Definition: Unit.h:159
@ MODIFIER_TYPE_PCT_END
Definition: Unit.h:162
@ TOTAL_PCT
Definition: Unit.h:161
@ BASE_PCT
Definition: Unit.h:160
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:491
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:35
uint32 GetSpellId() const
Definition: AreaTrigger.h:99
Unit * GetTarget() const
Definition: SpellAuras.h:77
void SetRemoveMode(AuraRemoveMode mode)
Definition: SpellAuras.h:90
bool IsPositive() const
Definition: SpellAuras.h:84
void _HandleEffect(uint8 effIndex, bool apply)
Definition: SpellAuras.cpp:156
Aura * GetBase() const
Definition: SpellAuras.h:78
uint8 GetSlot() const
Definition: SpellAuras.h:80
uint32 GetEffectMask() const
Definition: SpellAuras.h:82
AuraRemoveMode GetRemoveMode() const
Definition: SpellAuras.h:91
bool HasEffect(uint8 effect) const
Definition: SpellAuras.h:83
SpellInfo const * GetSpellInfo() const
AuraType GetAuraType() const
void HandleEffect(AuraApplication *aurApp, uint8 mode, bool apply, AuraEffect const *triggeredBy=nullptr)
bool CanBeRecalculated() const
SpellEffectInfo const & GetSpellEffectInfo() const
uint32 GetId() const
bool IsAffectingSpell(SpellInfo const *spell) const
void ChangeAmount(int32 newAmount, bool mark=true, bool onStackOrReapply=false, AuraEffect const *triggeredBy=nullptr)
int32 GetMiscValueB() const
Unit * GetCaster() const
int32 GetMiscValue() const
Aura * GetBase() const
int32 const m_baseAmount
int32 GetBaseAmount() const
ObjectGuid GetCasterGUID() const
int32 GetAmount() const
bool HasMoreThanOneEffectForType(AuraType auraType) const
virtual void _UnapplyForTarget(Unit *target, Unit *caster, AuraApplication *auraApp)
Definition: SpellAuras.cpp:562
void CallScriptEffectCalcCritChanceHandlers(AuraEffect const *aurEff, AuraApplication const *aurApp, Unit const *victim, float &critChance)
ObjectGuid GetCastId() const
Definition: SpellAuras.h:138
bool IsArea() const
int32 GetMaxDuration() const
Definition: SpellAuras.h:168
void CallScriptEffectAbsorbHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount, bool &defaultPrevented)
virtual std::string GetDebugInfo() const
void CallScriptDispel(DispelInfo *dispelInfo)
static Aura * TryRefreshStackOrCreate(AuraCreateInfo &createInfo, bool updateEffectMask=true)
Definition: SpellAuras.cpp:337
ApplicationMap const & GetApplicationMap()
Definition: SpellAuras.h:234
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:147
AuraApplication const * GetApplicationOfTarget(ObjectGuid guid) const
ObjectGuid GetCasterGUID() const
Definition: SpellAuras.h:139
bool HasEffect(uint8 effIndex) const
Definition: SpellAuras.h:225
AuraEffectVector const & GetAuraEffects() const
Definition: SpellAuras.h:308
bool IsRemoved() const
Definition: SpellAuras.h:205
WorldObject * GetOwner() const
Definition: SpellAuras.h:146
bool ModCharges(int32 num, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: SpellAuras.cpp:973
bool CanStackWith(Aura const *existingAura) const
uint32 GetId() const
Definition: SpellAuras.h:135
int32 CalcDispelChance(Unit const *auraTarget, bool offensive) const
bool IsAppliedOnTarget(ObjectGuid guid) const
int32 GetDuration() const
Definition: SpellAuras.h:173
void UpdateOwner(uint32 diff, WorldObject *owner)
Definition: SpellAuras.cpp:773
void UnregisterSingleTarget()
bool IsDeathPersistent() const
AuraEffect * GetEffect(uint32 index) const
Definition: SpellAuras.cpp:529
Unit * GetCaster() const
Definition: SpellAuras.cpp:513
void SetNeedClientUpdateForTargets() const
void CallScriptEnterLeaveCombatHandlers(AuraApplication const *aurApp, bool isNowInCombat)
bool ModStackAmount(int32 num, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, bool resetPeriodicTimer=true)
void SetDuration(int32 duration, bool withMods=false)
Definition: SpellAuras.cpp:892
void CallScriptEffectAfterAbsorbHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount)
void CallScriptEffectManaShieldHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount, bool &defaultPrevented)
AuraObjectType GetType() const
Definition: SpellAuras.cpp:537
uint8 GetStackAmount() const
Definition: SpellAuras.h:189
uint8 GetCharges() const
Definition: SpellAuras.h:180
SpellInfo const * GetSpellInfo() const
Definition: SpellAuras.h:134
ObjectGuid GetCastItemGUID() const
Definition: SpellAuras.h:140
uint32 GetEffectMask() const
void HandleAuraSpecificMods(AuraApplication const *aurApp, Unit *caster, bool apply, bool onReapply)
Difficulty GetCastDifficulty() const
Definition: SpellAuras.h:136
void SetIsSingleTarget(bool val)
Definition: SpellAuras.h:209
virtual void _ApplyForTarget(Unit *target, Unit *caster, AuraApplication *auraApp)
Definition: SpellAuras.cpp:542
bool IsPassive() const
std::unordered_map< ObjectGuid, AuraApplication * > ApplicationMap
Definition: SpellAuras.h:123
void CallScriptEffectAfterManaShieldHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount)
virtual void Remove(AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)=0
void CallScriptAfterDispel(DispelInfo *dispelInfo)
void _Remove(AuraRemoveMode removeMode)
Definition: SpellAuras.cpp:592
bool IsSingleTarget() const
Definition: SpellAuras.h:207
size_t wpos() const
Definition: ByteBuffer.h:412
void put(std::size_t pos, T value)
Definition: ByteBuffer.h:220
void SuppressPvPCombat(UnitFilter *unitFilter=nullptr)
void EndAllPvECombat(UnitFilter *unitFilter=nullptr)
std::unordered_map< ObjectGuid, PvPCombatReference * > const & GetPvPCombatRefs() const
void RevalidateCombat()
void Update(uint32 tdiff)
bool HasPvECombat() const
std::unordered_map< ObjectGuid, CombatReference * > const & GetPvECombatRefs() const
void EndAllCombat(UnitFilter *unitFilter=nullptr)
bool HasPvPCombat() const
void EndAllPvPCombat(UnitFilter *unitFilter=nullptr)
static bool IsPlayerMeetingCondition(Player const *player, PlayerConditionEntry const *condition)
virtual void JustUnregisteredDynObject(DynamicObject *)
Definition: CreatureAI.h:123
virtual void JustSummonedGameobject(GameObject *)
Definition: CreatureAI.h:118
virtual void OnSpellClick(Unit *, bool)
Definition: CreatureAI.h:222
virtual void SummonedGameobjectDespawn(GameObject *)
Definition: CreatureAI.h:119
virtual void OnSpellFailed(SpellInfo const *)
Definition: CreatureAI.h:139
virtual void JustUnregisteredAreaTrigger(AreaTrigger *)
Definition: CreatureAI.h:127
virtual void KilledUnit(Unit *)
Definition: CreatureAI.h:108
virtual void JustRegisteredAreaTrigger(AreaTrigger *)
Definition: CreatureAI.h:126
virtual void JustRegisteredDynObject(DynamicObject *)
Definition: CreatureAI.h:122
bool IsTreatedAsRaidUnit() const
Definition: Creature.h:221
bool isWorldBoss() const
Definition: Creature.cpp:2484
CreatureDifficulty const * GetCreatureDifficulty() const
Definition: Creature.h:252
uint16 GetLootMode() const
Definition: Creature.h:295
std::unordered_map< ObjectGuid, std::unique_ptr< Loot > > m_personalLoot
Definition: Creature.h:278
void SetLastDamagedTime(time_t val)
Definition: Creature.h:427
bool IsEvadingAttacks() const
Definition: Creature.h:204
uint8 GetLevelForTarget(WorldObject const *target) const override
Definition: Creature.cpp:3104
void AllLootRemovedFromCorpse()
Definition: Creature.cpp:2958
bool CanHaveLoot() const
Definition: Creature.h:273
GuidUnorderedSet const & GetTapList() const
Definition: Creature.h:282
void SetTappedBy(Unit const *unit, bool withGroup=true)
Definition: Creature.cpp:1339
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
Definition: Creature.cpp:2415
float GetSpellDamageMod(CreatureClassifications classification) const
Definition: Creature.cpp:1709
CreatureTemplate const * GetCreatureTemplate() const
Definition: Creature.h:250
uint32 GetLootId() const
Definition: Creature.cpp:1326
CreatureGroup * GetFormation()
Definition: Creature.h:391
bool CannotPenetrateWater() const
Definition: Creature.h:136
bool CanEnterWater() const override
Definition: Creature.h:146
void SetDisplayId(uint32 displayId, bool setNative=false) override
Definition: Creature.cpp:3402
void LowerPlayerDamageReq(uint64 unDamage)
Definition: Creature.cpp:1680
bool HasFlag(CreatureStaticFlags flag) const
Definition: Creature.h:454
bool IsFullyLooted() const
Definition: Creature.cpp:1397
void SendAIReaction(AiReaction reactionType)
Definition: Creature.cpp:2521
bool IsAquatic() const
Definition: Creature.h:122
void CallAssistance()
Definition: Creature.cpp:2533
bool IsInEvadeMode() const
Definition: Creature.h:203
CreatureAI * AI() const
Definition: Creature.h:214
static char const * GetBroadcastTextValue(BroadcastTextEntry const *broadcastText, LocaleConstant locale=DEFAULT_LOCALE, uint8 gender=GENDER_MALE, bool forceGender=false)
Definition: DB2Stores.cpp:2008
static bool IsInArea(uint32 objectAreaId, uint32 areaId)
Definition: DB2Stores.cpp:1907
std::set< MountTypeXCapabilityEntry const *, MountTypeXCapabilityEntryComparator > MountTypeXCapabilitySet
Definition: DB2Stores.h:408
void ResistDamage(uint32 amount)
Definition: Unit.cpp:219
void AbsorbDamage(uint32 amount)
Definition: Unit.cpp:211
ProcFlagsHit m_hitMask
Definition: Unit.h:429
uint32 m_resist
Definition: Unit.h:427
void ModifyDamage(int32 amount)
Definition: Unit.cpp:205
Unit * GetVictim() const
Definition: Unit.h:441
Unit * GetAttacker() const
Definition: Unit.h:440
DamageInfo(Unit *attacker, Unit *victim, uint32 damage, SpellInfo const *spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType)
Definition: Unit.cpp:135
uint32 GetOriginalDamage() const
Definition: Unit.h:447
uint32 m_block
Definition: Unit.h:428
SpellInfo const * GetSpellInfo() const
Definition: Unit.h:442
void BlockDamage(uint32 amount)
Definition: Unit.cpp:231
WeaponAttackType GetAttackType() const
Definition: Unit.h:445
uint32 GetResist() const
Definition: Unit.h:449
SpellSchoolMask GetSchoolMask() const
Definition: Unit.h:443
uint32 m_absorb
Definition: Unit.h:426
uint32 m_damage
Definition: Unit.h:420
ProcFlagsHit GetHitMask() const
Definition: Unit.cpp:244
uint32 GetDamage() const
Definition: Unit.h:446
uint32 GetAbsorb() const
Definition: Unit.h:448
uint8 GetRemovedCharges() const
Definition: Unit.h:392
bool RollDispel() const
Definition: Unit.cpp:130
int32 _chance
Definition: Unit.h:143
DispelableAura(Aura *aura, int32 dispelChance, uint8 dispelCharges)
Definition: Unit.cpp:123
uint32 GetSpellId() const
Definition: DynamicObject.h:79
constexpr bool HasFlag(T flag) const
Definition: EnumFlag.h:106
void KillAllEvents(bool force)
std::multimap< uint64, BasicEvent * > const & GetEvents() const
T_VALUES GetValue(FLAG_TYPE flag) const
Definition: Object.h:445
void SetValue(FLAG_TYPE flag, T_VALUES value)
Definition: Object.h:446
ObjectGuid GetOwnerGUID() const override
Definition: GameObject.h:242
uint32 GetSpellId() const
Definition: GameObject.h:249
void Delete()
void SetOwnerGUID(ObjectGuid owner)
Definition: GameObject.h:232
void SetRespawnTime(int32 respawn)
GroupReference * next()
Definition: Group.h:197
uint32 GetMembersCount() const
Definition: Group.h:327
ObjectGuid GetLooterGuid() const
Definition: Group.cpp:1678
GroupReference * GetFirstMember()
Definition: Group.h:325
bool InitStatsForLevel(uint8 level)
Definition: Pet.cpp:840
Definition: Unit.h:456
uint32 _heal
Definition: Unit.h:460
Unit * GetHealer() const
Definition: Unit.h:474
uint32 _effectiveHeal
Definition: Unit.h:462
uint32 GetAbsorb() const
Definition: Unit.h:479
uint32 GetEffectiveHeal() const
Definition: Unit.h:478
SpellInfo const * GetSpellInfo() const
Definition: Unit.h:480
uint32 _absorb
Definition: Unit.h:463
uint32 GetHitMask() const
Definition: Unit.cpp:264
uint32 GetOriginalHeal() const
Definition: Unit.h:477
void SetEffectiveHeal(uint32 amount)
Definition: Unit.h:472
SpellSchoolMask GetSchoolMask() const
Definition: Unit.h:481
void AbsorbHeal(uint32 amount)
Definition: Unit.cpp:254
Unit * GetTarget() const
Definition: Unit.h:475
HealInfo(Unit *healer, Unit *target, uint32 heal, SpellInfo const *spellInfo, SpellSchoolMask schoolMask)
Definition: Unit.cpp:249
uint32 GetHeal() const
Definition: Unit.h:476
uint32 _hitMask
Definition: Unit.h:466
Definition: Item.h:170
ItemTemplate const * GetTemplate() const
Definition: Item.cpp:1141
bool IsBroken() const
Definition: Item.h:257
bool HaveLootFor(uint32 loot_id) const
Definition: LootMgr.h:83
bool IsDungeon() const
Definition: Map.cpp:3238
void CreatureRelocation(Creature *creature, float x, float y, float z, float ang, bool respawnRelocationOnFail=true)
Definition: Map.cpp:1080
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:1726
MapDifficultyEntry const * GetMapDifficulty() const
Definition: Map.cpp:3223
float GetWaterOrGroundLevel(PhaseShift const &phaseShift, float x, float y, float z, float *ground=nullptr, bool swim=false, float collisionHeight=2.03128f)
Definition: Map.cpp:1777
BattlegroundMap * ToBattlegroundMap()
Definition: Map.h:457
Difficulty GetDifficultyID() const
Definition: Map.h:324
MapEntry const * GetEntry() const
Definition: Map.h:195
void PlayerRelocation(Player *, float x, float y, float z, float orientation)
Definition: Map.cpp:1053
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)
void MoveJump(Position const &pos, float speedXY, float speedZ, uint32 id=EVENT_JUMP, bool hasOrientation=false, JumpArrivalCastArgs const *arrivalCast=nullptr, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
MovementGeneratorType GetCurrentMovementGeneratorType() const
void MoveFleeing(Unit *enemy, Milliseconds time=0ms)
void PropagateSpeedChange()
void MoveConfused()
void MoveKnockbackFrom(Position const &origin, float speedXY, float speedZ, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
void MoveTargetedHome()
void MoveJumpTo(float angle, float speedXY, float speedZ)
void Remove(MovementGenerator *movement, MovementSlot slot=MOTION_SLOT_ACTIVE)
void InitializeDefault()
void MoveTo(Vector3 const &destination, bool generatePath=true, bool forceDestination=false)
void DisableTransportPathTransformations()
void SetFacing(float angle)
LowType GetCounter() const
Definition: ObjectGuid.h:293
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
bool IsEmpty() const
Definition: ObjectGuid.h:319
bool IsMOTransport() const
Definition: ObjectGuid.h:333
bool IsPlayer() const
Definition: ObjectGuid.h:326
std::string ToString() const
Definition: ObjectGuid.cpp:554
static CreatureModel const * ChooseDisplayId(CreatureTemplate const *cinfo, CreatureData const *data=nullptr)
Definition: ObjectMgr.cpp:1616
void SetDynamicFlag(uint32 flag)
Definition: Object.h:169
uint16 m_objectType
Definition: Object.h:401
static Creature * ToCreature(Object *o)
Definition: Object.h:219
bool IsPlayer() const
Definition: Object.h:212
float GetObjectScale() const
Definition: Object.h:164
static Unit * ToUnit(Object *o)
Definition: Object.h:225
Player * ToPlayer()
Definition: Object.h:215
ObjectGuid const & GetGUID() const
Definition: Object.h:160
bool IsInWorld() const
Definition: Object.h:154
UF::UpdateField< UF::ObjectData, 0, TYPEID_OBJECT > m_objectData
Definition: Object.h:267
bool HasDynamicFlag(uint32 flag) const
Definition: Object.h:168
void RemoveUpdateFieldFlagValue(UF::UpdateFieldSetter< T > setter, typename UF::UpdateFieldSetter< T >::value_type flag)
Definition: Object.h:301
void BuildValuesUpdateBlockForPlayerWithFlag(UpdateData *data, UF::UpdateFieldFlag flags, Player const *target) const
Definition: Object.cpp:206
TypeID GetTypeId() const
Definition: Object.h:173
virtual void DestroyForPlayer(Player *target) const
Definition: Object.cpp:233
CreateObjectBits m_updateFlag
Definition: Object.h:404
void SetUpdateFieldFlagValue(UF::UpdateFieldSetter< T > setter, typename UF::UpdateFieldSetter< T >::value_type flag)
Definition: Object.h:294
virtual void ClearUpdateMask(bool remove)
Definition: Object.cpp:790
void SetUpdateFieldValue(UF::UpdateFieldSetter< T > setter, typename UF::UpdateFieldSetter< T >::value_type value)
Definition: Object.h:287
uint32 GetEntry() const
Definition: Object.h:161
bool IsCreature() const
Definition: Object.h:218
UF::UpdateFieldHolder m_values
Definition: Object.h:266
Creature * ToCreature()
Definition: Object.h:221
ByteBuffer & PrepareValuesUpdateBuffer(UpdateData *data) const
Definition: Object.cpp:225
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
virtual void SetObjectScale(float scale)
Definition: Object.h:165
void ForceUpdateFieldChange(UF::UpdateFieldSetter< T > const &)
Definition: Object.h:270
TypeID m_objectTypeId
Definition: Object.h:403
static Player * ToPlayer(Object *o)
Definition: Object.h:213
void ApplyPercentModUpdateFieldValue(UF::UpdateFieldSetter< T > setter, float percent, bool apply)
Definition: Object.h:365
Optional< uint32 > GetCurrentActivePetIndex() const
Definition: PetDefines.h:177
std::array< Optional< PetInfo >, MAX_ACTIVE_PETS > ActivePets
Definition: PetDefines.h:158
void SetCurrentActivePetIndex(uint32 index)
Definition: PetDefines.h:178
Definition: Pet.h:40
void FillPetInfo(PetStable::PetInfo *petInfo, Optional< ReactStates > forcedReactState={}) const
Definition: Pet.cpp:545
void SetGroupUpdateFlag(uint32 flag)
Definition: Pet.cpp:1828
std::string GetDebugInfo() const override
Definition: Pet.cpp:1937
bool CreateBaseAtCreatureInfo(CreatureTemplate const *cinfo, Unit *owner)
Definition: Pet.cpp:802
bool CreateBaseAtCreature(Creature *creature)
Definition: Pet.cpp:769
bool isControlled() const
Definition: Pet.h:53
void InitPetCreateSpells()
Definition: Pet.cpp:1596
static void InheritPhaseShift(WorldObject *target, WorldObject const *source)
void StopCastingBindSight() const
Definition: Player.cpp:26129
bool HaveAtClient(Object const *u) const
Definition: Player.cpp:23726
void SetClientControl(Unit *target, bool allowMove)
Definition: Player.cpp:25739
bool IsInSameRaidWith(Player const *p) const
Definition: Player.cpp:2160
void SendAttackSwingCancelAttack() const
Definition: Player.cpp:21294
void AddPetToUpdateFields(PetStable::PetInfo const &pet, PetSaveMode slot, PetStableFlags flags)
Definition: Player.cpp:28662
void SetGroupUpdateFlag(uint32 flag)
Definition: Player.h:2614
void DuelComplete(DuelCompleteType type)
Definition: Player.cpp:7741
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6324
uint16 GetSkillValue(uint32 skill) const
Definition: Player.cpp:6052
void SendAutoRepeatCancel(Unit *target)
Definition: Player.cpp:21307
PetStable & GetOrInitPetStable()
Definition: Player.cpp:28654
float GetRatingBonusValue(CombatRating cr) const
Definition: Player.cpp:5286
void CharmSpellInitialize()
Definition: Player.cpp:21991
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={})
Definition: Player.cpp:1250
void UpdatePvPState(bool onlyFFA=false)
Definition: Player.cpp:23317
bool InBattleground() const
Definition: Player.h:2394
void DurabilityPointLossForEquipSlot(EquipmentSlots slot)
Definition: Player.cpp:4709
void PetSpellInitialize()
Definition: Player.cpp:21879
uint32 GetBaseSpellPowerBonus() const
Returns base spellpower bonus from spellpower stat on items, without spellpower from intellect stat.
Definition: Player.h:2065
void SetFallInformation(uint32 time, float z)
Definition: Player.cpp:26672
void SendRemoveControlBar() const
Definition: Player.cpp:22031
WorldSession * GetSession() const
Definition: Player.h:2101
OutdoorPvP * GetOutdoorPvP() const
Definition: Player.cpp:25439
void CastItemCombatSpell(DamageInfo const &damageInfo)
Definition: Player.cpp:8622
PlayerSpellMap const & GetSpellMap() const
Definition: Player.h:1901
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:26767
void StopCastingCharm()
Definition: Player.cpp:21677
Battleground * GetBattleground() const
Definition: Player.cpp:24976
float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const
Definition: Player.cpp:5347
bool IsGameMaster() const
Definition: Player.h:1178
std::array< uint8, MAX_MOVE_TYPE > m_forced_speed_changes
Definition: Player.h:2529
void PossessSpellInitialize()
Definition: Player.cpp:21918
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition: Player.cpp:9643
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2606
std::unique_ptr< DuelInfo > duel
Definition: Player.h:1972
uint8 GetSubGroup() const
Definition: Player.h:2612
void VehicleSpellInitialize()
Definition: Player.cpp:21944
Team GetEffectiveTeam() const
Definition: Player.h:2239
void SetFactionForRace(uint8 race)
Definition: Player.cpp:6489
void SetContestedPvP(Player *attackedPlayer=nullptr)
Definition: Player.cpp:21439
void ResummonPetTemporaryUnSummonedIfAny()
Definition: Player.cpp:27180
void UpdatePvP(bool state, bool override=false)
Definition: Player.cpp:23360
bool IsInSameGroupWith(Player const *p) const
Definition: Player.cpp:2153
ProcEventInfo(Unit *actor, Unit *actionTarget, Unit *procTarget, ProcFlagsInit const &typeMask, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition: Unit.cpp:269
DamageInfo * _damageInfo
Definition: Unit.h:519
SpellSchoolMask GetSchoolMask() const
Definition: Unit.cpp:291
HealInfo * _healInfo
Definition: Unit.h:520
Spell const * GetProcSpell() const
Definition: Unit.h:508
SpellInfo const * GetSpellInfo() const
Definition: Unit.cpp:280
Spell * _spell
Definition: Unit.h:518
Mechanics Mechanic
Definition: SpellInfo.h:229
AuraType ApplyAuraName
Definition: SpellInfo.h:219
float CalcValueMultiplier(WorldObject *caster, Spell *spell=nullptr) const
Definition: SpellInfo.cpp:644
SpellEffectName Effect
Definition: SpellInfo.h:218
float BonusCoefficientFromAP
Definition: SpellInfo.h:239
float BonusCoefficient
Definition: SpellInfo.h:226
EnumFlag< SpellEffectAttributes > EffectAttributes
Definition: SpellInfo.h:241
SpellEffIndex EffectIndex
Definition: SpellInfo.h:217
void SendCooldownEvent(SpellInfo const *spellInfo, uint32 itemId=0, Spell *spell=nullptr, bool startCooldown=true)
void ResetCooldowns(Predicate predicate, bool update=false)
Definition: SpellHistory.h:131
void StartCooldown(SpellInfo const *spellInfo, uint32 itemId, Spell *spell=nullptr, bool onHold=false, Optional< Duration > forcedCooldown={})
DiminishingLevels GetDiminishingReturnsMaxLevel() const
Definition: SpellInfo.cpp:3298
Mechanics GetEffectMechanic(SpellEffIndex effIndex) const
Definition: SpellInfo.cpp:2508
SpellInfo const * GetFirstRankSpell() const
Definition: SpellInfo.cpp:4272
bool HasEffect(SpellEffectName effect) const
Definition: SpellInfo.cpp:1391
std::unordered_set< uint32 > Labels
Definition: SpellInfo.h:415
uint64 GetAllEffectsMechanicMask() const
Definition: SpellInfo.cpp:2470
bool IsRequiringDeadTarget() const
Definition: SpellInfo.cpp:1663
uint32 const Id
Definition: SpellInfo.h:325
EnumFlag< SpellAuraInterruptFlags2 > AuraInterruptFlags2
Definition: SpellInfo.h:373
bool IsGroupBuff() const
Definition: SpellInfo.cpp:1685
bool IsDeathPersistent() const
Definition: SpellInfo.cpp:1658
bool IsCooldownStartedOnEvent() const
Definition: SpellInfo.cpp:1649
bool IsPassive() const
Definition: SpellInfo.cpp:1592
uint32 Mechanic
Definition: SpellInfo.h:329
bool HasAnyAuraInterruptFlag() const
Definition: SpellInfo.cpp:1465
bool IsStackableOnOneSlotWithDifferentCasters() const
Definition: SpellInfo.cpp:1643
uint32 GetDispelMask() const
Definition: SpellInfo.cpp:2519
SpellSpecificType GetSpellSpecific() const
Definition: SpellInfo.cpp:2624
DiminishingReturnsType GetDiminishingReturnsGroupType() const
Definition: SpellInfo.cpp:3293
uint32 Dispel
Definition: SpellInfo.h:328
bool IsMultiSlotAura() const
Definition: SpellInfo.cpp:1638
int32 GetMaxDuration() const
Definition: SpellInfo.cpp:3798
int32 GetDiminishingReturnsLimitDuration() const
Definition: SpellInfo.cpp:3303
DiminishingGroup GetDiminishingReturnsGroupForSpell() const
Definition: SpellInfo.cpp:3288
uint32 SchoolMask
Definition: SpellInfo.h:413
uint32 CasterAuraState
Definition: SpellInfo.h:353
SpellCastResult CheckTarget(WorldObject const *caster, WorldObject const *target, bool implicit=true) const
Definition: SpellInfo.cpp:2175
flag128 SpellFamilyFlags
Definition: SpellInfo.h:409
WeaponAttackType GetAttackType() const
Definition: SpellInfo.cpp:1756
SpellSchoolMask GetSchoolMask() const
Definition: SpellInfo.cpp:2465
AuraStateType GetAuraState() const
Definition: SpellInfo.cpp:2538
bool HasAttribute(SpellAttr0 attribute) const
Definition: SpellInfo.h:449
uint64 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const
Definition: SpellInfo.cpp:2495
uint32 Attributes
Definition: SpellInfo.h:330
bool IsPassiveStackableWithRanks() const
Definition: SpellInfo.cpp:1633
uint32 MaxAffectedTargets
Definition: SpellInfo.h:407
int32 GetDuration() const
Definition: SpellInfo.cpp:3791
std::vector< SpellEffectInfo > const & GetEffects() const
Definition: SpellInfo.h:576
SpellCastResult CheckExplicitTarget(WorldObject const *caster, WorldObject const *target, Item const *itemTarget=nullptr) const
Definition: SpellInfo.cpp:2359
bool CanPierceImmuneAura(SpellInfo const *auraSpellInfo) const
Definition: SpellInfo.cpp:1841
bool IsPositive() const
Definition: SpellInfo.cpp:1709
uint32 DmgClass
Definition: SpellInfo.h:410
bool IsRangedWeaponSpell() const
Definition: SpellInfo.cpp:1734
EnumFlag< SpellAuraInterruptFlags > AuraInterruptFlags
Definition: SpellInfo.h:372
bool HasAura(AuraType aura) const
Definition: SpellInfo.cpp:1400
bool HasAuraInterruptFlag(SpellAuraInterruptFlags flag) const
Definition: SpellInfo.h:469
bool HasLabel(uint32 labelId) const
Definition: SpellInfo.cpp:4937
uint32 SpellFamilyName
Definition: SpellInfo.h:408
bool IsPositiveEffect(uint8 effIndex) const
Definition: SpellInfo.cpp:1714
bool IsSingleTarget() const
Definition: SpellInfo.cpp:1886
static CreatureImmunities const * GetCreatureImmunities(int32 creatureImmunitiesId)
Definition: SpellMgr.cpp:677
Definition: Spell.h:255
SpellInfo const * GetSpellInfo() const
Definition: Spell.h:650
void CallScriptCalcDamageHandlers(Unit *victim, int32 &damage, int32 &flatMod, float &pctMod)
Definition: Spell.cpp:8807
bool IsInterruptable() const
Definition: Spell.h:631
void SendChannelUpdate(uint32 time)
Definition: Spell.cpp:5195
static Spell const * ExtractSpellFromEvent(BasicEvent *event)
Definition: Spell.cpp:5633
bool IsProcDisabled() const
Definition: Spell.cpp:8168
int32 GetCastTime() const
Definition: Spell.h:612
std::string GetDebugInfo() const
Definition: Spell.cpp:9034
void CallScriptCalcHealingHandlers(Unit *victim, int32 &healing, int32 &flatMod, float &pctMod)
Definition: Spell.cpp:8819
static void SendCastResult(Player *caster, SpellInfo const *spellInfo, SpellCastVisual spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError=SPELL_CUSTOM_ERROR_NONE, int32 *param1=nullptr, int32 *param2=nullptr)
Definition: Spell.cpp:4643
uint32 getState() const
Definition: Spell.h:514
int32 GetProcChainLength() const
Definition: Spell.h:627
void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const &damageInfo, uint32 &resistAmount, int32 &absorbAmount)
Definition: Spell.cpp:8870
CurrentSpellTypes GetCurrentContainer() const
Definition: Spell.cpp:8026
void cancel()
Definition: Spell.cpp:3594
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition: Spell.cpp:3426
Spell ** m_selfContainer
Definition: Spell.h:662
void SetReferencedFromCurrent(bool yes)
Definition: Spell.h:630
UsedSpellMods m_appliedMods
Definition: Spell.h:610
void CallScriptCalcCritChanceHandlers(Unit const *victim, float &chance)
Definition: Spell.cpp:8795
void finish(SpellCastResult result=SPELL_CAST_OK)
Definition: Spell.cpp:4311
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
Utility class to enable range for loop syntax for multimap.equal_range uses.
Definition: IteratorPair.h:32
constexpr end_iterator end() const
Definition: IteratorPair.h:39
constexpr iterator begin() const
Definition: IteratorPair.h:38
Mask const & GetChangesMask() const
Definition: UpdateField.h:605
MutableFieldReference< T, false > ModifyValue(UpdateField< T, BlockBit, Bit >(Derived::*field))
Definition: UpdateField.h:683
void ClearChangesMask(UpdateField< T, BlockBit, Bit >(Derived::*field))
Definition: UpdateField.h:690
bool HasChanged(uint32 index) const
Definition: UpdateField.h:701
uint32 GetChangedObjectTypeMask() const
Definition: UpdateField.h:696
Definition: UnitAI.h:50
virtual void OnCharmed(bool isNew)
Definition: UnitAI.cpp:49
Definition: Unit.h:627
float GetUnitMissChance() const
Definition: Unit.cpp:2723
void EnterVehicle(Unit *base, int8 seatId=-1)
Definition: Unit.cpp:12118
void RewardRage(uint32 baseRage)
Definition: Unit.cpp:12463
void SetCannotTurn(bool apply)
Definition: Unit.cpp:8155
bool SetCanDoubleJump(bool enable)
Definition: Unit.cpp:13114
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:769
float GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const
Definition: Unit.cpp:9041
Unit * GetCharmed() const
Definition: Unit.h:1191
void ClearUnitState(uint32 f)
Definition: Unit.h:733
void OutDebugInfo() const
Definition: Unit.cpp:12514
bool IsWithinMeleeRangeAt(Position const &pos, Unit const *obj) const
Definition: Unit.cpp:651
void RemoveAreaTrigger(uint32 spellId)
Definition: Unit.cpp:5345
bool IsStopped() const
Definition: Unit.h:1656
bool IsVehicle() const
Definition: Unit.h:743
void ApplySpellImmune(uint32 spellId, SpellImmunity op, uint32 type, bool apply)
Definition: Unit.cpp:7845
void SetMinion(Minion *minion, bool apply)
Definition: Unit.cpp:6062
std::pair< AuraApplicationMap::iterator, AuraApplicationMap::iterator > AuraApplicationMapBoundsNonConst
Definition: Unit.h:639
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition: Unit.cpp:8280
void CastStop(uint32 except_spellid=0)
Definition: Unit.cpp:1135
bool IsWithinMeleeRange(Unit const *obj) const
Definition: Unit.h:699
void ApplyMovementForce(ObjectGuid id, Position origin, float magnitude, MovementForceType type, Position direction={}, ObjectGuid transportGuid=ObjectGuid::Empty)
Definition: Unit.cpp:13193
void SetImmuneToAll(bool apply, bool keepCombat)
Definition: Unit.cpp:8088
bool IsCharmed() const
Definition: Unit.h:1215
void SetImmuneToPC(bool apply, bool keepCombat)
Definition: Unit.cpp:8101
bool m_duringRemoveFromWorld
Definition: Unit.h:1984
float GetBoundingRadius() const
Definition: Unit.h:696
void KnockbackFrom(Position const &origin, float speedXY, float speedZ, Movement::SpellEffectExtraData const *spellEffectExtraData=nullptr)
Definition: Unit.cpp:11860
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:6626
void RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3608
Vehicle * GetVehicle() const
Definition: Unit.h:1713
EnumFlag< SpellAuraInterruptFlags2 > m_interruptMask2
Definition: Unit.h:1886
bool IsWithinBoundaryRadius(const Unit *obj) const
Definition: Unit.cpp:672
void SetVisible(bool x)
Definition: Unit.cpp:8351
virtual bool IsMovementPreventedByCasting() const
Definition: Unit.cpp:3119
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3812
virtual void UpdateResistances(uint32 school)
Definition: Unit.cpp:9264
bool HealthAbovePct(int32 pct) const
Definition: Unit.h:782
void DeleteCharmInfo()
Definition: Unit.cpp:9756
void RemoveGameObject(GameObject *gameObj, bool del)
Definition: Unit.cpp:5238
bool isTargetableForAttack(bool checkFakeDeath=true) const
Definition: Unit.cpp:8168
bool IsHunterPet() const
Definition: Unit.h:741
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition: Unit.h:1321
uint32 GetSchoolImmunityMask() const
Definition: Unit.cpp:7521
std::unique_ptr< SpellHistory > _spellHistory
Definition: Unit.h:1996
void UpdateAttackTimeField(WeaponAttackType att)
Definition: Unit.cpp:10314
float GetHealthPct() const
Definition: Unit.h:784
bool IsBlockCritical()
Definition: Unit.cpp:2462
float m_baseSpellCritChance
Definition: Unit.h:1474
SpellImmuneContainer m_spellImmune[MAX_SPELL_IMMUNITY]
Definition: Unit.h:1546
void CombatStop(bool includingCast=false, bool mutualPvP=true, bool(*unitFilter)(Unit const *otherUnit)=nullptr)
Definition: Unit.cpp:5827
int32 MeleeDamageBonusTaken(Unit *attacker, int32 pdamage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const *spellProto=nullptr, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL)
Definition: Unit.cpp:7736
bool HasExtraUnitMovementFlag(uint32 f) const
Definition: Unit.h:1669
void AIUpdateTick(uint32 diff)
Definition: Unit.cpp:9525
void JumpTo(float speedXY, float speedZ, float angle, Optional< Position > dest={})
Definition: Unit.cpp:12004
virtual void RecalculateObjectScale()
Definition: Unit.cpp:10140
void SetHealth(uint64 val)
Definition: Unit.cpp:9346
Unit * m_unitMovedByMe
Definition: Unit.h:1898
virtual MovementGeneratorType GetDefaultMovementType() const
Definition: Unit.cpp:10044
bool HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag128 familyFlags) const
Definition: Unit.cpp:716
AuraList m_removedAuras
Definition: Unit.h:1877
void SetFacingToPoint(Position const &point, bool force=true)
Definition: Unit.cpp:12688
uint32 GetUnitMovementFlags() const
Definition: Unit.h:1664
LiquidTypeEntry const * _lastLiquid
Definition: Unit.h:1914
static uint32 SpellCriticalHealingBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition: Unit.cpp:7120
void _UpdateAutoRepeatSpell()
Definition: Unit.cpp:2906
void SetVirtualItem(uint32 slot, uint32 itemId, uint16 appearanceModId=0, uint16 itemVisual=0)
Definition: Unit.cpp:13604
void SendMoveKnockBack(Player *player, float speedXY, float speedZ, float vcos, float vsin)
Definition: Unit.cpp:11849
float GetTotalAuraModValue(UnitMods unitMod) const
Definition: Unit.cpp:9211
AreaTriggerList m_areaTrigger
Definition: Unit.h:1869
bool IsInteractionAllowedInCombat() const
Definition: Unit.h:1052
void RestoreDisabledAI()
Definition: Unit.cpp:9579
int32 SpellHealingBonusTaken(Unit *caster, SpellInfo const *spellProto, int32 healamount, DamageEffectType damagetype) const
Definition: Unit.cpp:7285
void RemoveAllControlled()
Definition: Unit.cpp:6428
Pet * ToPet()
Definition: Unit.h:1750
ObjectGuid GetDemonCreatorGUID() const
Definition: Unit.h:1182
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Definition: Unit.h:1015
void RemoveAurasByShapeShift()
Definition: Unit.cpp:4194
float GetTotalStatValue(Stats stat) const
Definition: Unit.cpp:9197
void SetPlayHoverAnim(bool enable, bool sendUpdate=true)
Definition: Unit.cpp:13319
std::unique_ptr< MotionMaster > i_motionMaster
Definition: Unit.h:1905
void SetUnitFlag3(UnitFlags3 flags)
Definition: Unit.h:843
void SetGender(Gender gender)
Definition: Unit.h:756
float GetUnitCriticalChanceTaken(Unit const *attacker, WeaponAttackType attackType, float critDone) const
Definition: Unit.cpp:2796
bool IsContestedGuard() const
Definition: Unit.cpp:11602
std::unordered_map< ObjectGuid, uint32 > extraAttacksTargets
Definition: Unit.h:1980
void UpdateUnitMod(UnitMods unitMod)
Definition: Unit.cpp:9052
void UpdateDamagePctDoneMods(WeaponAttackType attackType)
Definition: Unit.cpp:9150
float GetSpeed(UnitMoveType mtype) const
Definition: Unit.cpp:8515
bool SetFall(bool enable)
Definition: Unit.cpp:12785
void _UnregisterDynObject(DynamicObject *dynObj)
Definition: Unit.cpp:5157
bool m_canModifyStats
Definition: Unit.h:1891
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3685
void UpdateObjectVisibility(bool forced=true) override
Definition: Unit.cpp:11836
int64 ModifyHealth(int64 val)
Definition: Unit.cpp:8182
std::array< uint32, MAX_REACTIVE > m_reactiveTimer
Definition: Unit.h:1907
void AddExtraUnitMovementFlag(uint32 f)
Definition: Unit.h:1667
std::shared_ptr< UnitAI > i_AI
Definition: Unit.h:1974
uint32 GetCastSpellXSpellVisualId(SpellInfo const *spellInfo) const override
Definition: Unit.cpp:13709
void SetCurrentCastSpell(Spell *pSpell)
Definition: Unit.cpp:2941
bool _isCombatDisallowed
Definition: Unit.h:2001
void SetFullHealth()
Definition: Unit.h:790
void TriggerOnHealthChangeAuras(uint64 oldVal, uint64 newVal)
Definition: Unit.cpp:8249
void SetMinionGUID(ObjectGuid guid)
Definition: Unit.h:1175
float SpellDamagePctDone(Unit *victim, SpellInfo const *spellProto, DamageEffectType damagetype, SpellEffectInfo const &spellEffectInfo) const
Definition: Unit.cpp:6717
void RestoreDisplayId(bool ignorePositiveAurasPreventingMounting=false)
Definition: Unit.cpp:10172
Diminishing m_Diminishing
Definition: Unit.h:1962
void SetHoverHeight(float hoverHeight)
Definition: Unit.h:1133
void BuildValuesUpdateForPlayerWithMask(UpdateData *data, UF::ObjectData::Mask const &requestedObjectMask, UF::UnitData::Mask const &requestedUnitMask, Player const *target) const
Definition: Unit.cpp:13416
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition: Unit.cpp:10100
void FinishSpell(CurrentSpellTypes spellType, SpellCastResult result=SPELL_CAST_OK)
Definition: Unit.cpp:3047
void EnergizeBySpell(Unit *victim, SpellInfo const *spellInfo, int32 damage, Powers powerType)
Definition: Unit.cpp:6613
void UpdateHeight(float newZ)
Only server-side height update, does not broadcast to client.
Definition: Unit.cpp:12455
std::array< Spell *, CURRENT_MAX_SPELL > m_currentSpells
Definition: Unit.h:1873
void _RemoveNoStackAurasDueToAura(Aura *aura, bool owned)
Definition: Unit.cpp:3572
virtual void OnPhaseChange()
Definition: Unit.cpp:11832
void SetConfused(bool apply)
Definition: Unit.cpp:11117
void _UpdateSpells(uint32 time)
Definition: Unit.cpp:2844
ThreatManager & GetThreatManager()
Definition: Unit.h:1063
void ReplaceAllPvpFlags(UnitPVPStateFlags flags)
Definition: Unit.h:870
void AddToWorld() override
Definition: Unit.cpp:9603
virtual float GetArmorMultiplierForTarget(WorldObject const *) const
Definition: Unit.h:797
void RestoreFaction()
Definition: Unit.cpp:11417
float GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const *spellProto) const
Definition: Unit.cpp:7873
virtual void AtExitCombat()
Definition: Unit.cpp:8670
void _UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode)
Definition: Unit.cpp:3457
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition: Unit.cpp:4687
void SetInCombatWith(Unit *enemy, bool addSecondUnitSuppressed=false)
Definition: Unit.h:1045
virtual void Say(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition: Unit.cpp:13562
void PropagateSpeedChange()
-------—End of Pet responses methods-------—
Definition: Unit.cpp:10039
bool HasBreakableByDamageCrowdControlAura(Unit *excludeCasterChannel=nullptr) const
Definition: Unit.cpp:734
void DelayOwnedAuras(uint32 spellId, ObjectGuid caster, int32 delaytime)
Definition: Unit.cpp:4433
void SetControlled(bool apply, UnitState state)
Definition: Unit.cpp:10911
UF::UpdateField< UF::UnitData, 0, TYPEID_UNIT > m_unitData
Definition: Unit.h:1814
uint8 GetClass() const
Definition: Unit.h:752
SpellSchools GetSpellSchoolByAuraGroup(UnitMods unitMod) const
Definition: Unit.cpp:9227
void SetStunned(bool apply)
Definition: Unit.cpp:11008
std::array< ObjectGuid, MAX_SUMMON_SLOT > m_SummonSlot
Definition: Unit.h:1460
Stats GetStatByAuraGroup(UnitMods unitMod) const
Definition: Unit.cpp:9247
uint32 m_state
Definition: Unit.h:1959
void HandleSpellClick(Unit *clicker, int8 seatId=-1)
Definition: Unit.cpp:12027
bool CanUseAttackType(uint8 attacktype) const
Definition: Unit.cpp:2492
bool IsWithinCombatRange(Unit const *obj, float dist2compare) const
Definition: Unit.cpp:635
Player * GetDemonCreatorPlayer() const
Definition: Unit.cpp:6012
void _RegisterAreaTrigger(AreaTrigger *areaTrigger)
Definition: Unit.cpp:5315
bool HasAuraTypeWithCaster(AuraType auraType, ObjectGuid caster) const
Definition: Unit.cpp:4679
Spell * FindCurrentSpellBySpellId(uint32 spell_id) const
Definition: Unit.cpp:3104
uint32 GetMountDisplayId() const
Definition: Unit.h:899
void UpdateAllDamageDoneMods()
Definition: Unit.cpp:9144
Vehicle * m_vehicle
Definition: Unit.h:1910
void RemoveVisibleAura(AuraApplication *aurApp)
Definition: Unit.cpp:689
Totem * ToTotem()
Definition: Unit.h:1753
int64 GetHealthGain(int64 dVal)
Definition: Unit.cpp:8224
Creature * GetVehicleCreatureBase() const
Definition: Unit.cpp:11501
std::unique_ptr< CharmInfo > m_charmInfo
Definition: Unit.h:1902
void UpdateDisplayPower()
Definition: Unit.cpp:5625
float GetCollisionHeight() const override
Definition: Unit.cpp:13733
void AddExtraUnitMovementFlag2(uint32 f)
Definition: Unit.h:1673
void RemoveAllGameObjects()
Definition: Unit.cpp:5302
static void DealHeal(HealInfo &healInfo)
Definition: Unit.cpp:6339
bool isPossessedByPlayer() const
Definition: Unit.cpp:6455
void SendClearTarget()
Definition: Unit.cpp:12556
std::multimap< uint32, AuraApplication * > AuraApplicationMap
Definition: Unit.h:637
void _RegisterDynObject(DynamicObject *dynObj)
Definition: Unit.cpp:5150
void UpdateSpeed(UnitMoveType mtype)
Definition: Unit.cpp:8361
static void DealDamageMods(Unit const *attacker, Unit const *victim, uint32 &damage, uint32 *absorb)
Definition: Unit.cpp:748
bool IsPolymorphed() const
Definition: Unit.cpp:10127
bool IsAreaSpiritHealer() const
Definition: Unit.h:1002
void PlayOneShotAnimKitId(uint16 animKitId)
Definition: Unit.cpp:10529
float m_weaponDamage[MAX_ATTACK][2]
Definition: Unit.h:1890
ShapeshiftForm GetShapeshiftForm() const
Definition: Unit.h:1463
void SetFaction(uint32 faction) override
Definition: Unit.h:859
virtual void SetPvP(bool state)
Definition: Unit.cpp:11610
ObjectGuid GetOwnerGUID() const override
Definition: Unit.h:1170
uint64 GetMechanicImmunityMask() const
Definition: Unit.cpp:7541
Unit * SelectNearbyTarget(Unit *exclude=nullptr, float dist=NOMINAL_MELEE_RANGE) const
Definition: Unit.cpp:10272
bool isInBackInMap(Unit const *target, float distance, float arc=float(M_PI)) const
Definition: Unit.cpp:3160
float GetCombatRatingReduction(CombatRating cr) const
Definition: Unit.cpp:11890
void RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject *dispeller, uint8 chargesRemoved=1)
Definition: Unit.cpp:3864
void RemoveExtraUnitMovementFlag(uint32 f)
Definition: Unit.h:1668
virtual void UpdateAttackPowerAndDamage(bool ranged=false)=0
static void CalcHealAbsorb(HealInfo &healInfo)
Definition: Unit.cpp:2028
virtual void Yell(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition: Unit.cpp:13567
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:1142
virtual SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType=BASE_ATTACK) const =0
Unit * GetVehicleRoot() const
Definition: Unit.cpp:11485
void SetCantProc(bool apply)
Definition: Unit.cpp:10392
Unit * GetCharmer() const
Definition: Unit.h:1188
void SetSpeed(UnitMoveType mtype, float newValue)
Definition: Unit.cpp:8520
Aura * GetOwnedAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, Aura *except=nullptr) const
Definition: Unit.cpp:3669
int32 m_procChainLength
Definition: Unit.h:1860
void SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
Definition: Unit.cpp:9021
Unit * getAttackerForHelper() const
Definition: Unit.cpp:5647
std::forward_list< AuraEffect * > AuraEffectList
Definition: Unit.h:644
float GetUnitParryChance(WeaponAttackType attType, Unit const *victim) const
Definition: Unit.cpp:2683
void SetPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition: Unit.cpp:9419
void TriggerOnPowerChangeAuras(Powers power, int32 oldVal, int32 newVal)
Definition: Unit.cpp:9481
void SendMeleeAttackStart(Unit *victim)
Definition: Unit.cpp:2444
Pet * CreateTamedPetFrom(Creature *creatureTarget, uint32 spell_id=0)
Definition: Unit.cpp:10441
Trinity::unique_trackable_ptr< Vehicle > m_vehicleKit
Definition: Unit.h:1911
bool IsInDisallowedMountForm() const
Definition: Unit.cpp:8915
void ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float amount)
Definition: Unit.cpp:8988
bool IsImmunedToSpell(SpellInfo const *spellInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition: Unit.cpp:7431
VisibleAuraContainer m_visibleAuras
Definition: Unit.h:1893
UnitPVPStateFlags GetPvpFlags() const
Definition: Unit.h:866
virtual void UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot=-1)
Definition: Unit.cpp:9114
void _removeAttacker(Unit *pAttacker)
Definition: Unit.cpp:5642
void SendAttackStateUpdate(CalcDamageInfo *damageInfo)
Definition: Unit.cpp:5488
AuraApplication * GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition: Unit.cpp:4578
std::forward_list< AuraApplication * > AuraApplicationList
Definition: Unit.h:646
uint32 GetTransformSpell() const
Definition: Unit.h:1574
void RemoveAllAurasExceptType(AuraType type)
Definition: Unit.cpp:4377
void DealSpellDamage(SpellNonMeleeDamage const *damageInfo, bool durabilityLoss)
Definition: Unit.cpp:1248
uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct) const
Definition: Unit.cpp:2392
uint32 _lastExtraAttackSpell
Definition: Unit.h:1979
void SetAnimTier(AnimTier animTier, bool notifyClient=true)
Definition: Unit.cpp:10114
static void CalcAbsorbResist(DamageInfo &damageInfo, Spell *spell=nullptr)
Definition: Unit.cpp:1797
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition: Unit.cpp:3089
virtual bool CanFly() const =0
void SetAuraStack(uint32 spellId, Unit *target, uint32 stack)
Definition: Unit.cpp:11665
Unit * GetVehicleBase() const
Definition: Unit.cpp:11480
bool haveOffhandWeapon() const
Definition: Unit.cpp:498
MotionMaster * GetMotionMaster()
Definition: Unit.h:1652
bool SetFeatherFall(bool enable)
Definition: Unit.cpp:12900
bool IsPet() const
Definition: Unit.h:740
Powers GetPowerType() const
Definition: Unit.h:799
bool HasUnitFlag(UnitFlags flags) const
Definition: Unit.h:832
static uint32 CalcArmorReducedDamage(Unit const *attacker, Unit *victim, uint32 damage, SpellInfo const *spellInfo, WeaponAttackType attackType=MAX_ATTACK, uint8 attackerLevel=0)
Definition: Unit.cpp:1625
void _addAttacker(Unit *pAttacker)
Definition: Unit.cpp:5637
void ProcSkillsAndReactives(bool isVictim, Unit *procTarget, ProcFlagsInit const &typeMask, ProcFlagsHit hitMask, WeaponAttackType attType)
Definition: Unit.cpp:9850
bool _instantCast
Definition: Unit.h:1985
void Dismount()
Definition: Unit.cpp:7920
std::array< ObjectGuid, MAX_GAMEOBJECT_SLOT > m_ObjectSlot
Definition: Unit.h:1461
void SetCharm(Unit *target, bool apply)
Definition: Unit.cpp:6258
void SetMovedUnit(Unit *target)
Definition: Unit.cpp:9765
ObjectGuid GetCharmedGUID() const
Definition: Unit.h:1190
void SetCreatedBySpell(int32 spellId)
Definition: Unit.h:847
bool SetHover(bool enable, bool updateAnimTier=true)
Definition: Unit.cpp:12938
bool CanDualWield() const
Definition: Unit.h:692
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition: Unit.cpp:3059
void UpdateInterruptMask()
Definition: Unit.cpp:696
void StartReactiveTimer(ReactiveType reactive)
Definition: Unit.h:1694
void IncrDiminishing(SpellInfo const *auraSpellInfo)
Definition: Unit.cpp:8765
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition: Unit.cpp:9697
void SetFacingToObject(WorldObject const *object, bool force=true)
Definition: Unit.cpp:12671
void ResumeMovement(uint32 timer=0, uint8 slot=0)
Definition: Unit.cpp:10076
Aura * AddAura(uint32 spellId, Unit *target)
Definition: Unit.cpp:11618
bool HasInterruptFlag(SpellAuraInterruptFlags flags) const
Definition: Unit.h:1556
AuraEffect * GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition: Unit.cpp:4464
bool isAttackingPlayer() const
Definition: Unit.cpp:5863
void AtEndOfEncounter(EncounterType type)
Definition: Unit.cpp:536
virtual void AtEnterCombat()
Definition: Unit.cpp:8647
UnitAIStack i_AIs
Definition: Unit.h:1973
uint32 GetBaseAttackTime(WeaponAttackType att) const
Definition: Unit.cpp:10303
std::unique_ptr< MovementForces > _movementForces
Definition: Unit.h:1998
int32 GetMaxNegativeAuraModifier(AuraType auraType) const
Definition: Unit.cpp:4944
void UpdateSplineMovement(uint32 t_diff)
Definition: Unit.cpp:557
uint32 GetDamageReduction(uint32 damage) const
Definition: Unit.h:953
std::array< float, MAX_STATS > m_floatStatPosBuff
Definition: Unit.h:1851
void SetUnitFlag2(UnitFlags2 flags)
Definition: Unit.h:838
bool HasUnitFlag2(UnitFlags2 flags) const
Definition: Unit.h:837
bool CanFreeMove() const
Definition: Unit.cpp:9323
std::string GetDebugInfo() const override
Definition: Unit.cpp:13774
std::pair< AuraMap::const_iterator, AuraMap::const_iterator > AuraMapBounds
Definition: Unit.h:634
virtual bool IsLoading() const
Definition: Unit.h:1747
uint32 BuildAuraStateUpdateForTarget(Unit const *target) const
Definition: Unit.cpp:5950
bool isInFrontInMap(Unit const *target, float distance, float arc=float(M_PI)) const
Definition: Unit.cpp:3155
float m_auraFlatModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_FLAT_END]
Definition: Unit.h:1888
void SetImmuneToNPC(bool apply, bool keepCombat)
Definition: Unit.cpp:8124
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition: Unit.cpp:10064
void SetPetNameTimestamp(uint32 timestamp)
Definition: Unit.h:1225
bool IsSplineEnabled() const
Definition: Unit.cpp:13355
std::array< uint32, MAX_ATTACK > m_baseAttackSpeed
Definition: Unit.h:1476
void RemoveAllAurasRequiringDeadTarget()
Definition: Unit.cpp:4356
void UpdateAuraForGroup()
Definition: Unit.cpp:10377
Vignettes::VignetteData const * GetVignette() const
Definition: Unit.h:1809
void UpdateReactives(uint32 p_time)
Definition: Unit.cpp:10238
int32 MeleeDamageBonusDone(Unit *pVictim, int32 damage, WeaponAttackType attType, DamageEffectType damagetype, SpellInfo const *spellProto=nullptr, Mechanics mechanic=MECHANIC_NONE, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL, Spell *spell=nullptr, AuraEffect const *aurEff=nullptr)
Definition: Unit.cpp:7624
bool IsAlive() const
Definition: Unit.h:1164
virtual bool CanApplyResilience() const
Definition: Unit.cpp:11759
AuraEffect * IsScriptOverriden(SpellInfo const *spell, int32 script) const
Definition: Unit.cpp:4776
float m_modRangedHitChance
Definition: Unit.h:1472
float GetCombatReach() const override
Definition: Unit.h:694
void AtTargetAttacked(Unit *target, bool canInitialAggro)
Definition: Unit.cpp:8686
static uint32 CalcSpellResistedDamage(Unit const *attacker, Unit *victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const *spellInfo)
Definition: Unit.cpp:1696
DeathState m_deathState
Definition: Unit.h:1857
void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply)
Definition: Unit.cpp:10335
void SetBonusResistanceMod(SpellSchools school, int32 val)
Definition: Unit.h:773
int32 GetMaxPower(Powers power) const
Definition: Unit.cpp:9410
uint32 m_unitTypeMask
Definition: Unit.h:1913
void StopMoving()
Definition: Unit.cpp:10049
std::pair< AuraApplicationMap::const_iterator, AuraApplicationMap::const_iterator > AuraApplicationMapBounds
Definition: Unit.h:638
int32 GetMaxNegativeAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition: Unit.cpp:4979
void RemoveAllAreaTriggers()
Definition: Unit.cpp:5372
int32 HealBySpell(HealInfo &healInfo, bool critical=false)
Definition: Unit.cpp:6591
void AddPlayerToVision(Player *player)
Definition: Unit.cpp:6525
void RemoveNpcFlag(NPCFlags flags)
Definition: Unit.h:983
void SendHealSpellLog(HealInfo &healInfo, bool critical=false)
Definition: Unit.cpp:6572
int32 GetMaxPositiveAuraModifier(AuraType auraType) const
Definition: Unit.cpp:4939
GameObject * GetGameObject(uint32 spellId) const
Definition: Unit.cpp:5201
virtual ~Unit()
Definition: Unit.cpp:389
void _ExitVehicle(Position const *exitPosition=nullptr)
Definition: Unit.cpp:12223
uint32 m_removedAurasCount
Definition: Unit.h:1879
void RemoveAllAurasOnDeath()
Definition: Unit.cpp:4333
uint32 m_movementCounter
Incrementing counter used in movement packets.
Definition: Unit.h:1955
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const *log)
Definition: Unit.cpp:5378
bool IsStandState() const
Definition: Unit.cpp:10094
TempSummon * ToTempSummon()
Definition: Unit.h:1756
bool IsGravityDisabled() const
Definition: Unit.h:1135
CharmInfo * GetCharmInfo()
Definition: Unit.h:1221
void AtStartOfEncounter(EncounterType type)
Definition: Unit.cpp:516
bool SetCanTransitionBetweenSwimAndFly(bool enable)
Definition: Unit.cpp:13048
bool SetDisableInertia(bool disable)
Definition: Unit.cpp:13145
ControlList m_Controlled
Definition: Unit.h:1211
bool IsInCombatWith(Unit const *who) const
Definition: Unit.h:1044
void DisableSpline()
Definition: Unit.cpp:624
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition: Unit.h:1195
int32 GetMechanicResistChance(SpellInfo const *spellInfo) const
Definition: Unit.cpp:2469
int32 GetMaxPositiveAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition: Unit.cpp:5009
TimeTracker m_splineSyncTimer
Definition: Unit.h:1960
void RemoveUnitFlag3(UnitFlags3 flags)
Definition: Unit.h:844
AuraMap::iterator m_auraUpdateIterator
Definition: Unit.h:1878
UnitAI * GetAI() const
Definition: Unit.h:660
Unit * GetMeleeHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo=nullptr)
Definition: Unit.cpp:6397
void DestroyForPlayer(Player *target) const override
Definition: Unit.cpp:13456
ObjectGuid _lastDamagedTargetGuid
Definition: Unit.h:1981
float SpellCritChanceDone(Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType=BASE_ATTACK) const
Definition: Unit.cpp:6931
bool SetDisableGravity(bool disable, bool updateAnimTier=true)
Definition: Unit.cpp:12725
void CancelSpellMissiles(uint32 spellId, bool reverseMissile=false, bool abortSpell=false)
Definition: Unit.cpp:11729
void RemoveAurasWithAttribute(uint32 flags)
Definition: Unit.cpp:4010
void RemoveAllFollowers()
Definition: Unit.cpp:8586
virtual void SetInteractionAllowedWhileHostile(bool interactionAllowed)
Definition: Unit.cpp:8722
void UpdateMountCapability()
Definition: Unit.cpp:8051
void _DeleteRemovedAuras()
Definition: Unit.cpp:2833
Player * GetPlayerMovingMe() const
Definition: Unit.h:1232
void _ApplyAura(AuraApplication *aurApp, uint32 effMask)
Definition: Unit.cpp:3404
void SetUninteractible(bool apply)
Definition: Unit.cpp:8147
Unit * GetNextRandomRaidMemberOrPet(float radius)
Definition: Unit.cpp:6473
void SetBaseAttackTime(WeaponAttackType att, uint32 val)
Definition: Unit.cpp:10308
virtual bool HasSpell(uint32) const
Definition: Unit.h:1069
virtual bool IsAffectedByDiminishingReturns() const
Definition: Unit.h:678
std::pair< AuraStateAurasMap::const_iterator, AuraStateAurasMap::const_iterator > AuraStateAurasMapBounds
Definition: Unit.h:642
int32 GetTotalAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition: Unit.cpp:4949
void AddUnitState(uint32 f)
Definition: Unit.h:731
static void ApplyResilience(Unit const *victim, int32 *damage)
Definition: Unit.cpp:11764
float GetTotalAuraMultiplier(AuraType auraType) const
Definition: Unit.cpp:4934
void Mount(uint32 mount, uint32 vehicleId=0, uint32 creatureEntry=0)
Definition: Unit.cpp:7887
void SetSheath(SheathState sheathed)
Definition: Unit.cpp:5630
bool IsOnVehicle(Unit const *vehicle) const
Definition: Unit.cpp:11475
void SendSpellDamageResist(Unit *target, uint32 spellId)
Definition: Unit.cpp:5469
bool isInAccessiblePlaceFor(Creature const *c) const
Definition: Unit.cpp:3165
bool IsCharmedOwnedByPlayerOrPlayer() const
Definition: Unit.h:1196
Gender GetGender() const
Definition: Unit.h:755
int32 GetMinPower(Powers power) const
Definition: Unit.h:805
virtual void SetInteractionAllowedInCombat(bool interactionAllowed)
Definition: Unit.cpp:8732
Unit * EnsureVictim() const
Definition: Unit.h:717
int32 GetMaxNegativeAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition: Unit.cpp:5019
uint32 getAttackTimer(WeaponAttackType type) const
Definition: Unit.h:689
void RefreshAI()
Definition: Unit.cpp:9557
bool IsDuringRemoveFromWorld() const
Definition: Unit.h:1748
void SendPlaySpellVisual(Unit *target, uint32 spellVisualId, uint16 missReason, uint16 reflectStatus, float travelSpeed, bool speedAsTime=false, float launchDelay=0.0f)
Definition: Unit.cpp:11674
bool m_ControlledByPlayer
Definition: Unit.h:1848
void SetFeared(bool apply)
Definition: Unit.cpp:11081
Unit * GetCharmerOrOwner() const
Definition: Unit.h:1200
uint32 GetDiseasesByCaster(ObjectGuid casterGUID, bool remove=false)
Definition: Unit.cpp:4788
void RemoveAurasDueToItemSpell(uint32 spellId, ObjectGuid castItemGuid)
Definition: Unit.cpp:3976
virtual void UpdateDamagePhysical(WeaponAttackType attType)
Definition: StatSystem.cpp:64
bool IsPlayingHoverAnim() const
Definition: Unit.h:1130
void _ApplyAllAuraStatMods()
Definition: Unit.cpp:4458
void SetBattlePetCompanionNameTimestamp(uint32 timestamp)
Definition: Unit.h:1246
uint32 GetCreatureType() const
Definition: Unit.cpp:8880
void AddGameObject(GameObject *gameObj)
Definition: Unit.cpp:5217
void InterruptMovementBasedAuras()
Definition: Unit.cpp:614
virtual bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition: Unit.cpp:7561
int32 GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const *aurEff, AuraType auraType, bool checkMiscValue=false, int32 miscValue=0) const
Definition: Unit.cpp:13477
bool HasNegativeAuraWithInterruptFlag(InterruptFlags flag, ObjectGuid guid=ObjectGuid::Empty) const
Definition: Unit.cpp:4723
bool IsThreatened() const
Definition: Unit.cpp:8163
void SendSetVehicleRecId(uint32 vehicleId)
Definition: Unit.cpp:13176
bool SetSwim(bool enable)
Definition: Unit.cpp:12801
void BuildValuesUpdateWithFlag(ByteBuffer *data, UF::UpdateFieldFlag flags, Player const *target) const override
Definition: Unit.cpp:13400
void SetEmoteState(Emote emote)
Definition: Unit.h:852
virtual bool UpdatePosition(float x, float y, float z, float ang, bool teleport=false)
Definition: Unit.cpp:12392
DynObjectList m_dynObj
Definition: Unit.h:1863
int32 GetMaxPositiveAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask, AuraEffect const *except=nullptr) const
Definition: Unit.cpp:4969
PositionUpdateInfo _positionUpdateInfo
Definition: Unit.h:1999
void SetPvpFlag(UnitPVPStateFlags flags)
Definition: Unit.h:868
virtual void UpdateNearbyPlayersInteractions()
Definition: Unit.cpp:8743
AuraApplicationList m_interruptableAuras
Definition: Unit.h:1883
void SetResistance(SpellSchools school, int32 val)
Definition: Unit.h:772
float GetTotalAuraMultiplierByMiscValue(AuraType auraType, int32 misc_value) const
Definition: Unit.cpp:4999
uint32 GetDisplayId() const
Definition: Unit.h:1567
void SendCancelSpellVisualKit(uint32 id)
Definition: Unit.cpp:11721
uint32 GetVirtualItemId(uint32 slot) const
Definition: Unit.cpp:13588
static float CalculateAverageResistReduction(WorldObject const *caster, SpellSchoolMask schoolMask, Unit const *victim, SpellInfo const *spellInfo=nullptr)
Definition: Unit.cpp:1754
void SendSpellDamageImmune(Unit *target, uint32 spellId, bool isPeriodic)
Definition: Unit.cpp:5478
void ModifyAuraState(AuraStateType flag, bool apply)
Definition: Unit.cpp:5894
bool IsAIEnabled() const
Definition: Unit.h:658
Unit * GetUnitBeingMoved() const
Definition: Unit.h:1230
EnumFlag< SpellOtherImmunity > GetSpellOtherImmunityMask() const
Definition: Unit.cpp:7551
uint32 GetAuraCount(uint32 spellId) const
Definition: Unit.cpp:4648
UnitAI * GetTopAI() const
Definition: Unit.h:666
void HandleProcExtraAttackFor(Unit *victim, uint32 count)
Definition: Unit.cpp:2256
bool isPossessing() const
Definition: Unit.cpp:6465
uint32 GetNativeDisplayId() const
Definition: Unit.h:1570
float SpellCritChanceTaken(Unit const *caster, Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType=BASE_ATTACK) const
Definition: Unit.cpp:6985
void RemoveAllGroupBuffsFromCaster(ObjectGuid casterGUID)
Definition: Unit.cpp:4419
virtual void UpdateArmor()=0
bool HealthBelowPct(int32 pct) const
Definition: Unit.h:780
uint64 GetMaxHealth() const
Definition: Unit.h:777
void UpdateCharmAI()
Definition: Unit.cpp:9704
void ClearAllReactives()
Definition: Unit.cpp:10227
void ApplyControlStatesIfNeeded()
Definition: Unit.cpp:10992
void SetRooted(bool apply, bool packetOnly=false)
Definition: Unit.cpp:11039
void AddUnitMovementFlag(uint32 f)
Definition: Unit.h:1661
void BuildValuesCreate(ByteBuffer *data, Player const *target) const override
Definition: Unit.cpp:13373
ThreatManager m_threatManager
Definition: Unit.h:1968
uint32 _oldFactionId
faction before charm
Definition: Unit.h:1987
bool Attack(Unit *victim, bool meleeAttack)
Definition: Unit.cpp:5670
int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, bool npcCaster) const
Definition: Unit.cpp:11786
float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type) const
Definition: Unit.cpp:9315
bool IsHovering() const
Definition: Unit.h:1137
std::forward_list< Aura * > AuraList
Definition: Unit.h:645
float GetTotalAuraMultiplierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition: Unit.cpp:5039
bool HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster=ObjectGuid::Empty) const
Definition: Unit.cpp:4634
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4560
bool PopAI()
Definition: Unit.cpp:9546
ObjectGuid GetMinionGUID() const
Definition: Unit.h:1174
bool SetCanFly(bool enable)
Definition: Unit.cpp:12820
virtual float GetDamageMultiplierForTarget(WorldObject const *) const
Definition: Unit.h:796
bool SetCollision(bool disable)
Definition: Unit.cpp:13011
bool isPossessed() const
Definition: Unit.h:1216
uint16 GetMaxSkillValueForLevel(Unit const *target=nullptr) const
Definition: Unit.h:917
bool HasUnitMovementFlag(uint32 f) const
Definition: Unit.h:1663
Unit * m_charmed
Definition: Unit.h:1901
virtual void UpdateMaxPower(Powers power)=0
uint64 GetHealth() const
Definition: Unit.h:776
void _AddAura(UnitAura *aura, Unit *caster)
Definition: Unit.cpp:3309
AttackerSet m_attackers
Definition: Unit.h:1854
bool IsSummon() const
Definition: Unit.h:738
bool IsInWater() const
Definition: Unit.cpp:3186
TransportBase * GetDirectTransport() const
Returns the transport this unit is on directly (if on vehicle and transport, return vehicle)
Definition: Unit.cpp:11520
uint32 GetFaction() const override
Definition: Unit.h:858
virtual void TextEmote(std::string_view text, WorldObject const *target=nullptr, bool isBossEmote=false)
Definition: Unit.cpp:13572
void RemoveDynObject(uint32 spellId)
Definition: Unit.cpp:5180
void SendCancelSpellVisual(uint32 id)
Definition: Unit.cpp:11703
void SendEnergizeSpellLog(Unit *victim, uint32 spellId, int32 damage, int32 overEnergize, Powers powerType)
Definition: Unit.cpp:6600
Unit * m_attacking
Definition: Unit.h:1855
bool HasAuraState(AuraStateType flag, SpellInfo const *spellProto=nullptr, Unit const *Caster=nullptr) const
Definition: Unit.cpp:5961
void GetDispellableAuraList(WorldObject const *caster, uint32 dispelMask, DispelChargesList &dispelList, bool isReflect=false) const
Definition: Unit.cpp:4596
AttackerSet const & getAttackers() const
Definition: Unit.h:713
void RemoveUnitFlag2(UnitFlags2 flags)
Definition: Unit.h:839
void RemovePvpFlag(UnitPVPStateFlags flags)
Definition: Unit.h:869
void SetAI(UnitAI *newAI)
Definition: Unit.cpp:9540
AuraEffect * GetAuraEffectOfRankedSpell(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition: Unit.cpp:4478
bool SetCanTurnWhileFalling(bool enable)
Definition: Unit.cpp:13082
std::multimap< uint32, Aura * > AuraMap
Definition: Unit.h:633
void SendPetTalk(uint32 pettalk)
Definition: Unit.cpp:10013
bool IsVisible() const
Definition: Unit.cpp:8346
bool HasAuraType(AuraType auraType) const
Definition: Unit.cpp:4674
std::unique_ptr< Vignettes::VignetteData > m_vignette
Definition: Unit.h:1916
void RemoveOwnedAuras(std::function< bool(Aura const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3771
bool isMoving() const
Definition: Unit.h:1732
bool SetWalk(bool enable)
Definition: Unit.cpp:12707
float GetUnitBlockChance(WeaponAttackType attType, Unit const *victim) const
Definition: Unit.cpp:2730
bool HasStrongerAuraWithDR(SpellInfo const *auraSpellInfo, Unit *caster) const
Definition: Unit.cpp:4756
void EngageWithTarget(Unit *who)
Definition: Unit.cpp:8077
void AddInterruptMask(SpellAuraInterruptFlags flags, SpellAuraInterruptFlags2 flags2)
Definition: Unit.h:1558
void NearTeleportTo(Position const &pos, bool casting=false)
Definition: Unit.cpp:12327
void CalculateMeleeDamage(Unit *victim, CalcDamageInfo *damageInfo, WeaponAttackType attackType=BASE_ATTACK)
Definition: Unit.cpp:1272
SpellMissInfo MeleeSpellHitResult(Unit *victim, SpellInfo const *spellInfo) const override
Definition: Unit.cpp:2508
void setAttackTimer(WeaponAttackType type, uint32 time)
Definition: Unit.h:687
virtual bool UpdateStats(Stats stat)=0
void RemoveAllDynObjects()
Definition: Unit.cpp:5195
bool HasNpcFlag(NPCFlags flags) const
Definition: Unit.h:981
void GetAllMinionsByEntry(std::list< TempSummon * > &Minions, uint32 entry)
Definition: Unit.cpp:6235
uint32 GetArmor() const
Definition: Unit.h:762
float m_modMeleeHitChance
Definition: Unit.h:1471
virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType, AuraEffect const *) const
Definition: Unit.h:1493
void RemoveArenaAuras()
Definition: Unit.cpp:4289
void _RemoveAllAuraStatMods()
Definition: Unit.cpp:4452
ObjectGuid GetCritterGUID() const
Definition: Unit.h:1178
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, uint16 num=1)
Definition: Unit.cpp:3847
uint8 GetLevelForTarget(WorldObject const *) const override
Definition: Unit.h:747
int32 GetTotalAuraModifier(AuraType auraType) const
Definition: Unit.cpp:4929
void SetFullPower(Powers power)
Definition: Unit.h:812
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition: Unit.cpp:4101
void SetMovementAnimKitId(uint16 animKitId)
Definition: Unit.cpp:10559
void ClearUpdateMask(bool remove) override
Definition: Unit.cpp:13471
void StopAttackFaction(uint32 faction_id)
Definition: Unit.cpp:12475
bool HasScheduledAIChange() const
Definition: Unit.cpp:9595
void RemoveAreaAurasDueToLeaveWorld()
Definition: Unit.cpp:4209
float GetAPMultiplier(WeaponAttackType attType, bool normalized) const
Definition: Unit.cpp:10403
bool CanModifyStats() const
Definition: Unit.h:1505
float GetUnitCriticalChanceDone(WeaponAttackType attackType) const
Definition: Unit.cpp:2761
void RemoveCharmedBy(Unit *charmer)
Definition: Unit.cpp:11315
void RemoveMovementForce(ObjectGuid id)
Definition: Unit.cpp:13228
bool IsMounted() const
Definition: Unit.h:898
Trinity::Containers::FlatSet< AuraApplication *, VisibleAuraSlotCompare > m_visibleAurasToUpdate
Definition: Unit.h:1894
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:8920
void SetMaxHealth(uint64 val)
Definition: Unit.cpp:9377
float GetSpeedRate(UnitMoveType mtype) const
Definition: Unit.h:1644
void SendPetAIReaction(ObjectGuid guid)
Definition: Unit.cpp:10025
std::set< Unit * > AttackerSet
Definition: Unit.h:629
virtual void SetTarget(ObjectGuid const &)=0
void RemoveAppliedAuras(std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3758
virtual uint32 GetPowerIndex(Powers power) const =0
void CleanupBeforeRemoveFromMap(bool finalCleanup)
Definition: Unit.cpp:9668
void SetPowerType(Powers power, bool sendUpdate=true)
Definition: Unit.cpp:5534
bool IsGuardian() const
Definition: Unit.h:739
void UpdateStatBuffModForClient(Stats stat)
Definition: Unit.cpp:5144
Unit * GetVictim() const
Definition: Unit.h:715
void UpdatePetCombatState()
Definition: Unit.cpp:8704
std::vector< Unit * > UnitVector
Definition: Unit.h:631
uint32 GetExtraUnitMovementFlags() const
Definition: Unit.h:1670
int32 GetPower(Powers power) const
Definition: Unit.cpp:9401
int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const
Definition: Unit.cpp:7338
uint64 CountPctFromMaxHealth(int32 pct) const
Definition: Unit.h:785
float GetTotalAttackPowerValue(WeaponAttackType attType, bool includeWeapon=true) const
Definition: Unit.cpp:9285
bool HasExtraUnitMovementFlag2(uint32 f) const
Definition: Unit.h:1675
void UpdateOrientation(float orientation)
Only server-side orientation update, does not broadcast to client.
Definition: Unit.cpp:12447
bool IsUnderWater() const
Definition: Unit.cpp:3191
void SetBattlePetCompanionGUID(ObjectGuid guid)
Definition: Unit.h:1181
void SetSpeedRate(UnitMoveType mtype, float rate)
Definition: Unit.cpp:8525
void AddExtraAttacks(uint32 count)
Definition: Unit.cpp:2265
void RemovePlayerFromVision(Player *player)
Definition: Unit.cpp:6536
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
Definition: Unit.cpp:7376
float GetCreateStat(Stats stat) const
Definition: Unit.h:1400
bool IsHighestExclusiveAura(Aura const *aura, bool removeOtherAuraApplications=false)
Definition: Unit.cpp:13501
void GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer &aurasTriggeringProc, AuraApplicationList *procAuras, ProcEventInfo &eventInfo)
Definition: Unit.cpp:9892
void UpdateSplinePosition()
Definition: Unit.cpp:590
void SetOwnerGUID(ObjectGuid owner)
Definition: Unit.cpp:5986
DeathState getDeathState() const
Definition: Unit.h:1167
bool SetIgnoreMovementForces(bool ignore)
Definition: Unit.cpp:13256
virtual SpellInfo const * GetCastSpellInfo(SpellInfo const *spellInfo, TriggerCastFlags &triggerFlag) const
Definition: Unit.cpp:13678
Unit * GetFirstControlled() const
Definition: Unit.cpp:6414
float GetTotalAuraMultiplierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition: Unit.cpp:4959
void SetFacingTo(float const ori, bool force=true)
Definition: Unit.cpp:12653
ObjectGuid GetTransGUID() const override
Definition: Unit.cpp:11510
bool m_aiLocked
Definition: Unit.h:1975
void ApplyCastTimePercentMod(float val, bool apply)
Definition: Unit.cpp:10361
int32 GetMaxPositiveAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition: Unit.cpp:5049
std::vector< DynamicObject * > GetDynObjects(uint32 spellId) const
Definition: Unit.cpp:5170
virtual float GetHealthMultiplierForTarget(WorldObject const *) const
Definition: Unit.h:795
bool IsCritter() const
Definition: Unit.h:1010
void DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
Definition: Unit.cpp:1470
uint16 _movementAnimKitId
Definition: Unit.h:1993
bool CreateVehicleKit(uint32 id, uint32 creatureEntry, bool loading=false)
Definition: Unit.cpp:11443
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
bool IsMagnet() const
Definition: Unit.cpp:6388
std::unordered_set< AbstractFollower * > m_followingMe
Definition: Unit.h:1977
virtual void Update(uint32 time) override
Definition: Unit.cpp:420
bool IsInRaidWith(Unit const *unit) const
Definition: Unit.cpp:11546
void UnsummonAllTotems()
Definition: Unit.cpp:6559
AuraApplication * _CreateAuraApplication(Aura *aura, uint32 effMask)
Definition: Unit.cpp:3348
uint16 _meleeAnimKitId
Definition: Unit.h:1994
void _UnregisterAreaTrigger(AreaTrigger *areaTrigger)
Definition: Unit.cpp:5322
GameObjectList m_gameObj
Definition: Unit.h:1866
int32 SpellDamageBonusTaken(Unit *caster, SpellInfo const *spellProto, int32 pdamage, DamageEffectType damagetype) const
Definition: Unit.cpp:6809
void RemoveExtraUnitMovementFlag2(uint32 f)
Definition: Unit.h:1674
AuraMap m_ownedAuras
Definition: Unit.h:1875
std::array< float, MAX_STATS > m_createStats
Definition: Unit.h:1850
void ProcessPositionDataChanged(PositionFullTerrainStatus const &data) override
Definition: Unit.cpp:3201
Unit(bool isWorldObject)
Definition: Unit.cpp:308
bool IsInFeralForm() const
Definition: Unit.cpp:8909
DynamicObject * GetDynObject(uint32 spellId) const
Definition: Unit.cpp:5164
void SetLevel(uint8 lvl, bool sendUpdate=true)
Definition: Unit.cpp:9329
std::unique_ptr< Movement::MoveSpline > movespline
Definition: Unit.h:1766
bool _playHoverAnim
Definition: Unit.h:1990
static uint32 SpellCriticalDamageBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition: Unit.cpp:7090
void CalculateHoverHeight()
Definition: Unit.cpp:13336
std::pair< AuraMap::iterator, AuraMap::iterator > AuraMapBoundsNonConst
Definition: Unit.h:635
void RemoveUnitMovementFlag(uint32 f)
Definition: Unit.h:1662
static std::vector< AuraEffect * > CopyAuraEffectList(AuraEffectList const &list)
Definition: Unit.cpp:762
void RemoveBindSightAuras()
Definition: Unit.cpp:6546
void SendPlaySpellVisualKit(uint32 id, uint32 type, uint32 duration) const
Definition: Unit.cpp:11711
AuraApplicationMap m_appliedAuras
Definition: Unit.h:1876
CharmInfo * InitCharmInfo()
Definition: Unit.cpp:9748
void RemoveAllAttackers()
Definition: Unit.cpp:5881
void SetClass(uint8 classId)
Definition: Unit.h:753
virtual bool CanSwim() const
Definition: Unit.cpp:12313
virtual float GetNativeObjectScale() const
Definition: Unit.h:1565
uint32 GetDoTsByCaster(ObjectGuid casterGUID) const
Definition: Unit.cpp:4820
void BuildValuesUpdate(ByteBuffer *data, Player const *target) const override
Definition: Unit.cpp:13384
void RemoveFromWorld() override
Definition: Unit.cpp:9611
void SendPetActionFeedback(PetActionFeedback msg, uint32 spellId)
-------—Pet responses methods--------------—
Definition: Unit.cpp:10001
void AttackerStateUpdate(Unit *victim, WeaponAttackType attType=BASE_ATTACK, bool extra=false)
Definition: Unit.cpp:2166
bool IsOnOceanFloor() const
Definition: Unit.cpp:3196
void ScheduleAIChange()
Definition: Unit.cpp:9566
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4664
Powers CalculateDisplayPowerType() const
Definition: Unit.cpp:5575
virtual void UpdateMaxHealth()=0
uint32 HasUnitTypeMask(uint32 mask) const
Definition: Unit.h:736
std::array< float, MAX_MOVE_TYPE > m_speed_rate
Definition: Unit.h:1896
float GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const
Definition: Unit.cpp:9030
void _RegisterAuraEffect(AuraEffect *aurEff, bool apply)
Definition: Unit.cpp:3592
void SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo)
Definition: Unit.cpp:5439
void _EnterVehicle(Vehicle *vehicle, int8 seatId, AuraApplication const *aurApp=nullptr)
Definition: Unit.cpp:12125
float GetMeleeRange(Unit const *target) const
Definition: Unit.cpp:666
bool isDying() const
Definition: Unit.h:1165
void DoMeleeAttackIfReady()
Definition: Unit.cpp:2093
float GetStat(Stats stat) const
Definition: Unit.h:760
void SendMeleeAttackStop(Unit *victim=nullptr)
Definition: Unit.cpp:2452
void RemoveAurasWithMechanic(uint64 mechanicMaskToRemove, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, uint32 exceptSpellId=0, bool withEffectMechanics=false)
Definition: Unit.cpp:4162
void SendDurabilityLoss(Player *receiver, uint32 percent)
Definition: Unit.cpp:10522
int32 GetTotalAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition: Unit.cpp:4989
virtual float GetBlockPercent(uint8) const
Definition: Unit.h:973
void RemoveAllAuras()
Definition: Unit.cpp:4242
SpellHistory * GetSpellHistory()
Definition: Unit.h:1457
std::array< float, MAX_ATTACK > m_modAttackSpeedPct
Definition: Unit.h:1477
void HandleEmoteCommand(Emote emoteId, Player *target=nullptr, Trinity::IteratorPair< int32 const * > spellVisualKitIds={}, int32 sequenceVariation=0)
Definition: Unit.cpp:1598
bool IsControlledByPlayer() const
Definition: Unit.h:1193
Unit * m_charmer
Definition: Unit.h:1900
void SetVisibleAura(AuraApplication *aurApp)
Definition: Unit.cpp:682
DiminishingLevels GetDiminishing(DiminishingGroup group) const
Definition: Unit.cpp:8752
bool m_canDualWield
Definition: Unit.h:704
ObjectGuid GetCharmerGUID() const
Definition: Unit.h:1187
bool HasAuraWithMechanic(uint64 mechanicMask) const
Definition: Unit.cpp:4739
Minion * GetFirstMinion() const
Definition: Unit.cpp:6030
UnitStandStateType GetStandState() const
Definition: Unit.h:886
float SpellHealingPctDone(Unit *victim, SpellInfo const *spellProto) const
Definition: Unit.cpp:7234
UnitAI * GetScheduledChangeAI()
Definition: Unit.cpp:9587
uint16 _aiAnimKitId
Definition: Unit.h:1992
bool HasAuraTypeWithValue(AuraType auraType, int32 value) const
Definition: Unit.cpp:4705
bool HasBreakableByDamageAuraType(AuraType type, uint32 excludeAura=0) const
Definition: Unit.cpp:724
bool SetCharmedBy(Unit *charmer, CharmType type, AuraApplication const *aurApp=nullptr)
Definition: Unit.cpp:11142
bool IsAlwaysVisibleFor(WorldObject const *seer) const override
Definition: Unit.cpp:8315
void SetPetGUID(ObjectGuid guid)
Definition: Unit.h:1177
bool SetWaterWalking(bool enable)
Definition: Unit.cpp:12863
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:9937
void SetMaxPower(Powers power, int32 val)
Definition: Unit.cpp:9456
std::vector< std::pair< uint32, AuraApplication * > > AuraApplicationProcContainer
Definition: Unit.h:649
void SendTeleportPacket(Position const &pos)
Definition: Unit.cpp:12343
virtual void setDeathState(DeathState s)
Definition: Unit.cpp:8592
void SetCreatorGUID(ObjectGuid creator)
Definition: Unit.h:1173
void GetPartyMembers(std::list< Unit * > &units)
Definition: Unit.cpp:11565
void RemoveVehicleKit(bool onRemoveFromWorld=false)
Definition: Unit.cpp:11459
ObjectGuid LastCharmerGUID
Definition: Unit.h:1708
uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const
Definition: Unit.cpp:11902
UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const *target) const override
Definition: Unit.cpp:13360
float GetUnitDodgeChance(WeaponAttackType attType, Unit const *victim) const
Definition: Unit.cpp:2647
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const *spellInfo=nullptr)
Definition: Unit.cpp:1616
int32 GetMaxNegativeAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition: Unit.cpp:5059
void HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
Definition: Unit.cpp:8963
CombatManager & GetCombatManager()
Definition: Unit.h:1023
void SetUnitFlag(UnitFlags flags)
Definition: Unit.h:833
MeleeHitOutcome RollMeleeOutcomeAgainst(Unit const *victim, WeaponAttackType attType) const
Definition: Unit.cpp:2280
void UpdateMovementForcesModMagnitude()
Definition: Unit.cpp:13287
uint32 GetCreatureTypeMask() const
Definition: Unit.cpp:8898
bool InitTamedPet(Pet *pet, uint8 level, uint32 spell_id)
Definition: Unit.cpp:10485
bool HasAuraTypeWithTriggerSpell(AuraType auratype, uint32 triggerSpell) const
Definition: Unit.cpp:4714
bool HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition: Unit.cpp:4696
bool IsFlying() const
Definition: Unit.h:1735
void SetCritterGUID(ObjectGuid guid)
Definition: Unit.h:1179
AuraApplicationMap & GetAppliedAuras()
Definition: Unit.h:1274
void ClearBossEmotes(Optional< uint32 > zoneId={}, Player const *target=nullptr) const
Clears boss emotes frame.
Definition: Unit.cpp:13662
void RemoveMovementImpairingAuras(bool withRoot)
Definition: Unit.cpp:4154
bool isAttackReady(WeaponAttackType type=BASE_ATTACK) const
Definition: Unit.h:690
void SetVignette(uint32 vignetteId)
Definition: Unit.cpp:13759
void InitStatBuffMods()
Definition: Unit.cpp:5069
int32 m_procDeep
Definition: Unit.h:1859
int32 GetTotalAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition: Unit.cpp:5029
void ClearDiminishings()
Definition: Unit.cpp:8874
bool ApplyDiminishingToDuration(SpellInfo const *auraSpellInfo, int32 &duration, WorldObject *caster, DiminishingLevels previousLevel) const
Definition: Unit.cpp:8776
bool IsUninteractible() const
Definition: Unit.h:1037
std::vector< AreaTrigger * > GetAreaTriggers(uint32 spellId) const
Definition: Unit.cpp:5335
virtual void ProcessTerrainStatusUpdate(ZLiquidStatus oldLiquidStatus, Optional< LiquidData > const &newLiquidData)
Definition: Unit.cpp:3208
std::vector< GameObject * > GetGameObjects(uint32 spellId) const
Definition: Unit.cpp:5207
std::array< uint32, MAX_ATTACK > m_attackTimer
Definition: Unit.h:1478
bool IsServiceProvider() const
Definition: Unit.cpp:8068
MountCapabilityEntry const * GetMountCapability(uint32 mountType) const
Definition: Unit.cpp:7953
bool IsTotem() const
Definition: Unit.h:742
CombatManager m_combatManager
Definition: Unit.h:1966
void ChangeSeat(int8 seatId, bool next=true)
Definition: Unit.cpp:12172
void SetInFront(WorldObject const *target)
Definition: Unit.cpp:12647
void ApplyDiminishingAura(DiminishingGroup group, bool apply)
Definition: Unit.cpp:8857
AuraStateAurasMap m_auraStateAuras
Definition: Unit.h:1884
int32 GetResistance(SpellSchools school) const
Definition: Unit.h:769
AuraList & GetSingleCastAuras()
Definition: Unit.h:1323
bool IsAlwaysDetectableFor(WorldObject const *seer) const override
Definition: Unit.cpp:8335
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition: Unit.cpp:4506
Vehicle * GetVehicleKit() const
Definition: Unit.h:1711
bool CanCastSpellWhileMoving(SpellInfo const *spellInfo) const
Definition: Unit.cpp:3140
void PushAI(UnitAI *newAI)
Definition: Unit.cpp:9535
float m_modSpellHitChance
Definition: Unit.h:1473
void ValidateAttackersAndOwnTarget()
Definition: Unit.cpp:5809
Guardian * GetGuardianPet() const
Definition: Unit.cpp:6046
void resetAttackTimer(WeaponAttackType type=BASE_ATTACK)
Definition: Unit.cpp:630
Aura * GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4590
virtual void Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const *target)
Definition: Unit.cpp:13554
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:5407
virtual bool IsEngaged() const
Definition: Unit.h:1019
void RemoveAurasWithFamily(SpellFamilyNames family, flag128 const &familyFlag, ObjectGuid casterGUID)
Definition: Unit.cpp:4136
void _ApplyAuraEffect(Aura *aura, uint8 effIndex)
Definition: Unit.cpp:3390
void DeMorph()
Definition: Unit.cpp:3241
void RemoveAllMinionsByEntry(uint32 entry)
Definition: Unit.cpp:6245
AuraMap & GetOwnedAuras()
Definition: Unit.h:1264
void UpdateAllDamagePctDoneMods()
Definition: Unit.cpp:9191
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const
Definition: Unit.cpp:6894
virtual void Whisper(std::string_view text, Language language, Player *target, bool isBossWhisper=false)
Definition: Unit.cpp:13577
bool IsFalling() const
Definition: Unit.cpp:12308
bool AttackStop()
Definition: Unit.cpp:5781
std::array< float, MAX_STATS > m_floatStatNegBuff
Definition: Unit.h:1852
int32 GetCurrentSpellCastTime(uint32 spell_id) const
Definition: Unit.cpp:3112
float MeleeSpellMissChance(Unit const *victim, WeaponAttackType attType, SpellInfo const *spellInfo) const override
Definition: Unit.cpp:11797
void RemoveAurasOnEvade()
Definition: Unit.cpp:4303
bool IsHighestExclusiveAuraEffect(SpellInfo const *spellInfo, AuraType auraType, int32 effectAmount, uint32 auraEffectMask, bool removeOtherAuraApplications=false)
Definition: Unit.cpp:13515
void SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
Definition: Unit.cpp:9012
void SetShapeshiftForm(ShapeshiftForm form)
Definition: Unit.cpp:8904
float GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const *victim) const
Definition: Unit.cpp:2827
bool IsInPartyWith(Unit const *unit) const
Definition: Unit.cpp:11527
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3831
static void Kill(Unit *attacker, Unit *victim, bool durabilityLoss=true, bool skipSettingDeathState=false)
Definition: Unit.cpp:10591
bool m_cleanupDone
Definition: Unit.h:1983
SharedVisionList m_sharedVision
Definition: Unit.h:1903
void SetMeleeAnimKitId(uint16 animKitId)
Definition: Unit.cpp:10575
EnumFlag< SpellAuraInterruptFlags > m_interruptMask
Definition: Unit.h:1885
std::array< AuraEffectList, TOTAL_AURAS > m_modAuras
Definition: Unit.h:1881
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:7138
ObjectGuid GetTarget() const
Definition: Unit.h:1759
bool _isWalkingBeforeCharm
Are we walking before we were charmed?
Definition: Unit.h:1988
uint8 GetLevel() const
Definition: Unit.h:746
void SetMountDisplayId(uint32 mountDisplayId)
Definition: Unit.h:900
uint8 GetRace() const
Definition: Unit.h:749
void RemoveNotOwnSingleTargetAuras(bool onPhaseChange=false)
Definition: Unit.cpp:4022
virtual void SetDisplayId(uint32 displayId, bool setNative=false)
Definition: Unit.cpp:10148
void RemoveCharmAuras()
Definition: Unit.cpp:6551
bool IsInCombat() const
Definition: Unit.h:1043
bool IsWalking() const
Definition: Unit.h:1136
void SetWildBattlePetLevel(uint32 wildBattlePetLevel)
Definition: Unit.h:1250
bool IsSitState() const
Definition: Unit.cpp:10085
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed=true, bool withInstant=true)
Definition: Unit.cpp:3017
uint32 GetModelForForm(ShapeshiftForm form, uint32 spellId) const
Definition: Unit.cpp:11908
void RemoveUnitFlag(UnitFlags flags)
Definition: Unit.h:834
void SetAIAnimKitId(uint16 animKitId)
Definition: Unit.cpp:10543
void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath=false, bool forceDestination=false)
Definition: Unit.cpp:506
uint16 GetVirtualItemAppearanceMod(uint32 slot) const
Definition: Unit.cpp:13596
Unit * GetDemonCreator() const
Definition: Unit.cpp:6007
Player * m_playerMovingMe
Definition: Unit.h:1899
void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject *stealer, int32 stolenCharges=1)
Definition: Unit.cpp:3892
AreaTrigger * GetAreaTrigger(uint32 spellId) const
Definition: Unit.cpp:5329
uint32 GetDamageImmunityMask() const
Definition: Unit.cpp:7531
Player * GetControllingPlayer() const
Definition: Unit.cpp:6017
float GetWeaponProcChance() const
Definition: Unit.cpp:7862
Aura * _TryStackingOrRefreshingExistingAura(AuraCreateInfo &createInfo)
Definition: Unit.cpp:3246
ObjectGuid GetPetGUID() const
Definition: Unit.h:1176
void UpdateStatBuffMod(Stats stat)
Definition: Unit.cpp:5079
virtual void ExitVehicle(Position const *exitPosition=nullptr)
Definition: Unit.cpp:12204
float m_auraPctModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_PCT_END]
Definition: Unit.h:1889
void CombatStopWithPets(bool includingCast=false)
Definition: Unit.cpp:5855
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition: Unit.h:1442
bool BuildPacket(WorldPacket *packet)
Definition: UpdateData.cpp:40
void AddUpdateBlock()
Definition: UpdateData.h:49
uint32 GetBlock(uint32 index) const
Definition: UpdateMask.h:53
void Set(uint32 index)
Definition: UpdateMask.h:84
Unit * GetBase() const
Definition: Vehicle.h:49
Vehicle * RemovePassenger(WorldObject *passenger) override
Removes the passenger from the vehicle.
Definition: Vehicle.cpp:492
uint32 GetCreatureEntry() const
Definition: Vehicle.h:51
void Uninstall()
Removes all passengers and sets status to STATUS_UNINSTALLING. No new passengers can be added to the ...
Definition: Vehicle.cpp:109
void RelocatePassengers()
Relocate passengers. Must be called after m_base::Relocate.
Definition: Vehicle.cpp:554
SeatMap Seats
The collection of all seats on the vehicle. Including vacant ones.
Definition: Vehicle.h:67
std::string GetDebugInfo() const
Definition: Vehicle.cpp:970
SeatMap::const_iterator GetNextEmptySeat(int8 seatId, bool next) const
Gets the next empty seat based on current seat.
Definition: Vehicle.cpp:314
VehicleSeatAddon const * GetSeatAddonForSeatOfPassenger(Unit const *passenger) const
Gets the vehicle seat addon data for the seat of a passenger.
Definition: Vehicle.cpp:355
Milliseconds GetDespawnDelay()
Definition: Vehicle.cpp:962
void InstallAllAccessories(bool evading)
Definition: Vehicle.cpp:85
bool AddVehiclePassenger(Unit *unit, int8 seatId=-1)
Definition: Vehicle.cpp:421
constexpr uint32 GetMapId() const
Definition: Position.h:201
int8 GetTransSeat() const
Definition: Object.h:757
bool InSamePhase(PhaseShift const &phaseShift) const
Definition: Object.h:527
bool IsWithinDist3d(float x, float y, float z, float dist) const
Definition: Object.cpp:1122
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition: Object.cpp:1744
Map * GetMap() const
Definition: Object.h:624
ZLiquidStatus GetLiquidStatus() const
Definition: Object.h:550
void UpdateAllowedPositionZ(float x, float y, float &z, float *groundZ=nullptr) const
Definition: Object.cpp:1371
void AddToWorld() override
Definition: Object.cpp:1011
virtual bool IsAlwaysVisibleFor(WorldObject const *seer) const
Definition: Object.h:822
Unit * GetCharmerOrOwner() const
Definition: Object.cpp:2234
void RemoveFromWorld() override
Definition: Object.cpp:1017
InstanceScript * GetInstanceScript() const
Definition: Object.cpp:1042
virtual uint8 GetLevelForTarget(WorldObject const *) const
Definition: Object.h:598
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
Definition: Object.cpp:2670
Unit * GetCharmerOrOwnerOrSelf() const
Definition: Object.cpp:2244
void SendCombatLogMessage(WorldPackets::CombatLog::CombatLogServerPacket *combatLog) const
Definition: Object.cpp:1783
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
std::string GetDebugInfo() const override
Definition: Object.cpp:3785
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition: Object.cpp:2991
virtual bool IsAlwaysDetectableFor(WorldObject const *seer) const
Definition: Object.h:825
bool IsHostileTo(WorldObject const *target) const
Definition: Object.cpp:2860
PhaseShift & GetPhaseShift()
Definition: Object.h:523
Unit * GetOwner() const
Definition: Object.cpp:2229
ZoneScript * GetZoneScript() const
Definition: Object.h:630
TransportBase * GetTransport() const
Definition: Object.h:750
void setActive(bool isActiveObject)
Definition: Object.cpp:922
float GetFloorZ() const
Definition: Object.cpp:3755
std::string const & GetName() const
Definition: Object.h:555
bool IsWithinLOSInMap(WorldObject const *obj, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition: Object.cpp:1181
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const &data)
Definition: Object.cpp:999
void GetContactPoint(WorldObject const *obj, float &x, float &y, float &z, float distance2d=CONTACT_DISTANCE) const
Definition: Object.cpp:3430
Player * GetSpellModOwner() const
Definition: Object.cpp:2272
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition: Object.cpp:2252
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition: Object.cpp:1147
void SetIsStoredInWorldObjectGridContainer(bool apply)
Definition: Object.cpp:903
void AddToNotify(uint16 f)
Definition: Object.h:732
EventProcessor m_Events
Definition: Object.h:777
float GetVisibilityRange() const
Definition: Object.cpp:1447
virtual uint32 GetCastSpellXSpellVisualId(SpellInfo const *spellInfo) const
Definition: Object.cpp:3286
SpellMissInfo SpellHitResult(Unit *victim, SpellInfo const *spellInfo, bool canReflect=false) const
Definition: Object.cpp:2621
float GetDistance(WorldObject const *obj) const
Definition: Object.cpp:1078
uint32 GetAreaId() const
Definition: Object.h:546
uint32 GetZoneId() const
Definition: Object.h:545
MovementInfo m_movementInfo
Definition: Object.h:761
FlaggedValuesArray32< int32, uint32, ServerSideVisibilityType, TOTAL_SERVERSIDE_VISIBILITY_TYPES > m_serverSideVisibility
Definition: Object.h:619
bool IsFriendlyTo(WorldObject const *target) const
Definition: Object.cpp:2865
bool IsInMap(WorldObject const *obj) const
Definition: Object.cpp:1115
virtual void Update(uint32 diff)
Definition: Object.cpp:898
FactionTemplateEntry const * GetFactionTemplateEntry() const
Definition: Object.cpp:2679
virtual void UpdateObjectVisibility(bool forced=true)
Definition: Object.cpp:3650
virtual void CleanupsBeforeDelete(bool finalCleanup=true)
Definition: Object.cpp:981
void Initialize(ChatMsg chatType, Language language, WorldObject const *sender, WorldObject const *receiver, std::string_view message, uint32 achievementId=0, std::string_view channelName="", LocaleConstant locale=DEFAULT_LOCALE, std::string_view addonPrefix="")
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: ChatPackets.h:231
WorldPacket const * Write() override
std::vector< int32 > SpellVisualKitIDs
Definition: ChatPackets.h:194
WorldPacket const * Write() override
Optional< Spells::ContentTuningParams > ContentTuning
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< PowerUpdatePower > Powers
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
TaggedPosition< Position::XY > Direction
WorldPacket const * Write() override
WorldPacket const * Write() override
uint32 SequenceIndex
Unit movement packet index, incremented each time.
WorldPacket const * Write() override
uint32 SequenceIndex
Unit movement packet index, incremented each time.
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
TaggedPosition< Position::XYZ > Pos
Optional< ObjectGuid > TransportGUID
WorldPacket const * Write() override
::MovementForces::Container const * MovementForces
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * GetRawPacket() const
Definition: Packet.h:38
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: PetPackets.cpp:184
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
TaggedPosition< Position::XYZ > TargetPosition
Definition: SpellPackets.h:736
WorldPacket const * Write() override
WorldPacket const * Write() override
LocaleConstant GetSessionDbLocaleIndex() const
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
OpcodeServer
Definition: Opcodes.h:901
@ SMSG_MOVE_SPLINE_SET_PITCH_RATE
Definition: Opcodes.h:1609
@ SMSG_MOVE_SPLINE_SET_SWIM_SPEED
Definition: Opcodes.h:1614
@ SMSG_MOVE_SET_FLIGHT_SPEED
Definition: Opcodes.h:1581
@ SMSG_MOVE_SPLINE_SET_FLYING
Definition: Opcodes.h:1605
@ SMSG_MOVE_SET_FLIGHT_BACK_SPEED
Definition: Opcodes.h:1580
@ SMSG_MOVE_DISABLE_COLLISION
Definition: Opcodes.h:1546
@ SMSG_MOVE_UPDATE_PITCH_RATE
Definition: Opcodes.h:1640
@ SMSG_MOVE_SPLINE_SET_WALK_SPEED
Definition: Opcodes.h:1617
@ SMSG_MOVE_ENABLE_DOUBLE_JUMP
Definition: Opcodes.h:1552
@ SMSG_MOVE_ROOT
Definition: Opcodes.h:1559
@ SMSG_MOVE_SPLINE_SET_RUN_MODE
Definition: Opcodes.h:1611
@ SMSG_MOVE_DISABLE_GRAVITY
Definition: Opcodes.h:1548
@ SMSG_MOVE_SPLINE_SET_SWIM_BACK_SPEED
Definition: Opcodes.h:1613
@ SMSG_MOVE_SPLINE_DISABLE_COLLISION
Definition: Opcodes.h:1597
@ SMSG_MOVE_ENABLE_TRANSITION_BETWEEN_SWIM_AND_FLY
Definition: Opcodes.h:1555
@ SMSG_MOVE_UNROOT
Definition: Opcodes.h:1625
@ SMSG_MOVE_SPLINE_UNROOT
Definition: Opcodes.h:1621
@ SMSG_MOVE_SET_RUN_BACK_SPEED
Definition: Opcodes.h:1588
@ SMSG_MOVE_SPLINE_SET_HOVER
Definition: Opcodes.h:1606
@ SMSG_MOVE_SPLINE_SET_WATER_WALK
Definition: Opcodes.h:1618
@ SMSG_MOVE_SPLINE_SET_NORMAL_FALL
Definition: Opcodes.h:1608
@ SMSG_MOVE_ENABLE_INERTIA
Definition: Opcodes.h:1554
@ SMSG_MOVE_SPLINE_SET_TURN_RATE
Definition: Opcodes.h:1615
@ SMSG_MOVE_SET_NORMAL_FALL
Definition: Opcodes.h:1586
@ SMSG_MOVE_SPLINE_UNSET_HOVER
Definition: Opcodes.h:1623
@ SMSG_MOVE_UPDATE_FLIGHT_SPEED
Definition: Opcodes.h:1637
@ SMSG_MOVE_SET_PITCH_RATE
Definition: Opcodes.h:1587
@ SMSG_MOVE_SPLINE_SET_LAND_WALK
Definition: Opcodes.h:1607
@ SMSG_MOVE_UPDATE_FLIGHT_BACK_SPEED
Definition: Opcodes.h:1636
@ SMSG_MOVE_UPDATE_WALK_SPEED
Definition: Opcodes.h:1649
@ SMSG_MOVE_SET_CAN_TURN_WHILE_FALLING
Definition: Opcodes.h:1576
@ SMSG_MOVE_SPLINE_DISABLE_GRAVITY
Definition: Opcodes.h:1598
@ SMSG_MOVE_ENABLE_COLLISION
Definition: Opcodes.h:1551
@ SMSG_MOVE_SET_IGNORE_MOVEMENT_FORCES
Definition: Opcodes.h:1583
@ SMSG_MOVE_UNSET_IGNORE_MOVEMENT_FORCES
Definition: Opcodes.h:1630
@ SMSG_MOVE_UPDATE_SWIM_SPEED
Definition: Opcodes.h:1646
@ SMSG_MOVE_ENABLE_GRAVITY
Definition: Opcodes.h:1553
@ SMSG_MOVE_UPDATE_MOD_MOVEMENT_FORCE_MAGNITUDE
Definition: Opcodes.h:1639
@ SMSG_MOVE_UNSET_HOVERING
Definition: Opcodes.h:1629
@ SMSG_MOVE_UPDATE_TURN_RATE
Definition: Opcodes.h:1648
@ SMSG_MOVE_SPLINE_SET_RUN_BACK_SPEED
Definition: Opcodes.h:1610
@ SMSG_MOVE_SET_TURN_RATE
Definition: Opcodes.h:1592
@ SMSG_MOVE_SET_WATER_WALK
Definition: Opcodes.h:1595
@ SMSG_MOVE_SPLINE_ROOT
Definition: Opcodes.h:1601
@ SMSG_MOVE_SET_SWIM_SPEED
Definition: Opcodes.h:1591
@ SMSG_MOVE_UPDATE_RUN_SPEED
Definition: Opcodes.h:1644
@ SMSG_MOVE_SET_WALK_SPEED
Definition: Opcodes.h:1594
@ SMSG_MOVE_SET_HOVERING
Definition: Opcodes.h:1582
@ SMSG_MOVE_SET_MOD_MOVEMENT_FORCE_MAGNITUDE
Definition: Opcodes.h:1585
@ SMSG_MOVE_SPLINE_ENABLE_GRAVITY
Definition: Opcodes.h:1600
@ SMSG_MOVE_SET_CAN_FLY
Definition: Opcodes.h:1575
@ SMSG_MOVE_SPLINE_SET_RUN_SPEED
Definition: Opcodes.h:1612
@ SMSG_MOVE_DISABLE_INERTIA
Definition: Opcodes.h:1549
@ SMSG_MOVE_SPLINE_SET_FLIGHT_BACK_SPEED
Definition: Opcodes.h:1603
@ SMSG_MOVE_UPDATE_SWIM_BACK_SPEED
Definition: Opcodes.h:1645
@ SMSG_MOVE_DISABLE_DOUBLE_JUMP
Definition: Opcodes.h:1547
@ SMSG_MOVE_UNSET_CAN_FLY
Definition: Opcodes.h:1627
@ SMSG_MOVE_SPLINE_UNSET_FLYING
Definition: Opcodes.h:1622
@ SMSG_MOVE_SPLINE_SET_FLIGHT_SPEED
Definition: Opcodes.h:1604
@ SMSG_MOVE_SPLINE_STOP_SWIM
Definition: Opcodes.h:1620
@ SMSG_MOVE_SPLINE_START_SWIM
Definition: Opcodes.h:1619
@ SMSG_MOVE_UPDATE_RUN_BACK_SPEED
Definition: Opcodes.h:1643
@ SMSG_MOVE_SET_SWIM_BACK_SPEED
Definition: Opcodes.h:1590
@ SMSG_MOVE_UNSET_CAN_TURN_WHILE_FALLING
Definition: Opcodes.h:1628
@ SMSG_MOVE_SET_RUN_SPEED
Definition: Opcodes.h:1589
@ SMSG_MOVE_DISABLE_TRANSITION_BETWEEN_SWIM_AND_FLY
Definition: Opcodes.h:1550
@ SMSG_MOVE_SPLINE_ENABLE_COLLISION
Definition: Opcodes.h:1599
@ SMSG_MOVE_SET_LAND_WALK
Definition: Opcodes.h:1584
@ SMSG_MOVE_SPLINE_SET_FEATHER_FALL
Definition: Opcodes.h:1602
@ SMSG_MOVE_SPLINE_SET_WALK_MODE
Definition: Opcodes.h:1616
@ SMSG_MOVE_SET_FEATHER_FALL
Definition: Opcodes.h:1579
#define sWorld
Definition: World.h:931
@ CONFIG_CREATURE_FAMILY_FLEE_DELAY
Definition: World.h:315
@ CONFIG_DURABILITY_LOSS_IN_PVP
Definition: World.h:104
@ RATE_POWER_RAGE_INCOME
Definition: World.h:455
@ RATE_DURABILITY_LOSS_DAMAGE
Definition: World.h:527
@ RATE_DURABILITY_LOSS_ON_DEATH
Definition: World.h:526
@ CONFIG_LISTEN_RANGE_YELL
Definition: World.h:211
@ CONFIG_LISTEN_RANGE_SAY
Definition: World.h:209
@ CONFIG_LISTEN_RANGE_TEXTEMOTE
Definition: World.h:210
void apply(T *val)
Definition: ByteConverter.h:41
TimePoint Now()
Current chrono steady_clock time point.
Definition: GameTime.cpp:59
time_t GetGameTime()
Definition: GameTime.cpp:44
uint32 GetGameTimeMS()
Definition: GameTime.cpp:49
ItemContext GetContextForPlayer(MapDifficultyEntry const *mapDifficulty, Player const *player)
TC_GAME_API WorldObject * GetWorldObject(WorldObject const &, ObjectGuid const &)
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
TC_GAME_API HashMapHolder< Player >::MapType const & GetPlayers()
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Pet * GetPet(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreatureOrPetOrVehicle(WorldObject const &, ObjectGuid const &)
std::list< T, Alloc >::iterator RemoveUnique(std::list< T, Alloc > &list, T const &value)
Definition: ListUtils.h:27
auto MapEqualRange(M &map, typename M::key_type const &key)
Definition: IteratorPair.h:60
auto SelectRandomContainerElement(C const &container) -> typename std::add_const< decltype(*std::begin(container))>::type &
Definition: Containers.h:109
bool IsValidMapCoord(float c)
Definition: GridDefines.h:231
UpdateFieldFlag
Definition: UpdateField.h:34
std::unique_ptr< VignetteData > Create(VignetteEntry const *vignetteData, WorldObject const *owner)
Definition: Vignette.cpp:72
void Update(VignetteData &vignette, WorldObject const *owner)
Definition: Vignette.cpp:90
void Remove(VignetteData &vignette, WorldObject const *owner)
Definition: Vignette.cpp:100
TC_PROTO_API ::google::protobuf::internal::ExtensionIdentifier< ::google::protobuf::FieldOptions, ::google::protobuf::internal::MessageTypeTraits< ::bgs::protocol::FieldRestriction >, 11, false > valid
STL namespace.
ObjectGuid CasterGUID
int32 const * BaseAmount
ObjectGuid CastItemGUID
AuraCreateInfo & SetBaseAmount(int32 const *bp)
AuraCreateInfo & SetCaster(Unit *caster)
AuraCreateInfo & SetCasterGUID(ObjectGuid const &guid)
uint32 GetAuraEffectMask() const
SpellInfo const * GetSpellInfo() const
WeaponAttackType AttackType
Definition: Unit.h:539
ProcFlagsInit ProcAttacker
Definition: Unit.h:540
uint32 DamageSchoolMask
Definition: Unit.h:529
Unit * Target
Definition: Unit.h:528
uint32 TargetState
Definition: Unit.h:536
MeleeHitOutcome HitOutCome
Definition: Unit.h:543
Unit * Attacker
Definition: Unit.h:527
uint32 Damage
Definition: Unit.h:530
uint32 Blocked
Definition: Unit.h:534
uint32 Resist
Definition: Unit.h:533
uint32 CleanDamage
Definition: Unit.h:542
uint32 HitInfo
Definition: Unit.h:535
uint32 Absorb
Definition: Unit.h:532
uint32 OriginalDamage
Definition: Unit.h:531
ProcFlagsInit ProcVictim
Definition: Unit.h:541
CastSpellExtraArgs & AddSpellMod(SpellValueMod mod, int32 val)
Definition: SpellDefines.h:474
ObjectGuid OriginalCaster
Definition: SpellDefines.h:482
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:203
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:191
void SaveStayPosition()
Definition: Unit.cpp:12596
float _stayY
Definition: CharmInfo.h:153
void SetIsCommandFollow(bool val)
Definition: Unit.cpp:12586
bool IsCommandAttack()
Definition: Unit.cpp:12581
bool _isAtStay
Definition: CharmInfo.h:149
void InitPossessCreateSpells()
Definition: CharmInfo.cpp:74
void SetIsAtStay(bool val)
Definition: Unit.cpp:12617
bool IsFollowing()
Definition: Unit.cpp:12632
float _stayX
Definition: CharmInfo.h:152
void SetPetNumber(uint32 petnumber, bool statwindow)
Definition: CharmInfo.cpp:227
float _stayZ
Definition: CharmInfo.h:154
bool IsReturning()
Definition: Unit.cpp:12642
void SetIsFollowing(bool val)
Definition: Unit.cpp:12627
bool _isCommandFollow
Definition: CharmInfo.h:148
void SetIsReturning(bool val)
Definition: Unit.cpp:12637
void InitCharmCreateSpells()
Definition: CharmInfo.cpp:113
bool IsAtStay()
Definition: Unit.cpp:12622
bool _isFollowing
Definition: CharmInfo.h:150
bool _isCommandAttack
Definition: CharmInfo.h:147
void GetStayPosition(float &x, float &y, float &z)
Definition: Unit.cpp:12610
bool IsCommandFollow()
Definition: Unit.cpp:12591
void SetIsCommandAttack(bool val)
Definition: Unit.cpp:12576
bool _isReturning
Definition: CharmInfo.h:151
Unit * _unit
Definition: CharmInfo.h:138
EnumFlag< ChrRacesFlag > GetFlags() const
Definition: DB2Structure.h:851
uint32 absorbed_damage
Definition: Unit.h:405
WeaponAttackType attackType
Definition: Unit.h:408
bool MovementUpdate
Definition: Object.h:86
bool Vehicle
Definition: Object.h:91
EnumFlag< CreatureModelDataFlags > GetFlags() const
uint32 CreatureDisplayID
Definition: CreatureData.h:432
DeclinedName()=default
uint32 hitCount
Definition: Unit.h:375
uint32 hitTime
Definition: Unit.h:374
uint16 stack
Definition: Unit.h:373
InventoryType GetInventoryType() const
Definition: ItemTemplate.h:786
uint32 GetSubClass() const
Definition: ItemTemplate.h:778
uint32 GetDelay() const
Definition: ItemTemplate.h:804
Definition: Loot.h:281
void NotifyLootList(Map const *map) const
Definition: Loot.cpp:638
bool isLooted() const
Definition: Loot.h:307
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
Definition: Loot.cpp:745
void SetDungeonEncounterId(uint32 dungeonEncounterId)
Definition: Loot.h:305
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:759
int16 CosmeticParentMapID
int16 ParentMapID
MovementForceType Type
Definition: MovementInfo.h:155
uint32 TransportID
Definition: MovementInfo.h:153
TaggedPosition< Position::XYZ > Origin
Definition: MovementInfo.h:151
ObjectGuid ID
Definition: MovementInfo.h:150
TaggedPosition< Position::XYZ > Direction
Definition: MovementInfo.h:152
ObjectGuid guid
Definition: MovementInfo.h:30
void SetFallTime(uint32 fallTime)
Definition: MovementInfo.h:127
void RemoveMovementFlag(uint32 flag)
Definition: MovementInfo.h:111
struct MovementInfo::TransportInfo transport
bool HasMovementFlag(uint32 flag) const
Definition: MovementInfo.h:112
Position pos
Definition: MovementInfo.h:34
Optional< LiquidData > liquidInfo
Definition: MapDefines.h:165
void Reset()
Definition: Unit.h:612
bool Relocated
Definition: Unit.h:618
constexpr void SetOrientation(float orientation)
Definition: Position.h:71
constexpr float GetPositionX() const
Definition: Position.h:76
float m_positionZ
Definition: Position.h:55
constexpr float GetPositionY() const
Definition: Position.h:77
float GetExactDist2d(const float x, const float y) const
Definition: Position.h:106
float GetRelativeAngle(float x, float y) const
Definition: Position.h:136
std::string ToString() const
Definition: Position.cpp:128
float m_positionX
Definition: Position.h:53
float m_positionY
Definition: Position.h:54
constexpr Position(float x=0, float y=0, float z=0, float o=0)
Definition: Position.h:29
bool HasInArc(float arcangle, Position const *pos, float border=2.0f) const
Definition: Position.cpp:99
float GetAbsoluteAngle(float x, float y) const
Definition: Position.h:125
constexpr void GetPosition(float &x, float &y) const
Definition: Position.h:81
constexpr void Relocate(float x, float y)
Definition: Position.h:63
constexpr Position GetPosition() const
Definition: Position.h:84
constexpr bool IsInDist(float x, float y, float z, float dist) const
Definition: Position.h:143
void RelocateOffset(Position const &offset)
Definition: Position.cpp:34
constexpr float GetOrientation() const
Definition: Position.h:79
constexpr float GetPositionZ() const
Definition: Position.h:78
SpellNonMeleeDamage(Unit *_attacker, Unit *_target, SpellInfo const *_spellInfo, SpellCastVisual spellVisual, uint32 _schoolMask, ObjectGuid _castId=ObjectGuid::Empty)
Definition: Unit.cpp:302
ObjectGuid castId
Definition: Unit.h:553
Unit * target
Definition: Unit.h:551
uint32 HitInfo
Definition: Unit.h:563
uint32 damage
Definition: Unit.h:556
uint32 absorb
Definition: Unit.h:559
uint32 preHitHealth
Definition: Unit.h:567
SpellCastVisual SpellVisual
Definition: Unit.h:555
Unit * attacker
Definition: Unit.h:552
uint32 schoolMask
Definition: Unit.h:558
SpellInfo const * Spell
Definition: Unit.h:554
bool periodicLog
Definition: Unit.h:561
uint32 cleanDamage
Definition: Unit.h:565
uint32 originalDamage
Definition: Unit.h:557
uint32 resist
Definition: Unit.h:560
uint32 blocked
Definition: Unit.h:562
AuraEffect const * auraEff
Definition: Unit.h:575
EnumFlag< SpellShapeshiftFormFlags > GetFlags() const
EnumFlag< SummonPropertiesFlags > GetFlags() const
void Update(int32 diff)
Definition: Timer.h:121
bool Passed() const
Definition: Timer.h:131
void Reset(int32 expiry)
Definition: Timer.h:136
UpdateFieldArray< std::string, 5, 0, 1 > Name
Definition: UpdateFields.h:469
UpdateField< uint8, 64, 82 > SheatheState
Definition: UpdateFields.h:346
UpdateField< uint8, 32, 62 > StandState
Definition: UpdateFields.h:327
UpdateField< float, 32, 55 > NativeXDisplayScale
Definition: UpdateFields.h:320
UpdateField< float, 64, 73 > ModSpellHaste
Definition: UpdateFields.h:337
UpdateField< int64, 32, 33 > MaxHealth
Definition: UpdateFields.h:294
UpdateField< float, 64, 71 > ModCastingSpeed
Definition: UpdateFields.h:335
UpdateFieldArray< uint32, 2, 127, 128 > NpcFlags
Definition: UpdateFields.h:392
UpdateField< int32, 0, 5 > DisplayID
Definition: UpdateFields.h:266
UpdateField< ObjectGuid, 0, 14 > CharmedBy
Definition: UpdateFields.h:276
UpdateField< float, 64, 74 > ModHaste
Definition: UpdateFields.h:338
UpdateField< float, 32, 51 > DisplayScale
Definition: UpdateFields.h:316
UpdateField< int32, 32, 34 > Level
Definition: UpdateFields.h:295
UpdateField< uint8, 0, 29 > DisplayPower
Definition: UpdateFields.h:291
UpdateFieldArray< int32, 4, 178, 187 > StatNegBuff
Definition: UpdateFields.h:402
UpdateField< ObjectGuid, 0, 11 > Charm
Definition: UpdateFields.h:273
UpdateFieldArray< int32, 4, 178, 183 > StatPosBuff
Definition: UpdateFields.h:401
UpdateField< uint8, 64, 85 > ShapeshiftForm
Definition: UpdateFields.h:350
UpdateField< uint8, 64, 66 > AnimTier
Definition: UpdateFields.h:330
UpdateFieldArray< uint32, 2, 175, 176 > AttackRoundBaseTime
Definition: UpdateFields.h:399
UpdateField< uint32, 32, 47 > AuraState
Definition: UpdateFields.h:311
UpdateField< float, 64, 75 > ModRangedHaste
Definition: UpdateFields.h:339
UpdateField< float, 64, 76 > ModHasteRegen
Definition: UpdateFields.h:340
UpdateFieldArray< int32, 10, 130, 131 > Power
Definition: UpdateFields.h:394
UpdateField< int32, 32, 54 > NativeDisplayID
Definition: UpdateFields.h:319
UpdateFieldArray< UF::VisibleItem, 3, 171, 172 > VirtualItems
Definition: UpdateFields.h:398
UpdateField< ObjectGuid, 0, 15 > SummonedBy
Definition: UpdateFields.h:277
UpdateField< int64, 0, 31 > Health
Definition: UpdateFields.h:293
UpdateFieldArray< int32, 10, 130, 141 > MaxPower
Definition: UpdateFields.h:395
UpdateField< uint32, 32, 48 > RangedAttackRoundBaseTime
Definition: UpdateFields.h:313
UpdateField< uint16, 0, 4 > ItemAppearanceModID
Definition: UpdateFields.h:241
UpdateField< uint16, 0, 5 > ItemVisual
Definition: UpdateFields.h:242
UpdateField< int32, 0, 1 > ItemID
Definition: UpdateFields.h:238
UF::ObjectData::Base ObjectMask
Definition: Unit.h:1833
void operator()(Player const *player) const
Definition: Unit.cpp:13445
bool operator()(AuraApplication *left, AuraApplication *right) const
Definition: Unit.cpp:13727
VehicleExitParameters ExitParameter