TrinityCore
Loading...
Searching...
No Matches
Unit.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Unit.h"
19#include "AbstractFollower.h"
20#include "Battlefield.h"
21#include "BattlefieldMgr.h"
22#include "Battleground.h"
23#include "BattlegroundPackets.h"
24#include "BattlegroundScore.h"
25#include "CellImpl.h"
26#include "CharacterCache.h"
27#include "ChatPackets.h"
28#include "ChatTextBuilder.h"
29#include "CombatLogPackets.h"
30#include "CombatPackets.h"
31#include "Common.h"
32#include "ConditionMgr.h"
33#include "Containers.h"
34#include "CreatureAI.h"
35#include "CreatureAIImpl.h"
36#include "CreatureGroups.h"
37#include "Formulas.h"
38#include "GameClient.h"
39#include "GameObjectAI.h"
40#include "GameTime.h"
41#include "GridNotifiersImpl.h"
42#include "Group.h"
43#include "InstanceSaveMgr.h"
44#include "InstanceScript.h"
45#include "Item.h"
46#include "Log.h"
47#include "LootMgr.h"
48#include "MiscPackets.h"
49#include "MotionMaster.h"
50#include "MovementGenerator.h"
51#include "MovementPackets.h"
52#include "MoveSpline.h"
53#include "MoveSplineInit.h"
54#include "ObjectAccessor.h"
55#include "ObjectMgr.h"
56#include "Opcodes.h"
57#include "OutdoorPvP.h"
59#include "PassiveAI.h"
60#include "PetAI.h"
61#include "Pet.h"
62#include "PetPackets.h"
63#include "Player.h"
64#include "PlayerAI.h"
65#include "QuestDef.h"
66#include "ReputationMgr.h"
67#include "ScheduledChangeAI.h"
68#include "SpellAuraEffects.h"
69#include "SpellAuras.h"
70#include "Spell.h"
71#include "SpellInfo.h"
72#include "SpellHistory.h"
73#include "SpellMgr.h"
74#include "SpellPackets.h"
75#include "StringConvert.h"
76#include "TemporarySummon.h"
77#include "Transport.h"
78#include "Totem.h"
79#include "UnitAI.h"
80#include "UpdateFieldFlags.h"
81#include "Util.h"
82#include "Vehicle.h"
83#include "World.h"
84#include "WorldPacket.h"
85#include "WorldSession.h"
86#include <cmath>
87
89{
90 2.5f, // MOVE_WALK
91 7.0f, // MOVE_RUN
92 4.5f, // MOVE_RUN_BACK
93 4.722222f, // MOVE_SWIM
94 2.5f, // MOVE_SWIM_BACK
95 3.141594f, // MOVE_TURN_RATE
96 7.0f, // MOVE_FLIGHT
97 4.5f, // MOVE_FLIGHT_BACK
98 3.14f // MOVE_PITCH_RATE
99};
100
102{
103 2.5f, // MOVE_WALK
104 7.0f, // MOVE_RUN
105 4.5f, // MOVE_RUN_BACK
106 4.722222f, // MOVE_SWIM
107 2.5f, // MOVE_SWIM_BACK
108 3.141594f, // MOVE_TURN_RATE
109 7.0f, // MOVE_FLIGHT
110 4.5f, // MOVE_FLIGHT_BACK
111 3.14f // MOVE_PITCH_RATE
112};
113
114DamageInfo::DamageInfo(Unit* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, DamageEffectType damageType, WeaponAttackType attackType)
115 : m_attacker(attacker), m_victim(victim), m_damage(damage), m_spellInfo(spellInfo), m_schoolMask(schoolMask), m_damageType(damageType), m_attackType(attackType),
116 m_absorb(0), m_resist(0), m_block(0), m_hitMask(0)
117{
118}
119
121 : m_attacker(dmg1.m_attacker), m_victim(dmg1.m_victim), m_damage(dmg1.m_damage + dmg2.m_damage), m_spellInfo(dmg1.m_spellInfo), m_schoolMask(SpellSchoolMask(dmg1.m_schoolMask | dmg2.m_schoolMask)),
122 m_damageType(dmg1.m_damageType), m_attackType(dmg1.m_attackType), m_absorb(dmg1.m_absorb + dmg2.m_absorb), m_resist(dmg1.m_resist + dmg2.m_resist), m_block(dmg1.m_block), m_hitMask(dmg1.m_hitMask | dmg2.m_hitMask)
123{
124}
125
126DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo) : DamageInfo(DamageInfo(dmgInfo, 0), DamageInfo(dmgInfo, 1))
127{
128}
129
130DamageInfo::DamageInfo(CalcDamageInfo const& dmgInfo, uint8 damageIndex)
131 : m_attacker(dmgInfo.Attacker), m_victim(dmgInfo.Target), m_damage(dmgInfo.Damages[damageIndex].Damage), m_spellInfo(nullptr), m_schoolMask(SpellSchoolMask(dmgInfo.Damages[damageIndex].DamageSchoolMask)),
132 m_damageType(DIRECT_DAMAGE), m_attackType(dmgInfo.AttackType), m_absorb(dmgInfo.Damages[damageIndex].Absorb), m_resist(dmgInfo.Damages[damageIndex].Resist), m_block(dmgInfo.Blocked), m_hitMask(0)
133{
134 switch (dmgInfo.TargetState)
135 {
138 break;
141 break;
142 }
143
146
147 if (dmgInfo.HitInfo & HITINFO_FULL_RESIST)
149
150 if (m_block)
152
153 bool const damageNullified = (dmgInfo.HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 ||
155 switch (dmgInfo.HitOutCome)
156 {
157 case MELEE_HIT_MISS:
159 break;
160 case MELEE_HIT_DODGE:
162 break;
163 case MELEE_HIT_PARRY:
165 break;
166 case MELEE_HIT_EVADE:
168 break;
169 case MELEE_HIT_BLOCK:
172 case MELEE_HIT_NORMAL:
173 if (!damageNullified)
175 break;
176 case MELEE_HIT_CRIT:
177 if (!damageNullified)
179 break;
180 }
181}
182
183DamageInfo::DamageInfo(SpellNonMeleeDamage const& spellNonMeleeDamage, DamageEffectType damageType, WeaponAttackType attackType, uint32 hitMask)
184 : m_attacker(spellNonMeleeDamage.attacker), m_victim(spellNonMeleeDamage.target), m_damage(spellNonMeleeDamage.damage),
185 m_spellInfo(sSpellMgr->GetSpellInfo(spellNonMeleeDamage.SpellID)), m_schoolMask(SpellSchoolMask(spellNonMeleeDamage.schoolMask)), m_damageType(damageType),
186 m_attackType(attackType), m_absorb(spellNonMeleeDamage.absorb), m_resist(spellNonMeleeDamage.resist), m_block(spellNonMeleeDamage.blocked), m_hitMask(hitMask)
187{
188 if (spellNonMeleeDamage.blocked)
190 if (spellNonMeleeDamage.absorb)
192}
193
195{
196 amount = std::max(amount, -static_cast<int32>(GetDamage()));
197 m_damage += amount;
198}
199
201{
202 amount = std::min(amount, GetDamage());
203 m_absorb += amount;
204 m_damage -= amount;
206}
207
209{
210 amount = std::min(amount, GetDamage());
211 m_resist += amount;
212 m_damage -= amount;
213 if (!m_damage)
214 {
217 }
218}
219
221{
222 amount = std::min(amount, GetDamage());
223 m_block += amount;
224 m_damage -= amount;
226 if (!m_damage)
227 {
230 }
231}
232
234{
235 return m_hitMask;
236}
237
238HealInfo::HealInfo(Unit* healer, Unit* target, uint32 heal, SpellInfo const* spellInfo, SpellSchoolMask schoolMask)
239 : _healer(healer), _target(target), _heal(heal), _effectiveHeal(0), _absorb(0), _spellInfo(spellInfo), _schoolMask(schoolMask), _hitMask(0)
240{
241}
242
244{
245 amount = std::min(amount, GetHeal());
246 _absorb += amount;
247 _heal -= amount;
248 amount = std::min(amount, GetEffectiveHeal());
249 _effectiveHeal -= amount;
251}
252
254{
255 return _hitMask;
256}
257
259 uint32 typeMask, uint32 spellTypeMask,
260 uint32 spellPhaseMask, uint32 hitMask,
261 Spell* spell, DamageInfo* damageInfo,
262 HealInfo* healInfo) :
263 _actor(actor), _actionTarget(actionTarget),
264 _typeMask(typeMask), _spellTypeMask(spellTypeMask),
265 _spellPhaseMask(spellPhaseMask), _hitMask(hitMask), _spell(spell),
266 _damageInfo(damageInfo), _healInfo(healInfo)
267{ }
268
270{
271 if (_spell)
272 return _spell->GetSpellInfo();
273 if (_damageInfo)
274 return _damageInfo->GetSpellInfo();
275 if (_healInfo)
276 return _healInfo->GetSpellInfo();
277 return nullptr;
278}
279
281{
282 if (_spell)
283 return _spell->GetSpellInfo()->GetSchoolMask();
284 if (_damageInfo)
285 return _damageInfo->GetSchoolMask();
286 if (_healInfo)
287 return _healInfo->GetSchoolMask();
289}
290
291DispelableAura::DispelableAura(Aura* aura, int32 dispelChance, uint8 dispelCharges) :
292 _aura(aura), _chance(dispelChance), _charges(dispelCharges)
293{
294}
295
297
299{
300 return roll_chance_i(_chance);
301}
302
303Unit::Unit(bool isWorldObject) :
304 WorldObject(isWorldObject), m_lastSanctuaryTime(0), LastCharmerGUID(), movespline(new Movement::MoveSpline()),
305 m_ControlledByPlayer(false), m_AutoRepeatFirstCast(false), m_procDeep(0), m_transformSpell(0),
306 m_removedAurasCount(0), m_charmer(nullptr), m_charmed(nullptr),
307 i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_vehicle(nullptr), m_vehicleKit(nullptr),
308 m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this), m_threatManager(this),
309 m_aiLocked(false), m_comboTarget(nullptr), m_comboPoints(0), _spellHistory(new SpellHistory(this))
310{
313
315
322
323 m_canDualWield = false;
324
326
327 m_state = 0;
329
330 for (uint8 i = 0; i < CURRENT_MAX_SPELL; ++i)
331 m_currentSpells[i] = nullptr;
332
333 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
334 m_SummonSlot[i].Clear();
335
336 for (uint8 i = 0; i < MAX_GAMEOBJECT_SLOT; ++i)
337 m_ObjectSlot[i].Clear();
338
340
341 m_interruptMask = 0;
342 m_canModifyStats = false;
343
344 for (uint8 i = 0; i < UNIT_MOD_END; ++i)
345 {
350 }
351 // implement 50% base damage from offhand
353
354 for (uint32 i = 0; i < uint32(AttackPowerModIndex::End); ++i)
355 {
359 }
360
361 for (uint8 i = 0; i < MAX_ATTACK; ++i)
362 {
365
366 m_weaponDamage[i][MINDAMAGE][1] = 0.f;
367 m_weaponDamage[i][MAXDAMAGE][1] = 0.f;
368 }
369
370 for (uint8 i = 0; i < MAX_STATS; ++i)
371 m_createStats[i] = 0.0f;
372
373 m_attacking = nullptr;
374 m_modMeleeHitChance = 0.0f;
376 m_modSpellHitChance = 0.0f;
378
379 m_lastManaUse = 0;
380
381 for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
382 m_speed_rate[i] = 1.0f;
383
384 m_charmInfo = nullptr;
385 _gameClientMovingMe = nullptr;
386
387 // remove aurastates allowing special moves
388 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
389 m_reactiveTimer[i] = 0;
390
391 m_cleanupDone = false;
393
395
396 _lastLiquid = nullptr;
397
398 _oldFactionId = 0;
399 _isWalkingBeforeCharm = false;
400 _instantCast = false;
401 _isCombatDisallowed = false;
402
404}
405
407// Methods of class Unit
409{
410 // set current spells as deletable
411 for (uint8 i = 0; i < CURRENT_MAX_SPELL; ++i)
412 if (m_currentSpells[i])
413 {
415 m_currentSpells[i] = nullptr;
416 }
417
419
421
422 delete std::exchange(i_motionMaster, nullptr);
423 delete std::exchange(m_charmInfo, nullptr);
424 delete std::exchange(movespline, nullptr);
425 delete std::exchange(_spellHistory, nullptr);
426
429 ASSERT(m_attackers.empty());
430 ASSERT(m_sharedVision.empty());
431 ASSERT(m_Controlled.empty());
432 ASSERT(m_appliedAuras.empty());
433 ASSERT(m_ownedAuras.empty());
434 ASSERT(m_removedAuras.empty());
435 ASSERT(m_gameObj.empty());
436 ASSERT(m_dynObj.empty());
438}
439
441{
442 // WARNING! Order of execution here is important, do not change.
443 // Spells must be processed with event system BEFORE they go to _UpdateSpells.
444 // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
445 WorldObject::Update(p_time);
446
448
449 if (!IsInWorld())
450 return;
451
452 _UpdateSpells(p_time);
453
454 // If this is set during update SetCantProc(false) call is missing somewhere in the code
455 // Having this would prevent spells from being proced, so let's crash
457
458 m_combatManager.Update(p_time);
459
462 {
463 while (!extraAttacksTargets.empty())
464 {
465 auto itr = extraAttacksTargets.begin();
466 ObjectGuid targetGuid = itr->first;
467 uint32 count = itr->second;
468 extraAttacksTargets.erase(itr);
469 if (Unit* victim = ObjectAccessor::GetUnit(*this, targetGuid))
470 HandleProcExtraAttackFor(victim, count);
471 }
473 }
474
475 // not implemented before 3.0.2
476 if (uint32 base_att = getAttackTimer(BASE_ATTACK))
477 setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time));
478 if (uint32 ranged_att = getAttackTimer(RANGED_ATTACK))
479 setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time));
480 if (uint32 off_att = getAttackTimer(OFF_ATTACK))
481 setAttackTimer(OFF_ATTACK, (p_time >= off_att ? 0 : off_att - p_time));
482
483 // update abilities available only for fraction of time
484 UpdateReactives(p_time);
485
486 if (IsAlive())
487 {
491 }
492
493 UpdateSplineMovement(p_time);
494 i_motionMaster->Update(p_time);
495
496 // Wait with the aura interrupts until we have updated our movement generators and position
497 if (GetTypeId() == TYPEID_PLAYER)
499 else if (!movespline->Finalized())
501
502 // All position info based actions have been executed, reset info
504
507 RefreshAI();
508}
509
511{
513
514 // SMSG_FLIGHT_SPLINE_SYNC for cyclic splines
516}
517
519{
520 if (Player const* player = ToPlayer())
521 return player->GetWeaponForAttack(OFF_ATTACK, true) != nullptr;
522
523 return CanDualWield();
524}
525
526void Unit::MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath, bool forceDestination)
527{
528 std::function<void(Movement::MoveSplineInit&)> initializer = [=](Movement::MoveSplineInit& init)
529 {
530 init.MoveTo(x, y, z, generatePath, forceDestination);
531 init.SetVelocity(speed);
532 };
534}
535
537{
538 if (movespline->Finalized())
539 return;
540
541 movespline->updateState(t_diff);
542 bool arrived = movespline->Finalized();
543
544 if (arrived)
545 {
547
550 }
551
553}
554
556{
558
560 {
562 pos.m_positionX = loc.x;
563 pos.m_positionY = loc.y;
564 pos.m_positionZ = loc.z;
566
567 if (TransportBase* transport = GetDirectTransport())
568 transport->CalculatePassengerPosition(loc.x, loc.y, loc.z, &loc.orientation);
569 else
570 return;
571 }
572
575
576 UpdatePosition(loc.x, loc.y, loc.z, loc.orientation);
577}
578
580{
582 return;
583
585 flightSplineSync.Guid = GetGUID();
586 flightSplineSync.SplineDist = float(movespline->timePassed()) / movespline->Duration();
587 SendMessageToSet(flightSplineSync.Write(), true);
588}
589
591{
592 // TODO: Check if orientation transport offset changed instead of only global orientation
595
598}
599
605
610
611bool Unit::IsWithinCombatRange(Unit const* obj, float dist2compare) const
612{
613 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
614 return false;
615
616 float dx = GetPositionX() - obj->GetPositionX();
617 float dy = GetPositionY() - obj->GetPositionY();
618 float dz = GetPositionZ() - obj->GetPositionZ();
619 float distsq = dx * dx + dy * dy + dz * dz;
620
621 float sizefactor = GetCombatReach() + obj->GetCombatReach();
622 float maxdist = dist2compare + sizefactor;
623
624 return distsq < maxdist * maxdist;
625}
626
627bool Unit::IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const
628{
629 if (!obj || !IsInMap(obj) || !InSamePhase(obj))
630 return false;
631
632 float dx = pos.GetPositionX() - obj->GetPositionX();
633 float dy = pos.GetPositionY() - obj->GetPositionY();
634 float dz = pos.GetPositionZ() - obj->GetPositionZ();
635 float distsq = dx*dx + dy*dy + dz*dz;
636
637 float maxdist = GetMeleeRange(obj);
638
639 return distsq <= maxdist * maxdist;
640}
641
642float Unit::GetMeleeRange(Unit const* target) const
643{
644 float range = GetCombatReach() + target->GetCombatReach() + 4.0f / 3.0f;
645 return std::max(range, NOMINAL_MELEE_RANGE);
646}
647
649{
650 VisibleAuraMap::const_iterator itr = m_visibleAuras.find(slot);
651 if (itr != m_visibleAuras.end())
652 return itr->second;
653 return 0;
654}
655
657{
658 m_visibleAuras[slot]=aur;
659 UpdateAuraForGroup(slot);
660}
661
663{
664 m_visibleAuras.erase(slot);
665 UpdateAuraForGroup(slot);
666}
667
669{
670 m_interruptMask = 0;
671 for (AuraApplicationList::const_iterator i = m_interruptableAuras.begin(); i != m_interruptableAuras.end(); ++i)
672 m_interruptMask |= (*i)->GetBase()->GetSpellInfo()->AuraInterruptFlags;
673
675 if (spell->getState() == SPELL_STATE_CASTING)
676 m_interruptMask |= spell->m_spellInfo->ChannelInterruptFlags;
677}
678
679bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag96 familyFlags) const
680{
681 if (!HasAuraType(auraType))
682 return false;
683 AuraEffectList const& auras = GetAuraEffectsByType(auraType);
684 for (AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
685 if (SpellInfo const* iterSpellProto = (*itr)->GetSpellInfo())
686 if (iterSpellProto->SpellFamilyName == familyName && iterSpellProto->SpellFamilyFlags & familyFlags)
687 return true;
688 return false;
689}
690
692{
693 AuraEffectList const& auras = GetAuraEffectsByType(type);
694 for (AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
695 if ((!excludeAura || excludeAura != (*itr)->GetSpellInfo()->Id) && //Avoid self interrupt of channeled Crowd Control spells like Seduction
696 ((*itr)->GetSpellInfo()->AuraInterruptFlags & AURA_INTERRUPT_FLAG_TAKE_DAMAGE))
697 return true;
698 return false;
699}
700
701bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) const
702{
703 uint32 excludeAura = 0;
704 if (Spell* currentChanneledSpell = excludeCasterChannel ? excludeCasterChannel->GetCurrentSpell(CURRENT_CHANNELED_SPELL) : nullptr)
705 excludeAura = currentChanneledSpell->GetSpellInfo()->Id; //Avoid self interrupt of channeled Crowd Control spells like Seduction
706
712}
713
714/*static*/ void Unit::DealDamageMods(Unit const* victim, uint32& damage, uint32* absorb)
715{
716 if (!victim || !victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
717 {
718 if (absorb)
719 *absorb += damage;
720 damage = 0;
721 }
722}
723
724/*static*/ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
725{
726 uint32 rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0);
727
728 if (UnitAI* victimAI = victim->GetAI())
729 victimAI->DamageTaken(attacker, damage, damagetype, spellProto);
730
731 if (UnitAI* attackerAI = attacker ? attacker->GetAI() : nullptr)
732 attackerAI->DamageDealt(victim, damage, damagetype);
733
734 // Hook for OnDamage Event
735 sScriptMgr->OnDamage(attacker, victim, damage);
736
737 // Signal to pets that their owner was attacked - except when DOT.
738 if (attacker != victim && damagetype != DOT)
739 {
740 for (Unit* controlled : victim->m_Controlled)
741 if (Creature* cControlled = controlled->ToCreature())
742 if (CreatureAI* controlledAI = cControlled->AI())
743 controlledAI->OwnerAttackedBy(attacker);
744 }
745
746 if (Player* player = victim->ToPlayer())
747 if (player->GetCommandStatus(CHEAT_GOD))
748 return 0;
749
750 if (damagetype != NODAMAGE)
751 {
752 // interrupting auras with AURA_INTERRUPT_FLAG_DAMAGE before checking !damage (absorbed damage breaks that type of auras)
753 if (spellProto)
754 {
757 }
758 else
760
761 // interrupt spells with SPELL_INTERRUPT_FLAG_ABORT_ON_DMG on absorbed damage (no dots)
762 if (!damage && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage)
763 {
764 if (victim != attacker && victim->GetTypeId() == TYPEID_PLAYER)
765 {
766 if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
767 if (spell->getState() == SPELL_STATE_PREPARING)
768 {
769 uint32 interruptFlags = spell->m_spellInfo->InterruptFlags;
770 if ((interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG) != 0)
771 victim->InterruptNonMeleeSpells(false);
772 }
773 }
774 }
775
776 // We're going to call functions which can modify content of the list during iteration over it's elements
777 // Let's copy the list so we can prevent iterator invalidation
779 // copy damage to casters of this aura
780 for (AuraEffectList::iterator i = vCopyDamageCopy.begin(); i != vCopyDamageCopy.end(); ++i)
781 {
782 // Check if aura was removed during iteration - we don't need to work on such auras
783 if (!((*i)->GetBase()->IsAppliedOnTarget(victim->GetGUID())))
784 continue;
785 // check damage school mask
786 if (((*i)->GetMiscValue() & damageSchoolMask) == 0)
787 continue;
788
789 Unit* shareDamageTarget = (*i)->GetCaster();
790 if (!shareDamageTarget)
791 continue;
792 SpellInfo const* spell = (*i)->GetSpellInfo();
793
794 uint32 share = CalculatePct(damage, (*i)->GetAmount());
795
797 Unit::DealDamageMods(shareDamageTarget, share, nullptr);
798 Unit::DealDamage(attacker, shareDamageTarget, share, nullptr, NODAMAGE, spell->GetSchoolMask(), spell, false);
799 }
800 }
801
802 // Rage from Damage made (only from direct weapon damage)
803 if (attacker && cleanDamage && damagetype == DIRECT_DAMAGE && attacker != victim && attacker->GetPowerType() == POWER_RAGE)
804 {
805 uint32 weaponSpeedHitFactor;
806
807 switch (cleanDamage->attackType)
808 {
809 case BASE_ATTACK:
810 case OFF_ATTACK:
811 {
812 weaponSpeedHitFactor = uint32(attacker->GetAttackTime(cleanDamage->attackType) / 1000.0f * (cleanDamage->attackType == BASE_ATTACK ? 3.5f : 1.75f));
813 if (cleanDamage->hitOutCome == MELEE_HIT_CRIT)
814 weaponSpeedHitFactor *= 2;
815
816 attacker->RewardRage(rage_damage, weaponSpeedHitFactor, true);
817 break;
818 }
819 case RANGED_ATTACK:
820 break;
821 default:
822 break;
823 }
824 }
825
826 if (!damage)
827 {
828 // Rage from absorbed damage
829 if (cleanDamage && cleanDamage->absorbed_damage && victim->GetPowerType() == POWER_RAGE)
830 victim->RewardRage(cleanDamage->absorbed_damage, 0, false);
831
832 return 0;
833 }
834
835 uint32 health = victim->GetHealth();
836
837 // duel ends when player has 1 or less hp
838 bool duel_hasEnded = false;
839 bool duel_wasMounted = false;
840 if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->duel && damage >= (health-1))
841 {
842 if (!attacker)
843 return 0;
844
845 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
846 if (victim->ToPlayer()->duel->Opponent == attacker->GetControllingPlayer())
847 damage = health - 1;
848
849 duel_hasEnded = true;
850 }
851 else if (victim->IsVehicle() && damage >= (health-1) && victim->GetCharmer() && victim->GetCharmer()->GetTypeId() == TYPEID_PLAYER)
852 {
853 Player* victimRider = victim->GetCharmer()->ToPlayer();
854
855 if (victimRider && victimRider->duel && victimRider->duel->IsMounted)
856 {
857 if (!attacker)
858 return 0;
859
860 // prevent kill only if killed in duel and killed by opponent or opponent controlled creature
861 if (victimRider->duel->Opponent == attacker->GetControllingPlayer())
862 damage = health - 1;
863
864 duel_wasMounted = true;
865 duel_hasEnded = true;
866 }
867 }
868
869 if (attacker && attacker != victim)
870 {
871 if (Player* killer = attacker->ToPlayer())
872 {
873 // in bg, count dmg if victim is also a player
874 if (victim->GetTypeId() == TYPEID_PLAYER)
875 if (Battleground* bg = killer->GetBattleground())
876 bg->UpdatePlayerScore(killer, SCORE_DAMAGE_DONE, damage);
877
878 killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, health > damage ? damage : health, 0, victim);
879 killer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT, damage);
880 }
881 }
882
883 if (victim->GetTypeId() == TYPEID_PLAYER)
885 else if (!victim->IsControlledByPlayer() || victim->IsVehicle())
886 {
887 if (!victim->ToCreature()->hasLootRecipient())
888 victim->ToCreature()->SetLootRecipient(attacker);
889
890 if (!attacker || attacker->IsControlledByPlayer() || (attacker->ToTempSummon() && attacker->ToTempSummon()->GetSummonerUnit() && attacker->ToTempSummon()->GetSummonerUnit()->GetTypeId() == TYPEID_PLAYER))
891 victim->ToCreature()->LowerPlayerDamageReq(health < damage ? health : damage);
892 }
893
894 if (health <= damage)
895 {
896 if (victim->GetTypeId() == TYPEID_PLAYER && victim != attacker)
898
899 Unit::Kill(attacker, victim, durabilityLoss);
900 }
901 else
902 {
903 if (victim->GetTypeId() == TYPEID_PLAYER)
905
906 victim->ModifyHealth(-(int32)damage);
907
908 if (damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
909 victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, spellProto ? spellProto->Id : 0);
910
911 if (victim->GetTypeId() != TYPEID_PLAYER)
912 {
913 // Part of Evade mechanics. DoT's and Thorns / Retribution Aura do not contribute to this
914 if (damagetype != DOT && damage > 0 && !victim->GetOwnerGUID().IsPlayer() && (!spellProto || !spellProto->HasAura(SPELL_AURA_DAMAGE_SHIELD)))
916
917 if (attacker)
918 victim->GetThreatManager().AddThreat(attacker, float(damage), spellProto);
919 }
920 else // victim is a player
921 {
922 // random durability for items (HIT TAKEN)
924 {
927 }
928 }
929
930 // Rage from damage received
931 if (attacker != victim && victim->GetPowerType() == POWER_RAGE)
932 {
933 rage_damage = damage + (cleanDamage ? cleanDamage->absorbed_damage : 0);
934 victim->RewardRage(rage_damage, 0, false);
935 }
936
937 if (attacker && attacker->GetTypeId() == TYPEID_PLAYER)
938 {
939 // random durability for items (HIT DONE)
941 {
943 attacker->ToPlayer()->DurabilityPointLossForEquipSlot(slot);
944 }
945 }
946
947 if (damagetype != NODAMAGE && damagetype != DOT && damage)
948 {
949 if (victim != attacker && victim->IsPlayer() && (!spellProto || !(spellProto->HasAttribute(SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE) || spellProto->HasAttribute(SPELL_ATTR3_TREAT_AS_PERIODIC))))
950 {
952 {
953 if (Spell* spell = victim->m_currentSpells[i])
954 {
955 if (spell->getState() == SPELL_STATE_PREPARING)
956 {
957 uint32 interruptFlags = spell->m_spellInfo->InterruptFlags;
958 if (interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG)
959 victim->InterruptNonMeleeSpells(false);
960 else
961 spell->Delayed();
962 }
963 }
964 }
965
966 if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL])
967 if (spell->getState() == SPELL_STATE_CASTING)
968 spell->DelayedChannel();
969 }
970 }
971
972 // last damage from duel opponent
973 if (duel_hasEnded)
974 {
975 Player* he = duel_wasMounted ? victim->GetCharmer()->ToPlayer() : victim->ToPlayer();
976
977 ASSERT_NODEBUGINFO(he && he->duel);
978
979 if (duel_wasMounted) // In this case victim == mount
980 victim->SetHealth(1);
981 else
982 he->SetHealth(1);
983
984 he->duel->Opponent->CombatStopWithPets(true);
985 he->CombatStopWithPets(true);
986
987 he->CastSpell(he, 7267, true); // beg
989 }
990 }
991
992 // make player victims stand up automatically
993 if (victim->GetStandState() && victim->IsPlayer() && damagetype != NODAMAGE && damagetype != DOT)
995
996 return damage;
997}
998
999void Unit::CastStop(uint32 except_spellid)
1000{
1002 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id != except_spellid)
1004}
1005
1006void Unit::CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType, bool crit /*= false*/, bool blocked /*= false*/, Spell* spell /*= nullptr*/)
1007{
1008 if (damage < 0)
1009 return;
1010
1011 Unit* victim = damageInfo->target;
1012 if (!victim || !victim->IsAlive())
1013 return;
1014
1015 SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
1016 uint32 crTypeMask = victim->GetCreatureTypeMask();
1017
1018 // Spells with SPELL_ATTR4_FIXED_DAMAGE ignore resilience because their damage is based off another spell's damage.
1019 if (!spellInfo->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
1020 {
1021 if (Unit::IsDamageReducedByArmor(damageSchoolMask, spellInfo))
1022 damage = Unit::CalcArmorReducedDamage(this, victim, damage, spellInfo, attackType);
1023
1024 // Per-school calc
1025 switch (spellInfo->DmgClass)
1026 {
1027 // Melee and Ranged Spells
1030 {
1031 if (crit)
1032 {
1033 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1034
1035 // Calculate crit bonus
1036 uint32 crit_bonus = damage;
1037 // Apply crit_damage bonus for melee spells
1038 if (Player* modOwner = GetSpellModOwner())
1039 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
1040 damage += crit_bonus;
1041
1042 // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
1043 float critPctDamageMod = 0.0f;
1044 if (attackType == RANGED_ATTACK)
1046 else
1048
1049 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
1050 critPctDamageMod += (GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellInfo->GetSchoolMask()) - 1.0f) * 100;
1051
1052 // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
1054
1055 if (critPctDamageMod != 0)
1056 AddPct(damage, critPctDamageMod);
1057 }
1058
1059 // Spell weapon based damage CAN BE crit & blocked at same time
1060 if (blocked)
1061 {
1062 damageInfo->blocked = victim->GetShieldBlockValue();
1063 // double blocked amount if block is critical
1064 if (victim->IsBlockCritical())
1065 damageInfo->blocked += damageInfo->blocked;
1066 if (damage <= int32(damageInfo->blocked))
1067 {
1068 damageInfo->blocked = uint32(damage);
1069 damageInfo->fullBlock = true;
1070 }
1071 damage -= damageInfo->blocked;
1072 }
1073
1074 if (CanApplyResilience())
1075 Unit::ApplyResilience(victim, nullptr, &damage, crit, (attackType == RANGED_ATTACK ? CR_CRIT_TAKEN_RANGED : CR_CRIT_TAKEN_MELEE));
1076 break;
1077 }
1078 // Magical Attacks
1081 {
1082 // If crit add critical bonus
1083 if (crit)
1084 {
1085 damageInfo->HitInfo |= SPELL_HIT_TYPE_CRIT;
1086 damage = Unit::SpellCriticalDamageBonus(this, spellInfo, damage, victim);
1087 }
1088
1089 if (CanApplyResilience())
1090 Unit::ApplyResilience(victim, nullptr, &damage, crit, CR_CRIT_TAKEN_SPELL);
1091 break;
1092 }
1093 default:
1094 break;
1095 }
1096 }
1097
1098 // Script Hook For CalculateSpellDamageTaken -- Allow scripts to change the Damage post class mitigation calculations
1099 sScriptMgr->ModifySpellDamageTaken(damageInfo->target, damageInfo->attacker, damage);
1100
1101 // Calculate absorb resist
1102 if (damage < 0)
1103 damage = 0;
1104
1105 damageInfo->damage = damage;
1107 Unit::CalcAbsorbResist(dmgInfo, spell);
1108 damageInfo->absorb = dmgInfo.GetAbsorb();
1109 damageInfo->resist = dmgInfo.GetResist();
1110
1111 if (damageInfo->absorb)
1112 damageInfo->HitInfo |= (damageInfo->damage - damageInfo->absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
1113
1114 if (damageInfo->resist)
1115 damageInfo->HitInfo |= (damageInfo->damage - damageInfo->resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
1116
1117 damageInfo->damage = dmgInfo.GetDamage();
1118}
1119
1120void Unit::DealSpellDamage(SpellNonMeleeDamage const* damageInfo, bool durabilityLoss)
1121{
1122 if (!damageInfo)
1123 return;
1124
1125 Unit* victim = damageInfo->target;
1126 if (!victim)
1127 return;
1128
1129 if (!victim->IsAlive() || victim->HasUnitState(UNIT_STATE_IN_FLIGHT) || (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsEvadingAttacks()))
1130 return;
1131
1132 SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(damageInfo->SpellID);
1133 if (spellProto == nullptr)
1134 {
1135 TC_LOG_DEBUG("entities.unit", "Unit::DealSpellDamage has wrong damageInfo->SpellID: {}", damageInfo->SpellID);
1136 return;
1137 }
1138
1139 // Call default DealDamage
1140 CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
1141 Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
1142}
1143
1146{
1147 damageInfo->Attacker = this;
1148 damageInfo->Target = victim;
1150 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1151 {
1152 damageInfo->Damages[i].DamageSchoolMask = GetMeleeDamageSchoolMask(attackType, i);
1153 damageInfo->Damages[i].Damage = 0;
1154 damageInfo->Damages[i].Absorb = 0;
1155 damageInfo->Damages[i].Resist = 0;
1156 }
1157
1158 damageInfo->Blocked = 0;
1159 damageInfo->HitInfo = 0;
1160 damageInfo->TargetState = 0;
1161
1162 damageInfo->AttackType = attackType;
1163 damageInfo->ProcAttacker = PROC_FLAG_NONE;
1164 damageInfo->ProcVictim = PROC_FLAG_NONE;
1165 damageInfo->CleanDamage = 0;
1166 damageInfo->HitOutCome = MELEE_HIT_EVADE;
1167
1168 if (!victim)
1169 return;
1170
1171 if (!IsAlive() || !victim->IsAlive())
1172 return;
1173
1174 // Select HitInfo/procAttacker/procVictim flag based on attack type
1175 switch (attackType)
1176 {
1177 case BASE_ATTACK:
1180 break;
1181 case OFF_ATTACK:
1184 damageInfo->HitInfo = HITINFO_OFFHAND;
1185 break;
1186 default:
1187 return;
1188 }
1189
1190 // Physical Immune check (must immune to all damages)
1191 uint8 immunedMask = 0;
1192 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1193 if (damageInfo->Target->IsImmunedToDamage(SpellSchoolMask(damageInfo->Damages[i].DamageSchoolMask)))
1194 immunedMask |= (1 << i);
1195
1196 if (immunedMask == ((1 << 0) | (1 << 1)))
1197 {
1198 damageInfo->HitInfo |= HITINFO_NORMALSWING;
1199 damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
1200 damageInfo->CleanDamage = 0;
1201 return;
1202 }
1203
1204 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1205 {
1206 // only players have secondary weapon damage
1207 if (i > 0 && GetTypeId() != TYPEID_PLAYER)
1208 break;
1209
1210 if (immunedMask & (1 << i))
1211 continue;
1212
1213 SpellSchoolMask schoolMask = SpellSchoolMask(damageInfo->Damages[i].DamageSchoolMask);
1214 bool const addPctMods = (schoolMask & SPELL_SCHOOL_MASK_NORMAL);
1215
1216 uint32 damage = 0;
1217 uint8 itemDamagesMask = (GetTypeId() == TYPEID_PLAYER) ? (1 << i) : 0;
1218 damage += CalculateDamage(damageInfo->AttackType, false, addPctMods, itemDamagesMask);
1219 // Add melee damage bonus
1220 damage = MeleeDamageBonusDone(damageInfo->Target, damage, damageInfo->AttackType, nullptr, schoolMask);
1221 damage = damageInfo->Target->MeleeDamageBonusTaken(this, damage, damageInfo->AttackType, nullptr, schoolMask);
1222
1223 // Script Hook For CalculateMeleeDamage -- Allow scripts to change the Damage pre class mitigation calculations
1224 sScriptMgr->ModifyMeleeDamage(damageInfo->Target, damageInfo->Attacker, damage);
1225
1226 // Calculate armor reduction
1228 {
1229 damageInfo->Damages[i].Damage = Unit::CalcArmorReducedDamage(damageInfo->Attacker, damageInfo->Target, damage, nullptr, damageInfo->AttackType);
1230 damageInfo->CleanDamage += damage - damageInfo->Damages[i].Damage;
1231 }
1232 else
1233 damageInfo->Damages[i].Damage = damage;
1234 }
1235
1236 damageInfo->HitOutCome = RollMeleeOutcomeAgainst(damageInfo->Target, damageInfo->AttackType);
1237
1238 switch (damageInfo->HitOutCome)
1239 {
1240 case MELEE_HIT_EVADE:
1242 damageInfo->TargetState = VICTIMSTATE_EVADES;
1243
1244 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1245 damageInfo->Damages[i].Damage = 0;
1246 damageInfo->CleanDamage = 0;
1247 return;
1248 case MELEE_HIT_MISS:
1249 damageInfo->HitInfo |= HITINFO_MISS;
1250 damageInfo->TargetState = VICTIMSTATE_INTACT;
1251
1252 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1253 damageInfo->Damages[i].Damage = 0;
1254 damageInfo->CleanDamage = 0;
1255 break;
1256 case MELEE_HIT_NORMAL:
1257 damageInfo->TargetState = VICTIMSTATE_HIT;
1258 break;
1259 case MELEE_HIT_CRIT:
1260 {
1261 damageInfo->HitInfo |= HITINFO_CRITICALHIT;
1262 damageInfo->TargetState = VICTIMSTATE_HIT;
1263
1264 // Crit bonus calc
1265 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1266 {
1267 damageInfo->Damages[i].Damage *= 2;
1268
1269 float mod = 0.0f;
1270 // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
1271 if (damageInfo->AttackType == RANGED_ATTACK)
1273 else
1275
1276 // Increase crit damage from SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
1278
1279 uint32 crTypeMask = damageInfo->Target->GetCreatureTypeMask();
1280
1281 // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
1283 if (mod != 0)
1284 AddPct(damageInfo->Damages[i].Damage, mod);
1285 }
1286 break;
1287 }
1288 case MELEE_HIT_PARRY:
1289 damageInfo->TargetState = VICTIMSTATE_PARRY;
1290 damageInfo->CleanDamage = 0;
1291
1292 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1293 {
1294 damageInfo->CleanDamage += damageInfo->Damages[i].Damage;
1295 damageInfo->Damages[i].Damage = 0;
1296 }
1297 break;
1298 case MELEE_HIT_DODGE:
1299 damageInfo->TargetState = VICTIMSTATE_DODGE;
1300 damageInfo->CleanDamage = 0;
1301
1302 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1303 {
1304 damageInfo->CleanDamage += damageInfo->Damages[i].Damage;
1305 damageInfo->Damages[i].Damage = 0;
1306 }
1307 break;
1308 case MELEE_HIT_BLOCK:
1309 {
1310 damageInfo->TargetState = VICTIMSTATE_HIT;
1311 damageInfo->HitInfo |= HITINFO_BLOCK;
1312 damageInfo->Blocked = damageInfo->Target->GetShieldBlockValue();
1313 // double blocked amount if block is critical
1314 if (damageInfo->Target->IsBlockCritical())
1315 damageInfo->Blocked *= 2;
1316
1317 uint32 remainingBlock = damageInfo->Blocked;
1318 uint8 fullBlockMask = 0;
1319 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1320 {
1321 if (remainingBlock && remainingBlock >= damageInfo->Damages[i].Damage)
1322 {
1323 fullBlockMask |= (1 << i);
1324
1325 remainingBlock -= damageInfo->Damages[i].Damage;
1326 damageInfo->CleanDamage += damageInfo->Damages[i].Damage;
1327 damageInfo->Damages[i].Damage = 0;
1328 }
1329 else
1330 {
1331 damageInfo->CleanDamage += remainingBlock;
1332 damageInfo->Damages[i].Damage -= remainingBlock;
1333 remainingBlock = 0;
1334 }
1335 }
1336
1337 // full block
1338 if (fullBlockMask == ((1 << 0) | (1 << 1)))
1339 {
1340 damageInfo->TargetState = VICTIMSTATE_BLOCKS;
1341 damageInfo->Blocked -= remainingBlock;
1342 }
1343 break;
1344 }
1345 case MELEE_HIT_GLANCING:
1346 {
1347 damageInfo->HitInfo |= HITINFO_GLANCING;
1348 damageInfo->TargetState = VICTIMSTATE_HIT;
1349 int32 leveldif = int32(victim->GetLevelForTarget(this)) - int32(GetLevel());
1350 if (leveldif < 0)
1351 {
1352 TC_LOG_DEBUG("entities.unit", "Unit::CalculateMeleeDamage: (Player) {} attacked {}. Glancing should never happen against lower level target", GetGUID().ToString(), victim->GetGUID().ToString());
1353 break;
1354 }
1355 if (leveldif == 0)
1356 leveldif = 1;
1357 if (leveldif > 3)
1358 leveldif = 3;
1359
1360 // against boss-level targets - 24% chance of 25% average damage reduction (damage reduction range : 20-30%)
1361 // against level 82 elites - 18% chance of 15% average damage reduction (damage reduction range : 10-20%)
1362 int32 const reductionMax = leveldif * 10;
1363 int32 const reductionMin = std::max(1, reductionMax - 10);
1364
1365 float reducePercent = 1.f - irand(reductionMin, reductionMax) / 100.0f;
1366
1367 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1368 {
1369 uint32 reducedDamage = uint32(reducePercent * damageInfo->Damages[i].Damage);
1370 damageInfo->CleanDamage += damageInfo->Damages[i].Damage - reducedDamage;
1371 damageInfo->Damages[i].Damage = reducedDamage;
1372 }
1373 break;
1374 }
1375 case MELEE_HIT_CRUSHING:
1376 damageInfo->HitInfo |= HITINFO_CRUSHING;
1377 damageInfo->TargetState = VICTIMSTATE_HIT;
1378
1379 // 150% normal damage
1380 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1381 damageInfo->Damages[i].Damage += (damageInfo->Damages[i].Damage / 2);
1382 break;
1383 default:
1384 break;
1385 }
1386
1387 // Always apply HITINFO_AFFECTS_VICTIM in case its not a miss
1388 if (!(damageInfo->HitInfo & HITINFO_MISS))
1389 damageInfo->HitInfo |= HITINFO_AFFECTS_VICTIM;
1390
1391 uint32 tmpHitInfo[MAX_ITEM_PROTO_DAMAGES] = { };
1392
1393 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1394 {
1395 int32 resilienceReduction = damageInfo->Damages[i].Damage;
1396 // attackType is checked already for BASE_ATTACK or OFF_ATTACK so it can't be RANGED_ATTACK here
1397 if (CanApplyResilience())
1398 Unit::ApplyResilience(victim, nullptr, &resilienceReduction, (damageInfo->HitOutCome == MELEE_HIT_CRIT), CR_CRIT_TAKEN_MELEE);
1399 resilienceReduction = damageInfo->Damages[i].Damage - resilienceReduction;
1400 damageInfo->Damages[i].Damage -= resilienceReduction;
1401 damageInfo->CleanDamage += resilienceReduction;
1402
1403 // Calculate absorb resist
1404 if (int32(damageInfo->Damages[i].Damage) > 0)
1405 {
1406 damageInfo->ProcVictim |= PROC_FLAG_TAKEN_DAMAGE;
1407 // Calculate absorb & resists
1408 DamageInfo dmgInfo(*damageInfo, i);
1409 Unit::CalcAbsorbResist(dmgInfo);
1410 damageInfo->Damages[i].Absorb = dmgInfo.GetAbsorb();
1411 damageInfo->Damages[i].Resist = dmgInfo.GetResist();
1412
1413 if (damageInfo->Damages[i].Absorb)
1414 tmpHitInfo[i] |= (damageInfo->Damages[i].Damage - damageInfo->Damages[i].Absorb == 0 ? HITINFO_FULL_ABSORB : HITINFO_PARTIAL_ABSORB);
1415
1416 if (damageInfo->Damages[i].Resist)
1417 tmpHitInfo[i] |= (damageInfo->Damages[i].Damage - damageInfo->Damages[i].Resist == 0 ? HITINFO_FULL_RESIST : HITINFO_PARTIAL_RESIST);
1418
1419 damageInfo->CleanDamage += damageInfo->Damages[i].Damage - dmgInfo.GetDamage();
1420 damageInfo->Damages[i].Damage = dmgInfo.GetDamage();
1421 }
1422 else // Impossible get negative result but....
1423 damageInfo->Damages[i].Damage = 0;
1424 }
1425
1426 // set proper HitInfo flags
1427 if ((tmpHitInfo[0] & HITINFO_FULL_ABSORB) != 0)
1428 {
1429 // set partial absorb when secondary damage isn't full absorbed
1430 damageInfo->HitInfo |= ((tmpHitInfo[1] & HITINFO_PARTIAL_ABSORB) != 0) ? HITINFO_PARTIAL_ABSORB : HITINFO_FULL_ABSORB;
1431 }
1432 else
1433 damageInfo->HitInfo |= (tmpHitInfo[0] & HITINFO_PARTIAL_ABSORB);
1434
1435 if ((tmpHitInfo[0] & HITINFO_FULL_RESIST) != 0)
1436 {
1437 // set partial resist when secondary damage isn't full resisted
1438 damageInfo->HitInfo |= ((tmpHitInfo[1] & HITINFO_PARTIAL_RESIST) != 0) ? HITINFO_PARTIAL_RESIST : HITINFO_FULL_RESIST;
1439 }
1440 else
1441 damageInfo->HitInfo |= (tmpHitInfo[0] & HITINFO_PARTIAL_RESIST);
1442}
1443
1444void Unit::DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss)
1445{
1446 Unit* victim = damageInfo->Target;
1447
1448 auto canTakeMeleeDamage = [&]()
1449 {
1450 return victim->IsAlive() && !victim->HasUnitState(UNIT_STATE_IN_FLIGHT) && (victim->GetTypeId() != TYPEID_UNIT || !victim->ToCreature()->IsEvadingAttacks());
1451 };
1452
1453 if (!canTakeMeleeDamage())
1454 return;
1455
1456 if (damageInfo->TargetState == VICTIMSTATE_PARRY &&
1458 {
1459 // Get attack timers
1460 float offtime = float(victim->getAttackTimer(OFF_ATTACK));
1461 float basetime = float(victim->getAttackTimer(BASE_ATTACK));
1462 // Reduce attack time
1463 if (victim->haveOffhandWeapon() && offtime < basetime)
1464 {
1465 float percent20 = victim->GetAttackTime(OFF_ATTACK) * 0.20f;
1466 float percent60 = 3.0f * percent20;
1467 if (offtime > percent20 && offtime <= percent60)
1468 victim->setAttackTimer(OFF_ATTACK, uint32(percent20));
1469 else if (offtime > percent60)
1470 {
1471 offtime -= 2.0f * percent20;
1472 victim->setAttackTimer(OFF_ATTACK, uint32(offtime));
1473 }
1474 }
1475 else
1476 {
1477 float percent20 = victim->GetAttackTime(BASE_ATTACK) * 0.20f;
1478 float percent60 = 3.0f * percent20;
1479 if (basetime > percent20 && basetime <= percent60)
1480 victim->setAttackTimer(BASE_ATTACK, uint32(percent20));
1481 else if (basetime > percent60)
1482 {
1483 basetime -= 2.0f * percent20;
1484 victim->setAttackTimer(BASE_ATTACK, uint32(basetime));
1485 }
1486 }
1487 }
1488
1489 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
1490 {
1491 if (!canTakeMeleeDamage() || (!damageInfo->Damages[i].Damage && !damageInfo->Damages[i].Absorb && !damageInfo->Damages[i].Resist))
1492 continue;
1493
1494 // Call default DealDamage
1495 CleanDamage cleanDamage(damageInfo->CleanDamage, damageInfo->Damages[i].Absorb, damageInfo->AttackType, damageInfo->HitOutCome);
1496 Unit::DealDamage(this, victim, damageInfo->Damages[i].Damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->Damages[i].DamageSchoolMask), nullptr, durabilityLoss);
1497 }
1498
1499 // If this is a creature and it attacks from behind it has a probability to daze it's victim
1500 if ((damageInfo->HitOutCome == MELEE_HIT_CRIT || damageInfo->HitOutCome == MELEE_HIT_CRUSHING || damageInfo->HitOutCome == MELEE_HIT_NORMAL || damageInfo->HitOutCome == MELEE_HIT_GLANCING) &&
1501 GetTypeId() != TYPEID_PLAYER && !ToCreature()->IsControlledByPlayer() && !victim->HasInArc(float(M_PI), this)
1502 && (victim->GetTypeId() == TYPEID_PLAYER || !victim->ToCreature()->isWorldBoss())&& !victim->IsVehicle())
1503 {
1504 // 20% base chance
1505 float chance = 20.0f;
1506
1507 // there is a newbie protection, at level 10 just 7% base chance; assuming linear function
1508 if (victim->GetLevel() < 30)
1509 chance = 0.65f * victim->GetLevel() + 0.5f;
1510
1511 uint32 const victimDefense = victim->GetDefenseSkillValue();
1512 uint32 const attackerMeleeSkill = GetMaxSkillValueForLevel();
1513
1514 chance *= attackerMeleeSkill / float(victimDefense) * 0.16f;
1515
1516 // -probability is between 0% and 40%
1517 RoundToInterval(chance, 0.0f, 40.0f);
1518 if (roll_chance_f(chance))
1519 CastSpell(victim, 1604 /*SPELL_DAZED*/, true);
1520 }
1521
1522 if (GetTypeId() == TYPEID_PLAYER)
1523 {
1524 DamageInfo dmgInfo(*damageInfo);
1525 ToPlayer()->CastItemCombatSpell(dmgInfo);
1526 }
1527
1528 // Do effect if any damage done to target
1529 if (damageInfo->Damages[0].Damage + damageInfo->Damages[1].Damage)
1530 {
1531 // We're going to call functions which can modify content of the list during iteration over it's elements
1532 // Let's copy the list so we can prevent iterator invalidation
1534 for (AuraEffect const* aurEff : vDamageShieldsCopy)
1535 {
1536 SpellInfo const* spellInfo = aurEff->GetSpellInfo();
1537
1538 // Damage shield can be resisted...
1539 SpellMissInfo missInfo = victim->SpellHitResult(this, spellInfo, false);
1540 if (missInfo != SPELL_MISS_NONE)
1541 {
1542 victim->SendSpellMiss(this, spellInfo->Id, missInfo);
1543 continue;
1544 }
1545
1546 // ...or immuned
1547 if (IsImmunedToDamage(spellInfo))
1548 {
1549 victim->SendSpellDamageImmune(this, spellInfo->Id);
1550 continue;
1551 }
1552
1553 uint32 damage = aurEff->GetAmount();
1554 if (Unit* caster = aurEff->GetCaster())
1555 {
1556 damage = caster->SpellDamageBonusDone(this, spellInfo, damage, SPELL_DIRECT_DAMAGE, aurEff->GetSpellEffectInfo(), { });
1557 damage = SpellDamageBonusTaken(caster, spellInfo, damage, SPELL_DIRECT_DAMAGE);
1558 }
1559
1560 // No Unit::CalcAbsorbResist here - opcode doesn't send that data - this damage is probably not affected by that
1561 Unit::DealDamageMods(this, damage, nullptr);
1562
1564 WorldPacket data(SMSG_SPELLDAMAGESHIELD, 8 + 8 + 4 + 4 + 4 + 4 + 4);
1565 data << victim->GetGUID();
1566 data << GetGUID();
1567 data << uint32(spellInfo->Id);
1568 data << uint32(damage); // Damage
1569 int32 const overkill = int32(damage) - int32(GetHealth());
1570 data << uint32(std::max(overkill, 0)); // Overkill
1571 data << uint32(spellInfo->SchoolMask);
1572 victim->SendMessageToSet(&data, true);
1573
1574 Unit::DealDamage(victim, this, damage, nullptr, SPELL_DIRECT_DAMAGE, spellInfo->GetSchoolMask(), spellInfo, true);
1575 }
1576 }
1577}
1578
1580{
1582 packet.Guid = GetGUID();
1583 packet.EmoteID = emoteId;
1584 SendMessageToSet(packet.Write(), true);
1585}
1586
1587/*static*/ bool Unit::IsDamageReducedByArmor(SpellSchoolMask schoolMask, SpellInfo const* spellInfo /*= nullptr*/)
1588{
1589 // only physical spells damage gets reduced by armor
1590 if ((schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
1591 return false;
1592
1593 return !spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_IGNORE_ARMOR);
1594}
1595
1596/*static*/ uint32 Unit::CalcArmorReducedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType /*= MAX_ATTACK*/, uint8 attackerLevel /*= 0*/)
1597{
1598 float armor = float(victim->GetArmor());
1599
1600 // Ignore enemy armor by SPELL_AURA_MOD_TARGET_RESISTANCE aura
1601 if (attacker)
1602 {
1604
1605 if (spellInfo)
1606 if (Player* modOwner = attacker->GetSpellModOwner())
1607 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_IGNORE_ARMOR, armor);
1608
1610 for (AuraEffect const* aurEff : resIgnoreAurasAb)
1611 {
1612 if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL && aurEff->IsAffectingSpell(spellInfo))
1613 armor = std::floor(AddPct(armor, -aurEff->GetAmount()));
1614 }
1615
1617 for (AuraEffect const* aurEff : resIgnoreAuras)
1618 {
1619 if (aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
1620 armor = std::floor(AddPct(armor, -aurEff->GetAmount()));
1621 }
1622
1623 // Apply Player CR_ARMOR_PENETRATION rating and buffs from stances\specializations etc.
1624 if (attacker->GetTypeId() == TYPEID_PLAYER)
1625 {
1626 float arpPct = attacker->ToPlayer()->GetRatingBonusValue(CR_ARMOR_PENETRATION);
1627
1628 Item const* weapon = attacker->ToPlayer()->GetWeaponForAttack(attackType, true);
1629 arpPct += attacker->GetTotalAuraModifier(SPELL_AURA_MOD_ARMOR_PENETRATION_PCT, [weapon](AuraEffect const* aurEff) -> bool
1630 {
1631 return aurEff->GetSpellInfo()->IsItemFitToSpellRequirements(weapon);
1632 });
1633
1634 // no more than 100%
1635 RoundToInterval(arpPct, 0.f, 100.f);
1636
1637 float maxArmorPen = 0.f;
1638 if (victim->GetLevel() < 60)
1639 maxArmorPen = float(400 + 85 * victim->GetLevel());
1640 else
1641 maxArmorPen = 400 + 85 * victim->GetLevel() + 4.5f * 85 * (victim->GetLevel() - 59);
1642
1643 // Cap armor penetration to this number
1644 maxArmorPen = std::min((armor + maxArmorPen) / 3.f, armor);
1645 // Figure out how much armor do we ignore
1646 armor -= CalculatePct(maxArmorPen, arpPct);
1647 }
1648 }
1649
1650 if (armor < 0.0f)
1651 armor = 0.0f;
1652
1653 float levelModifier = attacker ? attacker->GetLevel() : attackerLevel;
1654 if (levelModifier > 59.f)
1655 levelModifier = levelModifier + 4.5f * (levelModifier - 59.f);
1656
1657 float damageReduction = 0.1f * armor / (8.5f * levelModifier + 40.f);
1658 damageReduction /= (1.0f + damageReduction);
1659
1660 RoundToInterval(damageReduction, 0.f, 0.75f);
1661 return uint32(std::ceil(std::max(damage * (1.0f - damageReduction), 0.0f)));
1662}
1663
1664/*static*/ uint32 Unit::CalcSpellResistedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const* spellInfo)
1665{
1666 // Magic damage, check for resists
1667 if (!(schoolMask & SPELL_SCHOOL_MASK_MAGIC))
1668 return 0;
1669
1670 // Npcs can have holy resistance
1671 if ((schoolMask & SPELL_SCHOOL_MASK_HOLY) && victim->GetTypeId() != TYPEID_UNIT)
1672 return 0;
1673
1674 // Ignore spells that can't be resisted
1675 if (spellInfo)
1676 {
1678 return 0;
1679 }
1680
1681 float const averageResist = Unit::CalculateAverageResistReduction(attacker, schoolMask, victim, spellInfo);
1682 float discreteResistProbability[11] = { };
1683 if (averageResist <= 0.1f)
1684 {
1685 discreteResistProbability[0] = 1.0f - 7.5f * averageResist;
1686 discreteResistProbability[1] = 5.0f * averageResist;
1687 discreteResistProbability[2] = 2.5f * averageResist;
1688 }
1689 else
1690 {
1691 for (uint32 i = 0; i < 11; ++i)
1692 discreteResistProbability[i] = std::max(0.5f - 2.5f * std::fabs(0.1f * i - averageResist), 0.0f);
1693 }
1694
1695 float roll = float(rand_norm());
1696 float probabilitySum = 0.0f;
1697
1698 uint32 resistance = 0;
1699 for (; resistance < 11; ++resistance)
1700 if (roll < (probabilitySum += discreteResistProbability[resistance]))
1701 break;
1702
1703 float damageResisted = damage * resistance / 10.f;
1704 if (damageResisted > 0.0f) // if any damage was resisted
1705 {
1706 int32 ignoredResistance = 0;
1707 if (attacker)
1708 {
1709 ignoredResistance += attacker->GetTotalAuraModifier(SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST, [schoolMask, spellInfo](AuraEffect const* aurEff) -> bool
1710 {
1711 if ((aurEff->GetMiscValue() & schoolMask) && aurEff->IsAffectingSpell(spellInfo))
1712 return true;
1713 return false;
1714 });
1715
1716 ignoredResistance += attacker->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_IGNORE_TARGET_RESIST, schoolMask);
1717 }
1718
1719 ignoredResistance = std::min<int32>(ignoredResistance, 100);
1720 ApplyPct(damageResisted, 100 - ignoredResistance);
1721
1722 // Spells with melee and magic school mask, decide whether resistance or armor absorb is higher
1723 if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC))
1724 {
1725 uint32 damageAfterArmor = Unit::CalcArmorReducedDamage(attacker, victim, damage, spellInfo, spellInfo->GetAttackType());
1726 float armorReduction = damage - damageAfterArmor;
1727
1728 // pick the lower one, the weakest resistance counts
1729 damageResisted = std::min(damageResisted, armorReduction);
1730 }
1731 }
1732
1733 damageResisted = std::max(damageResisted, 0.f);
1734 return uint32(damageResisted);
1735}
1736
1737/*static*/ float Unit::CalculateAverageResistReduction(WorldObject const* caster, SpellSchoolMask schoolMask, Unit const* victim, SpellInfo const* spellInfo)
1738{
1739 float victimResistance = float(victim->GetResistance(schoolMask));
1740 if (caster)
1741 {
1742 // pets inherit 100% of masters penetration
1743 if (Player const* player = caster->GetSpellModOwner())
1744 {
1745 victimResistance += float(player->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
1746 victimResistance -= float(player->GetSpellPenetrationItemMod());
1747 }
1748 else if (Unit const* unitCaster = caster->ToUnit())
1749 victimResistance += float(unitCaster->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_RESISTANCE, schoolMask));
1750 }
1751
1752 // holy resistance exists in pve and comes from level difference, ignore template values
1753 if (schoolMask & SPELL_SCHOOL_MASK_HOLY)
1754 victimResistance = 0.0f;
1755
1756 // Chaos Bolt exception, ignore all target resistances (unknown attribute?)
1757 if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && spellInfo->SpellIconID == 3178)
1758 victimResistance = 0.0f;
1759
1760 victimResistance = std::max(victimResistance, 0.0f);
1761
1762 // level-based resistance does not apply to binary spells, and cannot be overcome by spell penetration
1763 // gameobject caster -- should it have level based resistance?
1764 if (caster && caster->GetTypeId() != TYPEID_GAMEOBJECT && (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL)))
1765 victimResistance += std::max((float(victim->GetLevelForTarget(caster)) - float(caster->GetLevelForTarget(victim))) * 5.0f, 0.0f);
1766
1767 static uint32 const BOSS_LEVEL = 83;
1768 static float const BOSS_RESISTANCE_CONSTANT = 510.0f;
1769 uint32 level = victim->GetLevel();
1770 float resistanceConstant = 0.0f;
1771
1772 if (level == BOSS_LEVEL)
1773 resistanceConstant = BOSS_RESISTANCE_CONSTANT;
1774 else
1775 resistanceConstant = level * 5.0f;
1776
1777 return victimResistance / (victimResistance + resistanceConstant);
1778}
1779
1780/*static*/ void Unit::CalcAbsorbResist(DamageInfo& damageInfo, Spell* spell /*= nullptr*/)
1781{
1782 if (!damageInfo.GetVictim() || !damageInfo.GetVictim()->IsAlive() || !damageInfo.GetDamage())
1783 return;
1784
1785 uint32 resistedDamage = Unit::CalcSpellResistedDamage(damageInfo.GetAttacker(), damageInfo.GetVictim(), damageInfo.GetDamage(), damageInfo.GetSchoolMask(), damageInfo.GetSpellInfo());
1786
1787 // Ignore Absorption Auras
1788 float auraAbsorbMod = 0.f;
1789 if (Unit* attacker = damageInfo.GetAttacker())
1790 {
1791 auraAbsorbMod = attacker->GetMaxPositiveAuraModifierByMiscMask(SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL, damageInfo.GetSchoolMask());
1792 auraAbsorbMod = std::max(auraAbsorbMod, static_cast<float>(attacker->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL, [&damageInfo](AuraEffect const* aurEff) -> bool
1793 {
1794 if (!(aurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1795 return false;
1796
1797 if (!aurEff->IsAffectingSpell(damageInfo.GetSpellInfo()))
1798 return false;
1799
1800 return true;
1801 })));
1802 }
1803
1804 RoundToInterval(auraAbsorbMod, 0.0f, 100.0f);
1805
1806 int32 absorbIgnoringDamage = CalculatePct(damageInfo.GetDamage(), auraAbsorbMod);
1807
1808 if (spell)
1809 spell->CallScriptOnResistAbsorbCalculateHandlers(damageInfo, resistedDamage, absorbIgnoringDamage);
1810
1811 damageInfo.ResistDamage(resistedDamage);
1812 damageInfo.ModifyDamage(-absorbIgnoringDamage);
1813
1814 // We're going to call functions which can modify content of the list during iteration over it's elements
1815 // Let's copy the list so we can prevent iterator invalidation
1817 vSchoolAbsorbCopy.sort(Trinity::AbsorbAuraOrderPred());
1818
1819 // absorb without mana cost
1820 for (AuraEffectList::iterator itr = vSchoolAbsorbCopy.begin(); (itr != vSchoolAbsorbCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1821 {
1822 AuraEffect* absorbAurEff = *itr;
1823 // Check if aura was removed during iteration - we don't need to work on such auras
1824 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1825 if (!aurApp)
1826 continue;
1827 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1828 continue;
1829
1830 // get amount which can be still absorbed by the aura
1831 int32 currentAbsorb = absorbAurEff->GetAmount();
1832 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1833 if (currentAbsorb < 0)
1834 currentAbsorb = 0;
1835
1836 uint32 tempAbsorb = uint32(currentAbsorb);
1837
1838 bool defaultPrevented = false;
1839
1840 absorbAurEff->GetBase()->CallScriptEffectAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
1841 currentAbsorb = tempAbsorb;
1842
1843 if (defaultPrevented)
1844 continue;
1845
1846 // absorb must be smaller than the damage itself
1847 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
1848
1849 damageInfo.AbsorbDamage(currentAbsorb);
1850
1851 tempAbsorb = currentAbsorb;
1852 absorbAurEff->GetBase()->CallScriptEffectAfterAbsorbHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
1853
1854 // Check if our aura is using amount to count damage
1855 if (absorbAurEff->GetAmount() >= 0)
1856 {
1857 // Reduce shield amount
1858 absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
1859 // Aura cannot absorb anything more - remove it
1860 if (absorbAurEff->GetAmount() <= 0)
1861 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
1862 }
1863 }
1864
1865 // absorb by mana cost
1867 for (AuraEffectList::const_iterator itr = vManaShieldCopy.begin(); (itr != vManaShieldCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1868 {
1869 AuraEffect* absorbAurEff = *itr;
1870 // Check if aura was removed during iteration - we don't need to work on such auras
1871 AuraApplication const* aurApp = absorbAurEff->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1872 if (!aurApp)
1873 continue;
1874 // check damage school mask
1875 if (!(absorbAurEff->GetMiscValue() & damageInfo.GetSchoolMask()))
1876 continue;
1877
1878 // get amount which can be still absorbed by the aura
1879 int32 currentAbsorb = absorbAurEff->GetAmount();
1880 // aura with infinite absorb amount - let the scripts handle absorbtion amount, set here to 0 for safety
1881 if (currentAbsorb < 0)
1882 currentAbsorb = 0;
1883
1884 uint32 tempAbsorb = currentAbsorb;
1885
1886 bool defaultPrevented = false;
1887
1888 absorbAurEff->GetBase()->CallScriptEffectManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb, defaultPrevented);
1889 currentAbsorb = tempAbsorb;
1890
1891 if (defaultPrevented)
1892 continue;
1893
1894 // absorb must be smaller than the damage itself
1895 currentAbsorb = RoundToInterval(currentAbsorb, 0, int32(damageInfo.GetDamage()));
1896
1897 int32 manaReduction = currentAbsorb;
1898
1899 // lower absorb amount by talents
1900 if (float manaMultiplier = absorbAurEff->GetSpellEffectInfo().CalcValueMultiplier(absorbAurEff->GetCaster()))
1901 manaReduction = int32(float(manaReduction) * manaMultiplier);
1902
1903 int32 manaTaken = -damageInfo.GetVictim()->ModifyPower(POWER_MANA, -manaReduction);
1904
1905 // take case when mana has ended up into account
1906 currentAbsorb = currentAbsorb ? int32(float(currentAbsorb) * (float(manaTaken) / float(manaReduction))) : 0;
1907
1908 damageInfo.AbsorbDamage(currentAbsorb);
1909
1910 tempAbsorb = currentAbsorb;
1911 absorbAurEff->GetBase()->CallScriptEffectAfterManaShieldHandlers(absorbAurEff, aurApp, damageInfo, tempAbsorb);
1912
1913 // Check if our aura is using amount to count damage
1914 if (absorbAurEff->GetAmount() >= 0)
1915 {
1916 absorbAurEff->SetAmount(absorbAurEff->GetAmount() - currentAbsorb);
1917 if ((absorbAurEff->GetAmount() <= 0))
1918 absorbAurEff->GetBase()->Remove(AURA_REMOVE_BY_ENEMY_SPELL);
1919 }
1920 }
1921
1922 damageInfo.ModifyDamage(absorbIgnoringDamage);
1923
1924 // split damage auras - only when not damaging self
1925 if (damageInfo.GetVictim() != damageInfo.GetAttacker())
1926 {
1927 // We're going to call functions which can modify content of the list during iteration over it's elements
1928 // Let's copy the list so we can prevent iterator invalidation
1930 for (AuraEffectList::iterator itr = vSplitDamageFlatCopy.begin(); (itr != vSplitDamageFlatCopy.end()) && (damageInfo.GetDamage() > 0); ++itr)
1931 {
1932 // Check if aura was removed during iteration - we don't need to work on such auras
1933 if (!((*itr)->GetBase()->IsAppliedOnTarget(damageInfo.GetVictim()->GetGUID())))
1934 continue;
1935 // check damage school mask
1936 if (!((*itr)->GetMiscValue() & damageInfo.GetSchoolMask()))
1937 continue;
1938
1939 // Damage can be splitted only if aura has an alive caster
1940 Unit* caster = (*itr)->GetCaster();
1941 if (!caster || (caster == damageInfo.GetVictim()) || !caster->IsInWorld() || !caster->IsAlive())
1942 continue;
1943
1944 int32 splitDamage = (*itr)->GetAmount();
1945
1946 // absorb must be smaller than the damage itself
1947 splitDamage = RoundToInterval(splitDamage, 0, int32(damageInfo.GetDamage()));
1948
1949 damageInfo.AbsorbDamage(splitDamage);
1950
1951 // check if caster is immune to damage
1952 if (caster->IsImmunedToDamage(damageInfo.GetSchoolMask()))
1953 {
1954 damageInfo.GetVictim()->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
1955 continue;
1956 }
1957
1958 uint32 splitted = splitDamage;
1959 uint32 splitted_absorb = 0;
1960 Unit::DealDamageMods(caster, splitted, &splitted_absorb);
1961
1962 SpellNonMeleeDamage log(damageInfo.GetAttacker(), caster, (*itr)->GetId(), damageInfo.GetSchoolMask());
1963 log.damage = splitted;
1964 log.absorb = splitted_absorb;
1965 log.periodicLog = damageInfo.GetDamageType() == DOT;
1967 caster->SendSpellNonMeleeDamageLog(&log);
1968
1969 CleanDamage cleanDamage = CleanDamage(splitted, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
1970 Unit::DealDamage(damageInfo.GetAttacker(), caster, splitted, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
1971 }
1972
1973 // We're going to call functions which can modify content of the list during iteration over it's elements
1974 // Let's copy the list so we can prevent iterator invalidation
1976 for (AuraEffectList::iterator itr = vSplitDamagePctCopy.begin(); itr != vSplitDamagePctCopy.end() && damageInfo.GetDamage() > 0; ++itr)
1977 {
1978 // Check if aura was removed during iteration - we don't need to work on such auras
1979 AuraApplication const* aurApp = (*itr)->GetBase()->GetApplicationOfTarget(damageInfo.GetVictim()->GetGUID());
1980 if (!aurApp)
1981 continue;
1982
1983 // check damage school mask
1984 if (!((*itr)->GetMiscValue() & damageInfo.GetSchoolMask()))
1985 continue;
1986
1987 // Damage can be splitted only if aura has an alive caster
1988 Unit* caster = (*itr)->GetCaster();
1989 if (!caster || (caster == damageInfo.GetVictim()) || !caster->IsInWorld() || !caster->IsAlive())
1990 continue;
1991
1992 uint32 splitDamage = CalculatePct(damageInfo.GetDamage(), (*itr)->GetAmount());
1993
1994 (*itr)->GetBase()->CallScriptEffectSplitHandlers((*itr), aurApp, damageInfo, splitDamage);
1995
1996 // absorb must be smaller than the damage itself
1997 splitDamage = RoundToInterval(splitDamage, uint32(0), uint32(damageInfo.GetDamage()));
1998
1999 damageInfo.AbsorbDamage(splitDamage);
2000
2001 // check if caster is immune to damage
2002 if (caster->IsImmunedToDamage(damageInfo.GetSchoolMask()))
2003 {
2004 damageInfo.GetVictim()->SendSpellMiss(caster, (*itr)->GetSpellInfo()->Id, SPELL_MISS_IMMUNE);
2005 continue;
2006 }
2007
2008 uint32 split_absorb = 0;
2009 Unit::DealDamageMods(caster, splitDamage, &split_absorb);
2010
2011 SpellNonMeleeDamage log(damageInfo.GetAttacker(), caster, (*itr)->GetId(), damageInfo.GetSchoolMask());
2012 log.damage = splitDamage;
2013 log.absorb = split_absorb;
2014 log.periodicLog = damageInfo.GetDamageType() == DOT;
2016 caster->SendSpellNonMeleeDamageLog(&log);
2017
2018 CleanDamage cleanDamage = CleanDamage(splitDamage, 0, BASE_ATTACK, MELEE_HIT_NORMAL);
2019 Unit::DealDamage(damageInfo.GetAttacker(), caster, splitDamage, &cleanDamage, DIRECT_DAMAGE, damageInfo.GetSchoolMask(), (*itr)->GetSpellInfo(), false);
2020
2021 // break 'Fear' and similar auras
2023 }
2024 }
2025}
2026
2027/*static*/ void Unit::CalcHealAbsorb(HealInfo& healInfo)
2028{
2029 if (!healInfo.GetHeal())
2030 return;
2031
2032 int32 const healing = static_cast<int32>(healInfo.GetHeal());
2033 int32 absorbAmount = 0;
2034
2035 // Need remove expired auras after
2036 bool existExpired = false;
2037
2038 // absorb without mana cost
2040 for (AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end() && absorbAmount <= healing; ++i)
2041 {
2042 if (!((*i)->GetMiscValue() & healInfo.GetSpellInfo()->SchoolMask))
2043 continue;
2044
2045 // Max Amount can be absorbed by this aura
2046 int32 currentAbsorb = (*i)->GetAmount();
2047
2048 // Found empty aura (impossible but..)
2049 if (currentAbsorb <= 0)
2050 {
2051 existExpired = true;
2052 continue;
2053 }
2054
2055 // currentAbsorb - damage can be absorbed by shield
2056 // If need absorb less damage
2057 if (healing < currentAbsorb + absorbAmount)
2058 currentAbsorb = healing - absorbAmount;
2059
2060 absorbAmount += currentAbsorb;
2061
2062 // Reduce shield amount
2063 (*i)->SetAmount((*i)->GetAmount() - currentAbsorb);
2064 // Need remove it later
2065 if ((*i)->GetAmount() <= 0)
2066 existExpired = true;
2067 }
2068
2069 // Remove all expired absorb auras
2070 if (existExpired)
2071 {
2072 for (AuraEffectList::const_iterator i = vHealAbsorb.begin(); i != vHealAbsorb.end();)
2073 {
2074 AuraEffect* auraEff = *i;
2075 ++i;
2076 if (auraEff->GetAmount() <= 0)
2077 {
2078 uint32 removedAuras = healInfo.GetTarget()->m_removedAurasCount;
2080 if (removedAuras + 1 < healInfo.GetTarget()->m_removedAurasCount)
2081 i = vHealAbsorb.begin();
2082 }
2083 }
2084 }
2085
2086 if (absorbAmount > 0)
2087 healInfo.AbsorbHeal(absorbAmount);
2088}
2089
2090void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra)
2091{
2093 return;
2094
2096 return;
2097
2098 if (!victim->IsAlive())
2099 return;
2100
2101 if ((attType == BASE_ATTACK || attType == OFF_ATTACK) && !IsWithinLOSInMap(victim))
2102 return;
2103
2104 AtTargetAttacked(victim, true);
2106
2107 if (attType != BASE_ATTACK && attType != OFF_ATTACK)
2108 return; // ignore ranged case
2109
2110 if (!extra && _lastExtraAttackSpell)
2112
2113 // melee attack spell cast at main hand attack only - no normal melee dmg dealt
2114 if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL] && !extra)
2116 else
2117 {
2118 // attack can be redirected to another target
2119 victim = GetMeleeHitRedirectTarget(victim);
2120
2121 CalcDamageInfo damageInfo;
2122 CalculateMeleeDamage(victim, &damageInfo, attType);
2123 // Send log damage message to client
2124
2125 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
2126 Unit::DealDamageMods(victim, damageInfo.Damages[i].Damage, &damageInfo.Damages[i].Absorb);
2127 SendAttackStateUpdate(&damageInfo);
2128
2129 _lastDamagedTargetGuid = victim->GetGUID();
2130
2131 DealMeleeDamage(&damageInfo, true);
2132
2133 DamageInfo dmgInfo(damageInfo);
2134 Unit::ProcSkillsAndAuras(damageInfo.Attacker, damageInfo.Target, damageInfo.ProcAttacker, damageInfo.ProcVictim, PROC_SPELL_TYPE_NONE, PROC_SPELL_PHASE_NONE, dmgInfo.GetHitMask(), nullptr, &dmgInfo, nullptr);
2135
2136 TC_LOG_DEBUG("entities.unit", "AttackerStateUpdate: {} attacked {} for {} dmg, absorbed {}, blocked {}, resisted {}.",
2137 GetGUID().ToString(), victim->GetGUID().ToString(), dmgInfo.GetDamage(), dmgInfo.GetAbsorb(), dmgInfo.GetBlock(), dmgInfo.GetResist());
2138 }
2139}
2140
2142{
2143 while (count)
2144 {
2145 --count;
2146 AttackerStateUpdate(victim, BASE_ATTACK, true);
2147 }
2148}
2149
2151{
2153 if (!targetGUID)
2154 {
2155 ObjectGuid selection = GetTarget();
2156 if (!selection.IsEmpty())
2157 targetGUID = selection; // Spell was cast directly (not triggered by aura)
2158 else
2159 return;
2160 }
2161
2162 extraAttacksTargets[targetGUID] += count;
2163}
2164
2166{
2167 if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode())
2168 return MELEE_HIT_EVADE;
2169
2170 int32 const attackerMaxSkillValueForLevel = GetMaxSkillValueForLevel(victim);
2171 int32 const victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
2172
2173 int32 const attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
2174 int32 const victimDefenseSkill = victim->GetDefenseSkillValue(this);
2175
2176 // Miss chance based on melee
2177 int32 miss_chance = int32(MeleeSpellMissChance(victim, attType, attackerWeaponSkill - victimMaxSkillValueForLevel, 0) * 100.0f);
2178
2179 // Critical hit chance
2180 int32 crit_chance = int32(GetUnitCriticalChanceAgainst(attType, victim) * 100.0f);
2181
2182 int32 dodge_chance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
2183 int32 block_chance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
2184 int32 parry_chance = int32(GetUnitParryChance(attType, victim) * 100.0f);
2185
2186 // melee attack table implementation
2187 // outcome priority:
2188 // 1. > 2. > 3. > 4. > 5. > 6. > 7. > 8.
2189 // MISS > DODGE > PARRY > GLANCING > BLOCK > CRIT > CRUSHING > HIT
2190
2191 int32 sum = 0, tmp = 0;
2192 int32 roll = urand(0, 9999);
2193
2194 // check if attack comes from behind, nobody can parry or block if attacker is behind
2195 bool canParryOrBlock = victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION);
2196
2197 // only creatures can dodge if attacker is behind
2198 bool canDodge = victim->GetTypeId() != TYPEID_PLAYER || canParryOrBlock;
2199
2200 // if victim is casting or cc'd it can't avoid attacks
2201 if (victim->IsNonMeleeSpellCast(false, false, true) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
2202 {
2203 canDodge = false;
2204 canParryOrBlock = false;
2205 }
2206
2207 // 1. MISS
2208 tmp = miss_chance;
2209 if (tmp > 0 && roll < (sum += tmp))
2210 return MELEE_HIT_MISS;
2211
2212 // always crit against a sitting target (except 0 crit chance)
2213 if (victim->GetTypeId() == TYPEID_PLAYER && crit_chance > 0 && !victim->IsStandState())
2214 return MELEE_HIT_CRIT;
2215
2216 // 2. DODGE
2217 if (canDodge)
2218 {
2219 tmp = dodge_chance;
2220 if (tmp > 0 // check if unit _can_ dodge
2221 && roll < (sum += tmp))
2222 return MELEE_HIT_DODGE;
2223 }
2224
2225 // 3. PARRY
2226 if (canParryOrBlock)
2227 {
2228 tmp = parry_chance;
2229 if (tmp > 0 // check if unit _can_ parry
2230 && roll < (sum += tmp))
2231 return MELEE_HIT_PARRY;
2232 }
2233
2234 // 4. GLANCING
2235 // Max 40% chance to score a glancing blow against mobs of the same or higher level (only players and pets, not for ranged weapons).
2236 if ((GetTypeId() == TYPEID_PLAYER || IsPet()) &&
2237 victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet() &&
2238 GetLevel() <= victim->GetLevelForTarget(this))
2239 {
2240 // cap possible value (with bonuses > max skill)
2241 int32 skill = attackerWeaponSkill;
2242 int32 maxskill = attackerMaxSkillValueForLevel;
2243 skill = (skill > maxskill) ? maxskill : skill;
2244
2245 // against boss-level targets - 24% chance of 25% average damage reduction (damage reduction range : 20-30%)
2246 // against level 82 elites - 18% chance of 15% average damage reduction (damage reduction range : 10-20%)
2247 tmp = 600 + (victimDefenseSkill - skill) * 120;
2248 tmp = std::min(tmp, 4000);
2249 if (tmp > 0 && roll < (sum += tmp))
2250 return MELEE_HIT_GLANCING;
2251 }
2252
2253 // 5. BLOCK
2254 if (canParryOrBlock)
2255 {
2256 tmp = block_chance;
2257 if (tmp > 0 // check if unit _can_ block
2258 && roll < (sum += tmp))
2259 return MELEE_HIT_BLOCK;
2260 }
2261
2262 // 6.CRIT
2263 tmp = crit_chance;
2264 if (tmp > 0 && roll < (sum += tmp))
2265 return MELEE_HIT_CRIT;
2266
2267 // 7. CRUSHING
2268 // mobs can score crushing blows if they're 4 or more levels above victim
2269 if (GetLevelForTarget(victim) >= victim->GetLevelForTarget(this) + 4 &&
2270 // can be from by creature (if can) or from controlled player that considered as creature
2272 !(GetTypeId() == TYPEID_UNIT && ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRUSHING_BLOWS))
2273 {
2274 // when their weapon skill is 15 or more above victim's defense skill
2275 tmp = victimDefenseSkill;
2276 // having defense above your maximum (from items, talents etc.) has no effect
2277 tmp = std::min(tmp, victimMaxSkillValueForLevel);
2278 // tmp = mob's level * 5 - player's current defense skill
2279 tmp = attackerMaxSkillValueForLevel - tmp;
2280 // minimum of 20 points diff (4 levels difference)
2281 tmp = std::max(tmp, 20);
2282
2283 // add 2% chance per lacking skill point
2284 tmp = tmp * 200 - 1500;
2285 if (tmp > 0 && roll < (sum += tmp))
2286 return MELEE_HIT_CRUSHING;
2287 }
2288
2289 // 8. HIT
2290 return MELEE_HIT_NORMAL;
2291}
2292
2293uint32 Unit::CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, uint8 itemDamagesMask /*= 0*/) const
2294{
2295 float minDamage = 0.0f;
2296 float maxDamage = 0.0f;
2297
2298 if (normalized || !addTotalPct || itemDamagesMask)
2299 {
2300 // get both by default
2301 if (!itemDamagesMask)
2302 itemDamagesMask = (1 << 0) | (1 << 1);
2303
2304 for (uint8 i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
2305 {
2306 if (itemDamagesMask & (1 << i))
2307 {
2308 float minTmp, maxTmp;
2309 CalculateMinMaxDamage(attType, normalized, addTotalPct, minTmp, maxTmp, i);
2310 minDamage += minTmp;
2311 maxDamage += maxTmp;
2312 }
2313 }
2314 }
2315 else
2316 {
2317 switch (attType)
2318 {
2319 case RANGED_ATTACK:
2322 break;
2323 case BASE_ATTACK:
2326 break;
2327 case OFF_ATTACK:
2330 break;
2331 default:
2332 break;
2333 }
2334 }
2335
2336 minDamage = std::max(0.f, minDamage);
2337 maxDamage = std::max(0.f, maxDamage);
2338
2339 if (minDamage > maxDamage)
2340 std::swap(minDamage, maxDamage);
2341
2342 return urand(uint32(minDamage), uint32(maxDamage));
2343}
2344
2346{
2347 if (!spellInfo->MaxLevel || GetLevel() < spellInfo->MaxLevel)
2348 return 1.0f;
2349
2350 return std::max(0.0f, std::min(1.0f, (22.0f + spellInfo->MaxLevel - GetLevel()) / 20.0f));
2351}
2352
2354{
2356 packet.Attacker = GetGUID();
2357 packet.Victim = victim->GetGUID();
2358 SendMessageToSet(packet.Write(), true);
2359}
2360
2361void Unit::SendMeleeAttackStop(Unit const* victim) const
2362{
2364 attackStop.Attacker = GetGUID();
2365 attackStop.Victim = Object::GetGUID(victim);
2366 attackStop.NowDead = !IsAlive();
2367 SendMessageToSet(attackStop.Write(), true);
2368
2369 if (victim)
2370 TC_LOG_DEBUG("entities.unit", "{} stopped attacking {}", GetGUID().ToString(), victim->GetGUID().ToString());
2371 else
2372 TC_LOG_DEBUG("entities.unit", "{} stopped attacking", GetGUID().ToString());
2373}
2374
2376{
2378 return true;
2379 return false;
2380}
2381
2383{
2384 if (!spellInfo)
2385 return 0;
2386
2387 int32 resistMech = 0;
2388 for (SpellEffectInfo const& effect : spellInfo->GetEffects())
2389 {
2390 if (!effect.IsEffect())
2391 break;
2392
2393 int32 effectMech = spellInfo->GetEffectMechanic(effect.EffectIndex);
2394 if (effectMech)
2395 {
2397 if (resistMech < temp)
2398 resistMech = temp;
2399 }
2400 }
2401
2402 return std::max(resistMech, 0);
2403}
2404
2405bool Unit::CanUseAttackType(uint8 attacktype) const
2406{
2407 switch (attacktype)
2408 {
2409 case BASE_ATTACK:
2411 case OFF_ATTACK:
2413 case RANGED_ATTACK:
2415 default:
2416 return true;
2417 }
2418}
2419
2420// Melee based spells hit result calculations
2422{
2423 WeaponAttackType attType = BASE_ATTACK;
2424
2425 // Check damage class instead of attack type to correctly handle judgements
2426 // - they are meele, but can't be dodged/parried/deflected because of ranged dmg class
2427 if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED)
2428 attType = RANGED_ATTACK;
2429
2430 int32 attackerWeaponSkill;
2431 // skill value for these spells (for example judgements) is 5 * level
2432 if (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED && !spellInfo->IsRangedWeaponSpell())
2433 attackerWeaponSkill = GetMaxSkillValueForLevel();
2434 else
2435 attackerWeaponSkill = int32(GetWeaponSkillValue(attType, victim));
2436
2437 int32 skillDiff = attackerWeaponSkill - int32(victim->GetMaxSkillValueForLevel(this));
2438
2439 uint32 roll = urand(0, 9999);
2440
2441 uint32 missChance = uint32(MeleeSpellMissChance(victim, attType, skillDiff, spellInfo->Id) * 100.0f);
2442 // Roll miss
2443 uint32 tmp = missChance;
2444 if (roll < tmp)
2445 return SPELL_MISS_MISS;
2446
2447 // Chance resist mechanic
2448 int32 resist_chance = victim->GetMechanicResistChance(spellInfo) * 100;
2449 tmp += resist_chance;
2450 if (roll < tmp)
2451 return SPELL_MISS_RESIST;
2452
2453 // Same spells cannot be parried/dodged
2455 return SPELL_MISS_NONE;
2456
2457 bool canDodge = !spellInfo->HasAttribute(SPELL_ATTR7_CANT_DODGE);
2458 bool canParry = !spellInfo->HasAttribute(SPELL_ATTR7_CANT_PARRY);
2459 bool canBlock = true; // all melee and ranged attacks can be blocked
2460
2461 // if victim is casting or cc'd it can't avoid attacks
2462 if (victim->IsNonMeleeSpellCast(false, false, true) || victim->HasUnitState(UNIT_STATE_CONTROLLED))
2463 {
2464 canDodge = false;
2465 canParry = false;
2466 canBlock = false;
2467 }
2468
2469 // Ranged attacks can only miss, resist and deflect and get blocked
2470 if (attType == RANGED_ATTACK)
2471 {
2472 canParry = false;
2473 canDodge = false;
2474
2475 // only if in front
2476 if (!victim->HasUnitState(UNIT_STATE_CONTROLLED) && (victim->HasInArc(float(M_PI), this) || victim->HasAuraType(SPELL_AURA_IGNORE_HIT_DIRECTION)))
2477 {
2478 int32 deflect_chance = victim->GetTotalAuraModifier(SPELL_AURA_DEFLECT_SPELLS) * 100;
2479 tmp += deflect_chance;
2480 if (roll < tmp)
2481 return SPELL_MISS_DEFLECT;
2482 }
2483 }
2484
2485 // Check for attack from behind
2486 if (!victim->HasInArc(float(M_PI), this))
2487 {
2489 {
2490 // Can't dodge from behind in PvP (but its possible in PvE)
2491 if (victim->GetTypeId() == TYPEID_PLAYER)
2492 canDodge = false;
2493 // Can't parry or block
2494 canParry = false;
2495 canBlock = false;
2496 }
2497 else // Only deterrence as of 3.3.5
2498 {
2500 canParry = false;
2501 }
2502 }
2503
2504 // Ignore combat result aura
2506 for (AuraEffect const* aurEff : ignore)
2507 {
2508 if (!aurEff->IsAffectingSpell(spellInfo))
2509 continue;
2510
2511 switch (aurEff->GetMiscValue())
2512 {
2513 case MELEE_HIT_DODGE:
2514 canDodge = false;
2515 break;
2516 case MELEE_HIT_BLOCK:
2517 canBlock = false;
2518 break;
2519 case MELEE_HIT_PARRY:
2520 canParry = false;
2521 break;
2522 default:
2523 TC_LOG_DEBUG("entities.unit", "Spell {} SPELL_AURA_IGNORE_COMBAT_RESULT has unhandled state {}", aurEff->GetId(), aurEff->GetMiscValue());
2524 break;
2525 }
2526 }
2527
2528 if (canDodge)
2529 {
2530 // Roll dodge
2531 int32 dodgeChance = int32(GetUnitDodgeChance(attType, victim) * 100.0f);
2532 if (dodgeChance < 0)
2533 dodgeChance = 0;
2534
2535 if (roll < (tmp += dodgeChance))
2536 return SPELL_MISS_DODGE;
2537 }
2538
2539 if (canParry)
2540 {
2541 // Roll parry
2542 int32 parryChance = int32(GetUnitParryChance(attType, victim) * 100.0f);
2543 if (parryChance < 0)
2544 parryChance = 0;
2545
2546 tmp += parryChance;
2547 if (roll < tmp)
2548 return SPELL_MISS_PARRY;
2549 }
2550
2551 if (canBlock)
2552 {
2553 int32 blockChance = int32(GetUnitBlockChance(attType, victim) * 100.0f);
2554 if (blockChance < 0)
2555 blockChance = 0;
2556 tmp += blockChance;
2557
2558 if (roll < tmp)
2559 return SPELL_MISS_BLOCK;
2560 }
2561
2562 return SPELL_MISS_NONE;
2563}
2564
2566{
2567 uint32 value = GetShieldBlockValue();
2568 if (value >= hard_cap)
2569 {
2570 value = (soft_cap + hard_cap) / 2;
2571 }
2572 else if (value > soft_cap)
2573 {
2574 value = soft_cap + ((value - soft_cap) / 2);
2575 }
2576
2577 return value;
2578}
2579
2581{
2582 if (GetTypeId() == TYPEID_PLAYER)
2583 {
2584 // in PvP use full skill instead current skill value
2585 uint32 value = (target && target->GetTypeId() == TYPEID_PLAYER)
2588 value += uint32(ToPlayer()->GetRatingBonusValue(CR_DEFENSE_SKILL));
2589 return value;
2590 }
2591 else
2592 return GetMaxSkillValueForLevel(target);
2593}
2594
2595float Unit::GetUnitDodgeChance(WeaponAttackType attType, Unit const* victim) const
2596{
2597 int32 const attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
2598 int32 const victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
2599 int32 const skillDiff = victimMaxSkillValueForLevel - attackerWeaponSkill;
2600
2601 float chance = 0.0f;
2602 float skillBonus = 0.0f;
2603 if (victim->GetTypeId() == TYPEID_PLAYER)
2604 {
2605 chance = victim->GetFloatValue(PLAYER_DODGE_PERCENTAGE);
2606 skillBonus = 0.04f * skillDiff;
2607 }
2608 else
2609 {
2610 if (!victim->IsTotem())
2611 {
2612 chance = 5.0f;
2614
2615 if (skillDiff <= 10)
2616 skillBonus = skillDiff * 0.1f;
2617 else
2618 skillBonus = 1.0f + (skillDiff - 10) * 0.1f;
2619 }
2620 }
2621
2622 chance += skillBonus;
2623
2624 // Reduce enemy dodge chance by SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
2626
2627 // reduce dodge by SPELL_AURA_MOD_ENEMY_DODGE
2629
2630 // Reduce dodge chance by attacker expertise rating
2631 if (GetTypeId() == TYPEID_PLAYER)
2632 chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
2633 else
2635 return std::max(chance, 0.0f);
2636}
2637
2638float Unit::GetUnitParryChance(WeaponAttackType attType, Unit const* victim) const
2639{
2640 int32 const attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
2641 int32 const victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
2642 int32 const skillDiff = victimMaxSkillValueForLevel - attackerWeaponSkill;
2643
2644 float chance = 0.0f;
2645 float skillBonus = 0.0f;
2646 if (Player const* playerVictim = victim->ToPlayer())
2647 {
2648 if (playerVictim->CanParry())
2649 {
2650 Item* tmpitem = playerVictim->GetWeaponForAttack(BASE_ATTACK, true);
2651 if (!tmpitem)
2652 tmpitem = playerVictim->GetWeaponForAttack(OFF_ATTACK, true);
2653
2654 if (tmpitem)
2655 chance = playerVictim->GetFloatValue(PLAYER_PARRY_PERCENTAGE);
2656
2657 skillBonus = 0.04f * skillDiff;
2658 }
2659 }
2660 else
2661 {
2663 {
2664 chance = 5.0f;
2666
2667 if (skillDiff <= 10)
2668 skillBonus = skillDiff * 0.1f;
2669 else
2670 skillBonus = 1.0f + (skillDiff - 10) * 1.6f;
2671 }
2672 }
2673
2674 chance += skillBonus;
2675
2676 // Reduce parry chance by attacker expertise rating
2677 if (GetTypeId() == TYPEID_PLAYER)
2678 chance -= ToPlayer()->GetExpertiseDodgeOrParryReduction(attType);
2679 else
2681 return std::max(chance, 0.0f);
2682}
2683
2685{
2686 float miss_chance = 5.0f;
2687
2688 if (Player const* player = ToPlayer())
2689 miss_chance += player->GetMissPercentageFromDefense();
2690
2691 return miss_chance;
2692}
2693
2694float Unit::GetUnitBlockChance(WeaponAttackType attType, Unit const* victim) const
2695{
2696 int32 const attackerWeaponSkill = GetWeaponSkillValue(attType, victim);
2697 int32 const victimMaxSkillValueForLevel = victim->GetMaxSkillValueForLevel(this);
2698 int32 const skillDiff = victimMaxSkillValueForLevel - attackerWeaponSkill;
2699
2700 float chance = 0.0f;
2701 float skillBonus = 0.0f;
2702 if (Player const* playerVictim = victim->ToPlayer())
2703 {
2704 if (playerVictim->CanBlock())
2705 {
2706 Item* tmpitem = playerVictim->GetUseableItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
2707 if (tmpitem && !tmpitem->IsBroken() && tmpitem->GetTemplate()->GetBlock())
2708 {
2709 chance = playerVictim->GetFloatValue(PLAYER_BLOCK_PERCENTAGE);
2710 skillBonus = 0.04f * skillDiff;
2711 }
2712 }
2713 }
2714 else
2715 {
2717 {
2718 chance = 5.0f;
2720
2721 if (skillDiff <= 10)
2722 skillBonus = skillDiff * 0.1f;
2723 else
2724 skillBonus = 1.0f + (skillDiff - 10) * 0.1f;
2725 }
2726 }
2727
2728 chance += skillBonus;
2729 return std::max(chance, 0.0f);
2730}
2731
2733{
2734 float chance = 0.f;
2735 if (GetTypeId() == TYPEID_PLAYER)
2736 {
2737 switch (attackType)
2738 {
2739 case BASE_ATTACK:
2741 break;
2742 case OFF_ATTACK:
2744 break;
2745 case RANGED_ATTACK:
2747 break;
2748 // Just for good manner
2749 default:
2750 chance = 0.0f;
2751 break;
2752 }
2753 }
2754 else
2755 {
2756 if (!(ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_CRIT))
2757 {
2758 chance = 5.0f;
2761 }
2762 }
2763
2764 return chance;
2765}
2766
2767float Unit::GetUnitCriticalChanceTaken(Unit const* attacker, WeaponAttackType attackType, float critDone) const
2768{
2769 int32 const attackerWeaponSkill = attacker->GetWeaponSkillValue(attackType, this);
2770 int32 const victimDefenseSkill = GetDefenseSkillValue(attacker);
2771 int32 const skillDiff = victimDefenseSkill - attackerWeaponSkill;
2772
2773 float skillBonus = 0.0f;
2774 float chance = critDone;
2775
2776 // flat aura mods
2777 if (attackType == RANGED_ATTACK)
2779 else
2781
2782 // reduce crit chance from Rating for players
2783 if (attacker->CanApplyResilience())
2784 Unit::ApplyResilience(this, &chance, nullptr, false, (attackType == RANGED_ATTACK ? CR_CRIT_TAKEN_RANGED : CR_CRIT_TAKEN_MELEE));
2785
2786 // applied after resilience
2788
2789 // Apply crit chance from defense skill
2790 if (GetTypeId() == TYPEID_PLAYER)
2791 skillBonus = -skillDiff * 0.04f;
2792 else
2793 {
2794 skillBonus = -skillDiff * 0.12f;
2795 if (skillDiff >= 15)
2796 skillBonus -= 3.0f;
2797 }
2798
2799 chance += skillBonus;
2800 return std::max(chance, 0.f);
2801}
2802
2803float Unit::GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const* victim) const
2804{
2805 float chance = GetUnitCriticalChanceDone(attackType);
2806 return victim->GetUnitCriticalChanceTaken(this, attackType, chance);
2807}
2808
2810{
2811 uint32 value = 0;
2812 if (Player const* player = ToPlayer())
2813 {
2814 Item* item = player->GetWeaponForAttack(attType, true);
2815
2816 // feral or unarmed skill only for base attack
2817 if (attType != BASE_ATTACK && !item)
2818 return 0;
2819
2820 if (IsInFeralForm())
2821 return GetMaxSkillValueForLevel(); // always maximized SKILL_FERAL_COMBAT in fact
2822
2823 // weapon skill or (unarmed for base attack)
2824 uint32 skill = SKILL_UNARMED;
2825 if (item)
2826 skill = item->GetSkill();
2827
2828 // in PvP use full skill instead current skill value
2829 value = (target && target->IsControlledByPlayer())
2830 ? player->GetMaxSkillValue(skill)
2831 : player->GetSkillValue(skill);
2832 // Modify value from ratings
2833 value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL));
2834 switch (attType)
2835 {
2836 case BASE_ATTACK:
2837 value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_MAINHAND));
2838 break;
2839 case OFF_ATTACK:
2840 value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_OFFHAND));
2841 break;
2842 case RANGED_ATTACK:
2843 value += uint32(player->GetRatingBonusValue(CR_WEAPON_SKILL_RANGED));
2844 break;
2845 default:
2846 break;
2847 }
2848 }
2849 else
2850 value = GetMaxSkillValueForLevel(target);
2851 return value;
2852}
2853
2855{
2856 while (!m_removedAuras.empty())
2857 {
2858 delete m_removedAuras.front();
2859 m_removedAuras.pop_front();
2860 }
2861
2863}
2864
2866{
2869
2870 // remove finished spells from current pointers
2871 for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
2872 {
2873 if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED)
2874 {
2876 m_currentSpells[i] = nullptr; // remove pointer
2877 }
2878 }
2879
2880 // m_auraUpdateIterator can be updated in indirect called code at aura remove to skip next planned to update but removed auras
2882 {
2883 Aura* i_aura = m_auraUpdateIterator->second;
2884 ++m_auraUpdateIterator; // need shift to next for allow update if need into aura update
2885 i_aura->UpdateOwner(time, this);
2886 }
2887
2888 // remove expired auras - do that after updates(used in scripts?)
2889 for (AuraMap::iterator i = m_ownedAuras.begin(); i != m_ownedAuras.end();)
2890 {
2891 if (i->second->IsExpired())
2893 else if (i->second->GetSpellInfo()->IsChanneled() && i->second->GetCasterGUID() != GetGUID() && !ObjectAccessor::GetWorldObject(*this, i->second->GetCasterGUID()))
2894 RemoveOwnedAura(i, AURA_REMOVE_BY_CANCEL); // remove channeled auras when caster is not on the same map
2895 else
2896 ++i;
2897 }
2898
2899 for (VisibleAuraMap::iterator itr = m_visibleAuras.begin(); itr != m_visibleAuras.end(); ++itr)
2900 if (itr->second->IsNeedClientUpdate())
2901 itr->second->ClientUpdate();
2902
2904
2905 if (!m_gameObj.empty())
2906 {
2907 GameObjectList::iterator itr;
2908 for (itr = m_gameObj.begin(); itr != m_gameObj.end();)
2909 {
2910 if (!(*itr)->isSpawned())
2911 {
2912 (*itr)->SetOwnerGUID(ObjectGuid::Empty);
2913 (*itr)->SetRespawnTime(0);
2914 (*itr)->Delete();
2915 m_gameObj.erase(itr++);
2916 }
2917 else
2918 ++itr;
2919 }
2920 }
2921
2923}
2924
2926{
2927 SpellInfo const* autoRepeatSpellInfo = m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo;
2928
2929 // check "realtime" interrupts
2930 if ((GetTypeId() == TYPEID_PLAYER && ToPlayer()->isMoving()) || IsNonMeleeSpellCast(false, false, true, autoRepeatSpellInfo->Id == 75))
2931 {
2932 // cancel wand shoot
2933 if (autoRepeatSpellInfo->Id != 75)
2935 m_AutoRepeatFirstCast = true;
2936 return;
2937 }
2938
2939 // apply delay (Auto Shot (spellID 75) not affected)
2940 if (m_AutoRepeatFirstCast && getAttackTimer(RANGED_ATTACK) < 500 && autoRepeatSpellInfo->Id != 75)
2942 m_AutoRepeatFirstCast = false;
2943
2944 // castroutine
2946 {
2947 // Check if able to cast
2949 if (result != SPELL_CAST_OK)
2950 {
2951 if (autoRepeatSpellInfo->Id != 75)
2953 else if (GetTypeId() == TYPEID_PLAYER)
2954 Spell::SendCastResult(ToPlayer(), autoRepeatSpellInfo, 1, result);
2955
2956 return;
2957 }
2958
2959 // we want to shoot
2960 Spell* spell = new Spell(this, autoRepeatSpellInfo, TRIGGERED_FULL_MASK);
2962
2963 // all went good, reset attack
2965 }
2966}
2967
2969{
2970 ASSERT(pSpell); // NULL may be never passed here, use InterruptSpell or InterruptNonMeleeSpells
2971
2972 CurrentSpellTypes CSpellType = pSpell->GetCurrentContainer();
2973
2974 if (pSpell == m_currentSpells[CSpellType]) // avoid breaking self
2975 return;
2976
2977 // break same type spell if it is not delayed
2978 InterruptSpell(CSpellType, false);
2979
2980 // special breakage effects:
2981 switch (CSpellType)
2982 {
2984 {
2985 // generic spells always break channeled not delayed spells
2987
2988 // autorepeat breaking
2990 {
2991 // break autorepeat if not Auto Shot
2992 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75)
2994 m_AutoRepeatFirstCast = true;
2995 }
2996 if (pSpell->GetCastTime() > 0)
2998
2999 break;
3000 }
3002 {
3003 // channel spells always break generic non-delayed and any channeled spells
3006
3007 // it also does break autorepeat if not Auto Shot
3009 m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->GetSpellInfo()->Id != 75)
3012
3013 break;
3014 }
3016 {
3017 // only Auto Shoot does not break anything
3018 if (pSpell->GetSpellInfo()->Id != 75)
3019 {
3020 // generic autorepeats break generic non-delayed and channeled non-delayed spells
3023 }
3024 // special action: set first cast flag
3025 m_AutoRepeatFirstCast = true;
3026
3027 break;
3028 }
3029 default:
3030 break; // other spell types don't break anything now
3031 }
3032
3033 // current spell (if it is still here) may be safely deleted now
3034 if (m_currentSpells[CSpellType])
3035 m_currentSpells[CSpellType]->SetReferencedFromCurrent(false);
3036
3037 // set new current spell
3038 m_currentSpells[CSpellType] = pSpell;
3039 pSpell->SetReferencedFromCurrent(true);
3040
3041 pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]);
3042}
3043
3044void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool withInstant, SpellCastResult result, Optional<SpellCastResult> resultOther /*= {}*/)
3045{
3046 //TC_LOG_DEBUG("entities.unit", "Interrupt spell for unit {}.", GetEntry());
3047 Spell* spell = m_currentSpells[spellType];
3048 if (spell
3049 && (withDelayed || spell->getState() != SPELL_STATE_DELAYED)
3050 && (withInstant || spell->GetCastTime() > 0 || spell->getState() == SPELL_STATE_CASTING))
3051 {
3052 // for example, do not let self-stun aura interrupt itself
3053 if (!spell->IsInterruptable())
3054 return;
3055
3056 // send autorepeat cancel message for autorepeat spells
3057 if (spellType == CURRENT_AUTOREPEAT_SPELL)
3058 if (GetTypeId() == TYPEID_PLAYER)
3060
3061 if (spell->getState() != SPELL_STATE_FINISHED)
3062 spell->cancel(result, resultOther);
3063 else
3064 {
3065 m_currentSpells[spellType] = nullptr;
3066 spell->SetReferencedFromCurrent(false);
3067 }
3068
3069 if (GetTypeId() == TYPEID_UNIT && IsAIEnabled())
3070 ToCreature()->AI()->OnSpellFailed(spell->GetSpellInfo());
3071 }
3072}
3073
3074void Unit::FinishSpell(CurrentSpellTypes spellType, bool ok /*= true*/)
3075{
3076 Spell* spell = m_currentSpells[spellType];
3077 if (!spell)
3078 return;
3079
3080 if (spellType == CURRENT_CHANNELED_SPELL)
3081 spell->SendChannelUpdate(0);
3082
3083 spell->finish(ok);
3084}
3085
3086bool Unit::IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled, bool skipAutorepeat, bool isAutoshoot, bool skipInstant) const
3087{
3088 // We don't do loop here to explicitly show that melee spell is excluded.
3089 // Maybe later some special spells will be excluded too.
3090
3091 // generic spells are cast when they are not finished and not delayed
3094 (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED))
3095 {
3096 if (!skipInstant || m_currentSpells[CURRENT_GENERIC_SPELL]->GetCastTime())
3097 {
3098 if (!isAutoshoot || !(m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS)))
3099 return true;
3100 }
3101 }
3102 // channeled spells may be delayed, but they are still considered cast
3103 if (!skipChanneled && m_currentSpells[CURRENT_CHANNELED_SPELL] &&
3105 {
3106 if (!isAutoshoot || !(m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS)))
3107 return true;
3108 }
3109 // autorepeat spells may be finished or delayed, but they are still considered cast
3110 if (!skipAutorepeat && m_currentSpells[CURRENT_AUTOREPEAT_SPELL])
3111 return true;
3112
3113 return false;
3114}
3115
3116void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id, bool withInstant)
3117{
3118 // generic spells are interrupted if they are not finished or delayed
3119 if (m_currentSpells[CURRENT_GENERIC_SPELL] && (!spell_id || m_currentSpells[CURRENT_GENERIC_SPELL]->m_spellInfo->Id == spell_id))
3120 InterruptSpell(CURRENT_GENERIC_SPELL, withDelayed, withInstant);
3121
3122 // autorepeat spells are interrupted if they are not finished or delayed
3123 if (m_currentSpells[CURRENT_AUTOREPEAT_SPELL] && (!spell_id || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->m_spellInfo->Id == spell_id))
3124 InterruptSpell(CURRENT_AUTOREPEAT_SPELL, withDelayed, withInstant);
3125
3126 // channeled spells are interrupted if they are not finished, even if they are delayed
3127 if (m_currentSpells[CURRENT_CHANNELED_SPELL] && (!spell_id || m_currentSpells[CURRENT_CHANNELED_SPELL]->m_spellInfo->Id == spell_id))
3129}
3130
3132{
3133 for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
3134 if (m_currentSpells[i] && m_currentSpells[i]->m_spellInfo->Id == spell_id)
3135 return m_currentSpells[i];
3136 return nullptr;
3137}
3138
3140{
3141 if (Spell const* spell = FindCurrentSpellBySpellId(spell_id))
3142 return spell->GetCastTime();
3143 return 0;
3144}
3145
3147{
3148 // can always move when not casting
3150 return false;
3151
3153 if (spell->getState() == SPELL_STATE_FINISHED ||
3154 !(spell->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT))
3155 return false;
3156
3157 // channeled spells during channel stage (after the initial cast timer) allow movement with a specific spell attribute
3159 if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive())
3160 if (spell->GetSpellInfo()->IsMoveAllowedChannel())
3161 return false;
3162
3163 // prohibit movement for all other spell casts
3164 return true;
3165}
3166
3167bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const
3168{
3169 return IsWithinDistInMap(target, distance) && HasInArc(arc, target);
3170}
3171
3172bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const
3173{
3174 return IsWithinDistInMap(target, distance) && !HasInArc(2 * float(M_PI) - arc, target);
3175}
3176
3178{
3179 if (IsInWater())
3180 return c->CanEnterWater();
3181 else
3182 return c->CanWalk() || c->CanFly();
3183}
3184
3189
3191{
3193}
3194
3201
3202void Unit::ProcessTerrainStatusUpdate(ZLiquidStatus /*oldLiquidStatus*/, Optional<LiquidData> const& newLiquidData)
3203{
3204 if (!IsControlledByPlayer())
3205 return;
3206
3207 // remove appropriate auras if we are swimming/not swimming respectively
3208 if (IsInWater())
3210 else
3212
3213 // liquid aura handling
3214 LiquidTypeEntry const* curLiquid = nullptr;
3215 if (IsInWater() && newLiquidData)
3216 curLiquid = sLiquidTypeStore.LookupEntry(newLiquidData->entry);
3217 if (curLiquid != _lastLiquid)
3218 {
3222
3223 // Set _lastLiquid before casting liquid spell to avoid infinite loops
3224 _lastLiquid = curLiquid;
3225
3226 if (curLiquid && curLiquid->SpellID && (!player || !player->IsGameMaster()))
3227 CastSpell(this, curLiquid->SpellID, true);
3228 }
3229}
3230
3235
3237{
3238 ASSERT(!createInfo.CasterGUID.IsEmpty() || createInfo.Caster);
3239
3240 // Check if these can stack anyway
3241 if (!createInfo.CasterGUID && !createInfo.GetSpellInfo()->IsStackableOnOneSlotWithDifferentCasters())
3242 createInfo.CasterGUID = createInfo.Caster->GetGUID();
3243
3244 // world gameobjects can't own auras and they send empty casterguid
3245 // checked on sniffs with spell 22247
3246 if (createInfo.CasterGUID.IsGameObject())
3247 {
3248 createInfo.Caster = nullptr;
3249 createInfo.CasterGUID.Clear();
3250 }
3251
3252 // passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
3253 if (!createInfo.GetSpellInfo()->IsMultiSlotAura())
3254 {
3255 // check if cast item changed
3256 ObjectGuid castItemGUID = createInfo.CastItemGUID;
3257
3258 // find current aura from spell and change it's stackamount, or refresh it's duration
3260 {
3261 // effect masks do not match
3262 // extremely rare case
3263 // let's just recreate aura
3264 if (createInfo.GetAuraEffectMask() != foundAura->GetEffectMask())
3265 return nullptr;
3266
3267 // update basepoints with new values - effect amount will be recalculated in ModStackAmount
3268 for (SpellEffectInfo const& spellEffectInfo : createInfo.GetSpellInfo()->GetEffects())
3269 {
3270 AuraEffect const* auraEff = foundAura->GetEffect(spellEffectInfo.EffectIndex);
3271 if (!auraEff)
3272 continue;
3273
3274 int32 bp = spellEffectInfo.BasePoints;
3275 if (createInfo.BaseAmount)
3276 bp = *(createInfo.BaseAmount + spellEffectInfo.EffectIndex);
3277
3278 int32* oldBP = const_cast<int32*>(&(auraEff->m_baseAmount));
3279 *oldBP = bp;
3280 }
3281
3282 // correct cast item guid if needed
3283 if (castItemGUID != foundAura->GetCastItemGUID())
3284 {
3285 ObjectGuid* oldGUID = const_cast<ObjectGuid*>(&foundAura->m_castItemGuid);
3286 *oldGUID = castItemGUID;
3287 }
3288
3289 // try to increase stack amount
3290 foundAura->ModStackAmount(1, AURA_REMOVE_BY_DEFAULT, createInfo.ResetPeriodicTimer);
3291 return foundAura;
3292 }
3293 }
3294
3295 return nullptr;
3296}
3297
3298void Unit::_AddAura(UnitAura* aura, Unit* caster)
3299{
3301 m_ownedAuras.emplace(aura->GetId(), aura);
3302
3303 _RemoveNoStackAurasDueToAura(aura, true);
3304
3305 if (aura->IsRemoved())
3306 return;
3307
3308 aura->SetIsSingleTarget(caster && aura->GetSpellInfo()->IsSingleTarget());
3309 if (aura->IsSingleTarget())
3310 {
3312 /* @HACK: Player is not in world during loading auras.
3313 * Single target auras are not saved or loaded from database
3314 * but may be created as a result of aura links.
3315 */
3316
3317 // register single target aura
3318 caster->GetSingleCastAuras().push_back(aura);
3319 // remove other single target auras
3320 Unit::AuraList& scAuras = caster->GetSingleCastAuras();
3321 for (Unit::AuraList::iterator itr = scAuras.begin(); itr != scAuras.end();)
3322 {
3323 if ((*itr) != aura &&
3324 (*itr)->IsSingleTargetWith(aura))
3325 {
3326 (*itr)->Remove();
3327 itr = scAuras.begin();
3328 }
3329 else
3330 ++itr;
3331 }
3332 }
3333}
3334
3335// creates aura application instance and registers it in lists
3336// aura application effects are handled separately to prevent aura list corruption
3338{
3339 // can't apply aura on unit which is going to be deleted - to not create a memory leak
3341
3342 // just return if the aura has been already removed
3343 // this can happen if OnEffectHitTarget() script hook killed the unit or the aura owner (which can be different)
3344 if (aura->IsRemoved())
3345 {
3346 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());
3347 return nullptr;
3348 }
3349
3350 // aura mustn't be already applied on target
3351 ASSERT (!aura->IsAppliedOnTarget(GetGUID()) && "Unit::_CreateAuraApplication: aura musn't be applied on target");
3352
3353 SpellInfo const* aurSpellInfo = aura->GetSpellInfo();
3354 uint32 aurId = aurSpellInfo->Id;
3355
3356 // ghost spell check, allow apply any auras at player loading in ghost mode (will be cleanup after load)
3357 if (!IsAlive() && !aurSpellInfo->IsDeathPersistent() &&
3358 (GetTypeId() != TYPEID_PLAYER || !ToPlayer()->GetSession()->PlayerLoading()))
3359 return nullptr;
3360
3361 Unit* caster = aura->GetCaster();
3362
3363 AuraApplication * aurApp = new AuraApplication(this, caster, aura, effMask);
3364 m_appliedAuras.insert(AuraApplicationMap::value_type(aurId, aurApp));
3365
3366 if (aurSpellInfo->AuraInterruptFlags)
3367 {
3368 m_interruptableAuras.push_back(aurApp);
3369 AddInterruptMask(aurSpellInfo->AuraInterruptFlags);
3370 }
3371
3372 if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState())
3373 m_auraStateAuras.insert(AuraStateAurasMap::value_type(aState, aurApp));
3374
3375 aura->_ApplyForTarget(this, caster, aurApp);
3376 return aurApp;
3377}
3378
3379void Unit::_ApplyAuraEffect(Aura* aura, uint8 effIndex)
3380{
3381 ASSERT(aura);
3382 ASSERT(aura->HasEffect(effIndex));
3384 ASSERT(aurApp);
3385 if (!aurApp->GetEffectMask())
3386 _ApplyAura(aurApp, 1 << effIndex);
3387 else
3388 aurApp->_HandleEffect(effIndex, true);
3389}
3390
3391// handles effects of aura application
3392// should be done after registering aura in lists
3394{
3395 Aura* aura = aurApp->GetBase();
3396
3397 _RemoveNoStackAurasDueToAura(aura, false);
3398
3399 if (aurApp->GetRemoveMode())
3400 return;
3401
3402 // Update target aura state flag
3403 if (AuraStateType aState = aura->GetSpellInfo()->GetAuraState())
3404 {
3405 uint32 aStateMask = (1 << (aState - 1));
3406 // force update so the new caster registers it
3407 if ((aStateMask & PER_CASTER_AURA_STATE_MASK) && HasFlag(UNIT_FIELD_AURASTATE, aStateMask))
3409 else
3410 ModifyAuraState(aState, true);
3411 }
3412
3413 if (aurApp->GetRemoveMode())
3414 return;
3415
3416 // Sitdown on apply aura req seated
3419
3420 Unit* caster = aura->GetCaster();
3421
3422 if (aurApp->GetRemoveMode())
3423 return;
3424
3425 aura->HandleAuraSpecificMods(aurApp, caster, true, false);
3426
3427 // apply effects of the aura
3428 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
3429 {
3430 if (effMask & 1 << i && (!aurApp->GetRemoveMode()))
3431 aurApp->_HandleEffect(i, true);
3432 }
3433
3434 if (Player* player = ToPlayer())
3435 {
3436 if (sConditionMgr->IsSpellUsedInSpellClickConditions(aura->GetId()))
3437 player->UpdateVisibleGameobjectsOrSpellClicks();
3438
3439 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GAIN_AURA, aura->GetId(), 0, aura->GetCaster());
3440 }
3441}
3442
3443// removes aura application from lists and unapplies effects
3444void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMode)
3445{
3446 AuraApplication * aurApp = i->second;
3447 ASSERT(aurApp);
3448 ASSERT(!aurApp->GetRemoveMode());
3449 ASSERT(aurApp->GetTarget() == this);
3450
3451 aurApp->SetRemoveMode(removeMode);
3452 Aura* aura = aurApp->GetBase();
3453 TC_LOG_DEBUG("spells", "Aura {} now is remove mode {}", aura->GetId(), removeMode);
3454
3455 // dead loop is killing the server probably
3456 ASSERT(m_removedAurasCount < 0xFFFFFFFF);
3457
3459
3460 Unit* caster = aura->GetCaster();
3461
3462 // Remove all pointers from lists here to prevent possible pointer invalidation on spellcast/auraapply/auraremove
3463 m_appliedAuras.erase(i);
3464
3465 if (aura->GetSpellInfo()->AuraInterruptFlags)
3466 {
3467 m_interruptableAuras.remove(aurApp);
3469 }
3470
3471 bool auraStateFound = false;
3472 AuraStateType auraState = aura->GetSpellInfo()->GetAuraState();
3473 if (auraState)
3474 {
3475 bool canBreak = false;
3476 // Get mask of all aurastates from remaining auras
3477 for (AuraStateAurasMap::iterator itr = m_auraStateAuras.lower_bound(auraState); itr != m_auraStateAuras.upper_bound(auraState) && !(auraStateFound && canBreak);)
3478 {
3479 if (itr->second == aurApp)
3480 {
3481 m_auraStateAuras.erase(itr);
3482 itr = m_auraStateAuras.lower_bound(auraState);
3483 canBreak = true;
3484 continue;
3485 }
3486 auraStateFound = true;
3487 ++itr;
3488 }
3489 }
3490
3491 aurApp->_Remove();
3492 aura->_UnapplyForTarget(this, caster, aurApp);
3493
3494 // remove effects of the spell - needs to be done after removing aura from lists
3495 for (uint8 itr = 0; itr < MAX_SPELL_EFFECTS; ++itr)
3496 {
3497 if (aurApp->HasEffect(itr))
3498 aurApp->_HandleEffect(itr, false);
3499 }
3500
3501 // all effect mustn't be applied
3502 ASSERT(!aurApp->GetEffectMask());
3503
3504 // Remove totem at next update if totem loses its aura
3505 if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE && GetTypeId() == TYPEID_UNIT && IsTotem())
3506 {
3507 if (ToTotem()->GetSpell() == aura->GetId() && ToTotem()->GetTotemType() == TOTEM_PASSIVE)
3509 }
3510
3511 // Remove aurastates only if needed and were not found
3512 if (auraState)
3513 {
3514 if (!auraStateFound)
3515 ModifyAuraState(auraState, false);
3516 else
3517 {
3518 // update for casters, some shouldn't 'see' the aura state
3519 uint32 aStateMask = (1 << (auraState - 1));
3520 if ((aStateMask & PER_CASTER_AURA_STATE_MASK) != 0)
3522 }
3523 }
3524
3525 aura->HandleAuraSpecificMods(aurApp, caster, false, false);
3526
3527 if (Player* player = ToPlayer())
3528 if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId()))
3529 player->UpdateVisibleGameobjectsOrSpellClicks();
3530
3531 i = m_appliedAuras.begin();
3532}
3533
3535{
3536 // aura can be removed from unit only if it's applied on it, shouldn't happen
3537 ASSERT(aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) == aurApp);
3538
3539 uint32 spellId = aurApp->GetBase()->GetId();
3540 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3541
3542 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3543 {
3544 if (iter->second == aurApp)
3545 {
3546 _UnapplyAura(iter, removeMode);
3547 return;
3548 }
3549 else
3550 ++iter;
3551 }
3552 ABORT();
3553}
3554
3556{
3557 SpellInfo const* spellProto = aura->GetSpellInfo();
3558
3559 // passive spell special case (only non stackable with ranks)
3560 if (spellProto->IsPassiveStackableWithRanks())
3561 return;
3562
3563 if (!IsHighestExclusiveAura(aura))
3564 {
3565 aura->Remove();
3566 return;
3567 }
3568
3569 if (owned)
3570 RemoveOwnedAuras([aura](Aura const* ownedAura) { return !aura->CanStackWith(ownedAura); }, AURA_REMOVE_BY_DEFAULT);
3571 else
3572 RemoveAppliedAuras([aura](AuraApplication const* appliedAura) { return !aura->CanStackWith(appliedAura->GetBase()); }, AURA_REMOVE_BY_DEFAULT);
3573}
3574
3575void Unit::_RegisterAuraEffect(AuraEffect* aurEff, bool apply)
3576{
3577 if (apply)
3578 m_modAuras[aurEff->GetAuraType()].push_back(aurEff);
3579 else
3580 m_modAuras[aurEff->GetAuraType()].remove(aurEff);
3581}
3582
3583// All aura base removes should go through this function!
3584void Unit::RemoveOwnedAura(AuraMap::iterator& i, AuraRemoveMode removeMode)
3585{
3586 Aura* aura = i->second;
3587 ASSERT(!aura->IsRemoved());
3588
3589 // if unit currently update aura list then make safe update iterator shift to next
3590 if (m_auraUpdateIterator == i)
3592
3593 m_ownedAuras.erase(i);
3594 m_removedAuras.push_back(aura);
3595
3596 // Unregister single target aura
3597 if (aura->IsSingleTarget())
3598 aura->UnregisterSingleTarget();
3599
3600 aura->_Remove(removeMode);
3601
3602 i = m_ownedAuras.begin();
3603}
3604
3605void Unit::RemoveOwnedAura(uint32 spellId, ObjectGuid casterGUID, uint8 reqEffMask, AuraRemoveMode removeMode)
3606{
3607 for (AuraMap::iterator itr = m_ownedAuras.lower_bound(spellId); itr != m_ownedAuras.upper_bound(spellId);)
3608 if (((itr->second->GetEffectMask() & reqEffMask) == reqEffMask) && (!casterGUID || itr->second->GetCasterGUID() == casterGUID))
3609 {
3610 RemoveOwnedAura(itr, removeMode);
3611 itr = m_ownedAuras.lower_bound(spellId);
3612 }
3613 else
3614 ++itr;
3615}
3616
3618{
3619 if (aura->IsRemoved())
3620 return;
3621
3622 ASSERT(aura->GetOwner() == this);
3623
3624 if (removeMode == AURA_REMOVE_NONE)
3625 {
3626 TC_LOG_ERROR("spells", "Unit::RemoveOwnedAura() called with unallowed removeMode AURA_REMOVE_NONE, spellId {}", aura->GetId());
3627 return;
3628 }
3629
3630 uint32 spellId = aura->GetId();
3631 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3632
3633 for (AuraMap::iterator itr = range.first; itr != range.second; ++itr)
3634 {
3635 if (itr->second == aura)
3636 {
3637 RemoveOwnedAura(itr, removeMode);
3638 return;
3639 }
3640 }
3641
3642 ABORT();
3643}
3644
3645Aura* Unit::GetOwnedAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask, Aura* except) const
3646{
3647 AuraMapBounds range = m_ownedAuras.equal_range(spellId);
3648 for (AuraMap::const_iterator itr = range.first; itr != range.second; ++itr)
3649 {
3650 if (((itr->second->GetEffectMask() & reqEffMask) == reqEffMask)
3651 && (!casterGUID || itr->second->GetCasterGUID() == casterGUID)
3652 && (!itemCasterGUID || itr->second->GetCastItemGUID() == itemCasterGUID)
3653 && (!except || except != itr->second))
3654 {
3655 return itr->second;
3656 }
3657 }
3658 return nullptr;
3659}
3660
3661void Unit::RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode)
3662{
3663 AuraApplication * aurApp = i->second;
3664 // Do not remove aura which is already being removed
3665 if (aurApp->GetRemoveMode())
3666 return;
3667 Aura* aura = aurApp->GetBase();
3668 _UnapplyAura(i, mode);
3669 // Remove aura - for Area and Target auras
3670 if (aura->GetOwner() == this)
3671 aura->Remove(mode);
3672}
3673
3674void Unit::RemoveAura(uint32 spellId, ObjectGuid caster, uint8 reqEffMask, AuraRemoveMode removeMode)
3675{
3676 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3677 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3678 {
3679 Aura const* aura = iter->second->GetBase();
3680 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
3681 && (!caster || aura->GetCasterGUID() == caster))
3682 {
3683 RemoveAura(iter, removeMode);
3684 return;
3685 }
3686 else
3687 ++iter;
3688 }
3689}
3690
3692{
3693 // we've special situation here, RemoveAura called while during aura removal
3694 // this kind of call is needed only when aura effect removal handler
3695 // or event triggered by it expects to remove
3696 // not yet removed effects of an aura
3697 if (aurApp->GetRemoveMode())
3698 {
3699 // remove remaining effects of an aura
3700 for (uint8 itr = 0; itr < MAX_SPELL_EFFECTS; ++itr)
3701 {
3702 if (aurApp->HasEffect(itr))
3703 aurApp->_HandleEffect(itr, false);
3704 }
3705 return;
3706 }
3707 // no need to remove
3708 if (aurApp->GetBase()->GetApplicationOfTarget(GetGUID()) != aurApp || aurApp->GetBase()->IsRemoved())
3709 return;
3710
3711 uint32 spellId = aurApp->GetBase()->GetId();
3712 AuraApplicationMapBoundsNonConst range = m_appliedAuras.equal_range(spellId);
3713
3714 for (AuraApplicationMap::iterator iter = range.first; iter != range.second;)
3715 {
3716 if (aurApp == iter->second)
3717 {
3718 RemoveAura(iter, mode);
3719 return;
3720 }
3721 else
3722 ++iter;
3723 }
3724}
3725
3727{
3728 if (aura->IsRemoved())
3729 return;
3730 if (AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID()))
3731 RemoveAura(aurApp, mode);
3732}
3733
3734void Unit::RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3735{
3736 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
3737 {
3738 if (check(iter->second))
3739 {
3740 RemoveAura(iter, removeMode);
3741 continue;
3742 }
3743 ++iter;
3744 }
3745}
3746
3747void Unit::RemoveOwnedAuras(std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3748{
3749 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
3750 {
3751 if (check(iter->second))
3752 {
3753 RemoveOwnedAura(iter, removeMode);
3754 continue;
3755 }
3756 ++iter;
3757 }
3758}
3759
3760void Unit::RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3761{
3762 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3763 {
3764 if (check(iter->second))
3765 {
3766 RemoveAura(iter, removeMode);
3767 iter = m_appliedAuras.lower_bound(spellId);
3768 continue;
3769 }
3770 ++iter;
3771 }
3772}
3773
3774void Unit::RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3775{
3776 for (AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
3777 {
3778 if (check(iter->second))
3779 {
3780 RemoveOwnedAura(iter, removeMode);
3781 iter = m_ownedAuras.lower_bound(spellId);
3782 continue;
3783 }
3784 ++iter;
3785 }
3786}
3787
3788void Unit::RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
3789{
3790 for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
3791 {
3792 Aura* aura = (*iter)->GetBase();
3794 ASSERT(aurApp);
3795
3796 ++iter;
3797 if (check(aurApp))
3798 {
3799 uint32 removedAuras = m_removedAurasCount;
3800 RemoveAura(aurApp, removeMode);
3801 if (m_removedAurasCount > removedAuras + 1)
3802 iter = m_modAuras[auraType].begin();
3803 }
3804 }
3805}
3806
3807void Unit::RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID, uint8 reqEffMask, AuraRemoveMode removeMode)
3808{
3809 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3810 {
3811 Aura const* aura = iter->second->GetBase();
3812 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
3813 && (!casterGUID || aura->GetCasterGUID() == casterGUID))
3814 {
3815 RemoveAura(iter, removeMode);
3816 iter = m_appliedAuras.lower_bound(spellId);
3817 }
3818 else
3819 ++iter;
3820 }
3821}
3822
3823void Unit::RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID, AuraRemoveMode removeMode)
3824{
3825 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3826 for (AuraMap::iterator iter = range.first; iter != range.second;)
3827 {
3828 Aura* aura = iter->second;
3829 if ((aura->GetType() == UNIT_AURA_TYPE)
3830 && (!casterGUID || aura->GetCasterGUID() == casterGUID))
3831 {
3832 aura->ModStackAmount(-1, removeMode);
3833 return;
3834 }
3835 else
3836 ++iter;
3837 }
3838}
3839
3840void Unit::RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject* dispeller, uint8 chargesRemoved /*= 1*/)
3841{
3842 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3843 for (AuraMap::iterator iter = range.first; iter != range.second;)
3844 {
3845 Aura* aura = iter->second;
3846 if (aura->GetCasterGUID() == casterGUID)
3847 {
3848 DispelInfo dispelInfo(dispeller, dispellerSpellId, chargesRemoved);
3849
3850 // Call OnDispel hook on AuraScript
3851 aura->CallScriptDispel(&dispelInfo);
3852
3855 else
3857
3858 // Call AfterDispel hook on AuraScript
3859 aura->CallScriptAfterDispel(&dispelInfo);
3860
3861 return;
3862 }
3863 else
3864 ++iter;
3865 }
3866}
3867
3869{
3870 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
3871 for (AuraMap::iterator iter = range.first; iter != range.second;)
3872 {
3873 Aura* aura = iter->second;
3874 if (aura->GetCasterGUID() == casterGUID)
3875 {
3876 int32 damage[MAX_SPELL_EFFECTS];
3877 int32 baseDamage[MAX_SPELL_EFFECTS];
3878 uint8 effMask = 0;
3879 uint8 recalculateMask = 0;
3880 Unit* caster = aura->GetCaster();
3881 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
3882 {
3883 if (aura->GetEffect(i))
3884 {
3885 baseDamage[i] = aura->GetEffect(i)->GetBaseAmount();
3886 damage[i] = aura->GetEffect(i)->GetAmount();
3887 effMask |= (1<<i);
3888 if (aura->GetEffect(i)->CanBeRecalculated())
3889 recalculateMask |= (1<<i);
3890 }
3891 else
3892 {
3893 baseDamage[i] = 0;
3894 damage[i] = 0;
3895 }
3896 }
3897
3898 bool stealCharge = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
3899 // Cast duration to unsigned to prevent permanent aura's such as Righteous Fury being permanently added to caster
3900 uint32 dur = std::min(2u * MINUTE * IN_MILLISECONDS, uint32(aura->GetDuration()));
3901
3902 if (Unit* unitStealer = stealer->ToUnit())
3903 {
3904 if (Aura* oldAura = unitStealer->GetAura(aura->GetId(), aura->GetCasterGUID()))
3905 {
3906 if (stealCharge)
3907 oldAura->ModCharges(1);
3908 else
3909 oldAura->ModStackAmount(1);
3910 oldAura->SetDuration(int32(dur));
3911 }
3912 else
3913 {
3914 // single target state must be removed before aura creation to preserve existing single target aura
3915 if (aura->IsSingleTarget())
3916 aura->UnregisterSingleTarget();
3917
3918 AuraCreateInfo createInfo(aura->GetSpellInfo(), effMask, unitStealer);
3919 createInfo
3921 .SetBaseAmount(baseDamage);
3922
3923 if (Aura* newAura = Aura::TryRefreshStackOrCreate(createInfo))
3924 {
3925 // created aura must not be single target aura,, so stealer won't loose it on recast
3926 if (newAura->IsSingleTarget())
3927 {
3928 newAura->UnregisterSingleTarget();
3929 // bring back single target aura status to the old aura
3930 aura->SetIsSingleTarget(true);
3931 caster->GetSingleCastAuras().push_back(aura);
3932 }
3933 // FIXME: using aura->GetMaxDuration() maybe not blizzlike but it fixes stealing of spells like Innervate
3934 newAura->SetLoadedState(aura->GetMaxDuration(), int32(dur), stealCharge ? 1 : aura->GetCharges(), 1, recalculateMask, aura->GetCritChance(), aura->CanApplyResilience(), &damage[0]);
3935 newAura->ApplyForTargets();
3936 }
3937 }
3938 }
3939
3940 if (stealCharge)
3942 else
3944
3945 return;
3946 }
3947 else
3948 ++iter;
3949 }
3950}
3951
3953{
3954 for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
3955 {
3956 if (iter->second->GetBase()->GetCastItemGUID() == castItemGuid)
3957 {
3958 RemoveAura(iter);
3959 iter = m_appliedAuras.lower_bound(spellId);
3960 }
3961 else
3962 ++iter;
3963 }
3964}
3965
3966void Unit::RemoveAurasByType(AuraType auraType, ObjectGuid casterGUID, Aura* except, bool negative, bool positive)
3967{
3968 for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
3969 {
3970 Aura* aura = (*iter)->GetBase();
3972 ASSERT(aurApp);
3973
3974 ++iter;
3975 if (aura != except && (!casterGUID || aura->GetCasterGUID() == casterGUID)
3976 && ((negative && !aurApp->IsPositive()) || (positive && aurApp->IsPositive())))
3977 {
3978 uint32 removedAuras = m_removedAurasCount;
3979 RemoveAura(aurApp);
3980 if (m_removedAurasCount > removedAuras + 1)
3981 iter = m_modAuras[auraType].begin();
3982 }
3983 }
3984}
3985
3987{
3988 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
3989 {
3990 SpellInfo const* spell = iter->second->GetBase()->GetSpellInfo();
3991 if (spell->HasAttribute(flags))
3992 RemoveAura(iter);
3993 else
3994 ++iter;
3995 }
3996}
3997
3999{
4000 // single target auras from other casters
4001 // Iterate m_ownedAuras - aura is marked as single target in Unit::AddAura (and pushed to m_ownedAuras).
4002 // m_appliedAuras will NOT contain the aura before first Unit::Update after adding it to m_ownedAuras.
4003 // Quickly removing such an aura will lead to it not being unregistered from caster's single cast auras container
4004 // leading to assertion failures if the aura was cast on a player that can
4005 // (and is changing map at the point where this function is called).
4006 // Such situation occurs when player is logging in inside an instance and fails the entry check for any reason.
4007 // The aura that was loaded from db (indirectly, via linked casts) gets removed before it has a chance
4008 // to register in m_appliedAuras
4009 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4010 {
4011 Aura const* aura = iter->second;
4012
4013 if (aura->GetCasterGUID() != GetGUID() && aura->IsSingleTarget())
4014 {
4015 if (!newPhase)
4016 RemoveOwnedAura(iter);
4017 else
4018 {
4019 Unit* caster = aura->GetCaster();
4020 if (!caster || !caster->InSamePhase(newPhase))
4021 RemoveOwnedAura(iter);
4022 else
4023 ++iter;
4024 }
4025 }
4026 else
4027 ++iter;
4028 }
4029
4030 // single target auras at other targets
4031 AuraList& scAuras = GetSingleCastAuras();
4032 for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
4033 {
4034 Aura* aura = *iter;
4035 if (aura->GetUnitOwner() != this && !aura->GetUnitOwner()->InSamePhase(newPhase))
4036 {
4037 aura->Remove();
4038 iter = scAuras.begin();
4039 }
4040 else
4041 ++iter;
4042 }
4043}
4044
4046{
4047 if (!(m_interruptMask & flag))
4048 return;
4049
4050 // interrupt auras
4051 for (AuraApplicationList::iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end();)
4052 {
4053 Aura* aura = (*iter)->GetBase();
4054 ++iter;
4055 if ((aura->GetSpellInfo()->AuraInterruptFlags & flag) && (!except || aura->GetId() != except))
4056 {
4057 uint32 removedAuras = m_removedAurasCount;
4058 RemoveAura(aura);
4059 if (m_removedAurasCount > removedAuras + 1)
4060 iter = m_interruptableAuras.begin();
4061 }
4062 }
4063
4064 // interrupt channeled spell
4066 if (spell->getState() == SPELL_STATE_CASTING
4067 && (spell->m_spellInfo->ChannelInterruptFlags & flag)
4068 && spell->m_spellInfo->Id != except)
4070
4072}
4073
4074void Unit::RemoveAurasWithFamily(SpellFamilyNames family, flag96 const& familyFlag, ObjectGuid casterGUID)
4075{
4076 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4077 {
4078 Aura const* aura = iter->second->GetBase();
4079 if (!casterGUID || aura->GetCasterGUID() == casterGUID)
4080 {
4081 SpellInfo const* spell = aura->GetSpellInfo();
4082 if (spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags & familyFlag)
4083 {
4084 RemoveAura(iter);
4085 continue;
4086 }
4087 }
4088 ++iter;
4089 }
4090}
4091
4093{
4094 if (withRoot)
4096
4098}
4099
4100void Unit::RemoveAurasWithMechanic(uint32 mechanicMaskToRemove, AuraRemoveMode removeMode, uint32 exceptSpellId, bool withEffectMechanics)
4101{
4102 std::vector<Aura*> aurasToUpdateTargets;
4103 RemoveAppliedAuras([=, &aurasToUpdateTargets](AuraApplication const* aurApp)
4104 {
4105 Aura* aura = aurApp->GetBase();
4106 if (exceptSpellId && aura->GetId() == exceptSpellId)
4107 return false;
4108
4109 uint32 appliedMechanicMask = aura->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask());
4110 if (!(appliedMechanicMask & mechanicMaskToRemove))
4111 return false;
4112
4113 // spell mechanic matches required mask for removal
4114 if ((1 << aura->GetSpellInfo()->Mechanic) & mechanicMaskToRemove || withEffectMechanics)
4115 return true;
4116
4117 // effect mechanic matches required mask for removal - don't remove, only update targets
4118 aurasToUpdateTargets.push_back(aura);
4119 return false;
4120 }, removeMode);
4121
4122 for (Aura* aura : aurasToUpdateTargets)
4123 {
4124 aura->UpdateTargetMap(aura->GetCaster());
4125
4126 // Fully remove the aura if all effects were removed
4127 if (!aura->IsPassive() && aura->GetOwner() == this && !aura->GetApplicationOfTarget(GetGUID()))
4128 aura->Remove(removeMode);
4129 }
4130}
4131
4133{
4134 uint32 mechanic_mask = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT);
4135 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4136 {
4137 Aura const* aura = iter->second->GetBase();
4138 if ((aura->GetSpellInfo()->GetAllEffectsMechanicMask() & mechanic_mask) && !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR0_CU_AURA_CC))
4139 {
4140 RemoveAura(iter);
4141 continue;
4142 }
4143 ++iter;
4144 }
4145}
4146
4148{
4149 // make sure that all area auras not applied on self are removed - prevent access to deleted pointer later
4150 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4151 {
4152 Aura* aura = iter->second;
4153 ++iter;
4154 Aura::ApplicationMap const& appMap = aura->GetApplicationMap();
4155 for (Aura::ApplicationMap::const_iterator itr = appMap.begin(); itr!= appMap.end();)
4156 {
4157 AuraApplication * aurApp = itr->second;
4158 ++itr;
4159 Unit* target = aurApp->GetTarget();
4160 if (target == this)
4161 continue;
4162 target->RemoveAura(aurApp);
4163 // things linked on aura remove may apply new area aura - so start from the beginning
4164 iter = m_ownedAuras.begin();
4165 }
4166 }
4167
4168 // remove area auras owned by others
4169 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4170 {
4171 if (iter->second->GetBase()->GetOwner() != this)
4172 {
4173 RemoveAura(iter);
4174 }
4175 else
4176 ++iter;
4177 }
4178}
4179
4181{
4182 // this may be a dead loop if some events on aura remove will continiously apply aura on remove
4183 // we want to have all auras removed, so use your brain when linking events
4184 for (int counter = 0; !m_appliedAuras.empty() || !m_ownedAuras.empty(); counter++)
4185 {
4186 AuraApplicationMap::iterator aurAppIter;
4187 for (aurAppIter = m_appliedAuras.begin(); aurAppIter != m_appliedAuras.end();)
4189
4190 AuraMap::iterator aurIter;
4191 for (aurIter = m_ownedAuras.begin(); aurIter != m_ownedAuras.end();)
4192 RemoveOwnedAura(aurIter);
4193
4194 const int maxIteration = 50;
4195 // give this loop a few tries, if there are still auras then log as much information as possible
4196 if (counter >= maxIteration)
4197 {
4198 std::stringstream sstr;
4199 sstr << "Unit::RemoveAllAuras() iterated " << maxIteration << " times already but there are still "
4200 << m_appliedAuras.size() << " m_appliedAuras and " << m_ownedAuras.size() << " m_ownedAuras. Details:" << "\n";
4201 sstr << GetDebugInfo() << "\n";
4202
4203 if (!m_appliedAuras.empty())
4204 {
4205 sstr << "m_appliedAuras:" << "\n";
4206
4207 for (std::pair<uint32 const, AuraApplication*>& auraAppPair : m_appliedAuras)
4208 sstr << auraAppPair.second->GetDebugInfo() << "\n";
4209 }
4210
4211 if (!m_ownedAuras.empty())
4212 {
4213 sstr << "m_ownedAuras:" << "\n";
4214
4215 for (auto const& [spellId, aura] : m_ownedAuras)
4216 sstr << aura->GetDebugInfo() << "\n";
4217 }
4218
4219 TC_LOG_ERROR("entities.unit", "{}", sstr.str());
4220 ABORT_MSG("%s", sstr.str().c_str());
4221
4222 break;
4223 }
4224 }
4225}
4226
4228{
4229 // in join, remove positive buffs, on end, remove negative
4230 // used to remove positive visible auras in arenas
4231 RemoveAppliedAuras([](AuraApplication const* aurApp)
4232 {
4233 Aura const* aura = aurApp->GetBase();
4234 return (!aura->GetSpellInfo()->HasAttribute(SPELL_ATTR4_DONT_REMOVE_IN_ARENA) // don't remove stances, shadowform, pally/hunter auras
4235 && !aura->IsPassive() // don't remove passive auras
4236 && (aurApp->IsPositive() || !aura->GetSpellInfo()->HasAttribute(SPELL_ATTR3_DEATH_PERSISTENT))) || // not negative death persistent auras
4237 aura->GetSpellInfo()->HasAttribute(SPELL_ATTR5_REMOVE_ON_ARENA_ENTER); // special marker, always remove
4238 });
4239}
4240
4242{
4243 if (IsCharmedOwnedByPlayerOrPlayer()) // if it is a player owned creature it should not remove the aura
4244 return;
4245
4246 // don't remove vehicle auras, passengers aren't supposed to drop off the vehicle
4247 // don't remove clone caster on evade (to be verified)
4249}
4250
4252{
4253 // used just after dieing to remove all visible auras
4254 // and disable the mods for the passive ones
4255 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4256 {
4257 Aura const* aura = iter->second->GetBase();
4258 if (!aura->IsPassive() && !aura->IsDeathPersistent())
4260 else
4261 ++iter;
4262 }
4263
4264 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4265 {
4266 Aura* aura = iter->second;
4267 if (!aura->IsPassive() && !aura->IsDeathPersistent())
4269 else
4270 ++iter;
4271 }
4272}
4273
4275{
4276 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4277 {
4278 Aura const* aura = iter->second->GetBase();
4279 if (!aura->IsPassive() && aura->GetSpellInfo()->IsRequiringDeadTarget())
4281 else
4282 ++iter;
4283 }
4284
4285 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4286 {
4287 Aura* aura = iter->second;
4288 if (!aura->IsPassive() && aura->GetSpellInfo()->IsRequiringDeadTarget())
4290 else
4291 ++iter;
4292 }
4293}
4294
4296{
4297 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4298 {
4299 Aura const* aura = iter->second->GetBase();
4300 if (aura->GetSpellInfo()->HasAura(type))
4301 ++iter;
4302 else
4304 }
4305
4306 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4307 {
4308 Aura* aura = iter->second;
4309 if (aura->GetSpellInfo()->HasAura(type))
4310 ++iter;
4311 else
4313 }
4314}
4315
4317{
4318 for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
4319 {
4320 Aura const* aura = iter->second->GetBase();
4321 if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2))
4322 ++iter;
4323 else
4325 }
4326
4327 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4328 {
4329 Aura* aura = iter->second;
4330 if (aura->GetSpellInfo()->HasAura(type1) || aura->GetSpellInfo()->HasAura(type2))
4331 ++iter;
4332 else
4334 }
4335}
4336
4338{
4339 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
4340 {
4341 Aura* aura = iter->second;
4342 if (aura->GetCasterGUID() == casterGUID && aura->GetSpellInfo()->IsGroupBuff())
4343 {
4344 RemoveOwnedAura(iter);
4345 continue;
4346 }
4347 ++iter;
4348 }
4349}
4350
4351void Unit::DelayOwnedAuras(uint32 spellId, ObjectGuid caster, int32 delaytime)
4352{
4353 AuraMapBoundsNonConst range = m_ownedAuras.equal_range(spellId);
4354 for (; range.first != range.second; ++range.first)
4355 {
4356 Aura* aura = range.first->second;
4357 if (!caster || aura->GetCasterGUID() == caster)
4358 {
4359 if (aura->GetDuration() < delaytime)
4360 aura->SetDuration(0);
4361 else
4362 aura->SetDuration(aura->GetDuration() - delaytime);
4363
4364 // update for out of range group members (on 1 slot use)
4366 }
4367 }
4368}
4369
4371{
4372 for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
4373 (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, false);
4374}
4375
4377{
4378 for (AuraApplicationMap::iterator i = m_appliedAuras.begin(); i != m_appliedAuras.end(); ++i)
4379 (*i).second->GetBase()->HandleAllEffects(i->second, AURA_EFFECT_HANDLE_STAT, true);
4380}
4381
4382AuraEffect* Unit::GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster) const
4383{
4384 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4385 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4386 {
4387 if (itr->second->HasEffect(effIndex)
4388 && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
4389 {
4390 return itr->second->GetBase()->GetEffect(effIndex);
4391 }
4392 }
4393 return nullptr;
4394}
4395
4397{
4398 uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
4399 while (rankSpell)
4400 {
4401 if (AuraEffect* aurEff = GetAuraEffect(rankSpell, effIndex, caster))
4402 return aurEff;
4403 rankSpell = sSpellMgr->GetNextSpellInChain(rankSpell);
4404 }
4405 return nullptr;
4406}
4407
4409{
4410 AuraEffectList const& auras = GetAuraEffectsByType(type);
4411 for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
4412 {
4413 if (effIndex != (*itr)->GetEffIndex())
4414 continue;
4415 SpellInfo const* spell = (*itr)->GetSpellInfo();
4416 if (spell->SpellIconID == iconId && spell->SpellFamilyName == uint32(name) && !spell->SpellFamilyFlags)
4417 return *itr;
4418 }
4419 return nullptr;
4420}
4421
4422AuraEffect* Unit::GetAuraEffect(AuraType type, SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, ObjectGuid casterGUID) const
4423{
4424 AuraEffectList const& auras = GetAuraEffectsByType(type);
4425 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4426 {
4427 SpellInfo const* spell = (*i)->GetSpellInfo();
4428 if (spell->SpellFamilyName == uint32(family) && spell->SpellFamilyFlags & flag96(familyFlag1, familyFlag2, familyFlag3))
4429 {
4430 if (!casterGUID.IsEmpty() && (*i)->GetCasterGUID() != casterGUID)
4431 continue;
4432 return (*i);
4433 }
4434 }
4435 return nullptr;
4436}
4437
4439{
4440 return GetAuraEffect(SPELL_AURA_DUMMY, name, iconId, effIndex);
4441}
4442
4443AuraApplication * Unit::GetAuraApplication(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask, AuraApplication * except) const
4444{
4445 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4446 for (; range.first != range.second; ++range.first)
4447 {
4448 AuraApplication* app = range.first->second;
4449 Aura const* aura = app->GetBase();
4450
4451 if (((aura->GetEffectMask() & reqEffMask) == reqEffMask)
4452 && (!casterGUID || aura->GetCasterGUID() == casterGUID)
4453 && (!itemCasterGUID || aura->GetCastItemGUID() == itemCasterGUID)
4454 && (!except || except != app))
4455 {
4456 return app;
4457 }
4458 }
4459 return nullptr;
4460}
4461
4462Aura* Unit::GetAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask) const
4463{
4464 AuraApplication * aurApp = GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask);
4465 return aurApp ? aurApp->GetBase() : nullptr;
4466}
4467
4468AuraApplication * Unit::GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask, AuraApplication* except) const
4469{
4470 uint32 rankSpell = sSpellMgr->GetFirstSpellInChain(spellId);
4471 while (rankSpell)
4472 {
4473 if (AuraApplication * aurApp = GetAuraApplication(rankSpell, casterGUID, itemCasterGUID, reqEffMask, except))
4474 return aurApp;
4475 rankSpell = sSpellMgr->GetNextSpellInChain(rankSpell);
4476 }
4477 return nullptr;
4478}
4479
4480Aura* Unit::GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask) const
4481{
4482 AuraApplication * aurApp = GetAuraApplicationOfRankedSpell(spellId, casterGUID, itemCasterGUID, reqEffMask);
4483 return aurApp ? aurApp->GetBase() : nullptr;
4484}
4485
4486void Unit::GetDispellableAuraList(WorldObject const* caster, uint32 dispelMask, DispelChargesList& dispelList, bool isReflect /*= false*/) const
4487{
4488 // we should not be able to dispel diseases if the target is affected by unholy blight
4489 if (dispelMask & (1 << DISPEL_DISEASE) && HasAura(50536))
4490 dispelMask &= ~(1 << DISPEL_DISEASE);
4491
4492 AuraMap const& auras = GetOwnedAuras();
4493 for (auto itr = auras.begin(); itr != auras.end(); ++itr)
4494 {
4495 Aura* aura = itr->second;
4496 AuraApplication const* aurApp = aura->GetApplicationOfTarget(GetGUID());
4497 if (!aurApp)
4498 continue;
4499
4500 // don't try to remove passive auras
4501 if (aura->IsPassive())
4502 continue;
4503
4504 if (aura->GetSpellInfo()->GetDispelMask() & dispelMask)
4505 {
4506 // do not remove positive auras if friendly target
4507 // negative auras if non-friendly
4508 // unless we're reflecting (dispeller eliminates one of it's benefitial buffs)
4509 if (isReflect != (aurApp->IsPositive() == IsFriendlyTo(caster)))
4510 continue;
4511
4512 // 2.4.3 Patch Notes: "Dispel effects will no longer attempt to remove effects that have 100% dispel resistance."
4513 int32 chance = aura->CalcDispelChance(this, !IsFriendlyTo(caster));
4514 if (!chance)
4515 continue;
4516
4517 // The charges / stack amounts don't count towards the total number of auras that can be dispelled.
4518 // Ie: A dispel on a target with 5 stacks of Winters Chill and a Polymorph has 1 / (1 + 1) -> 50% chance to dispell
4519 // Polymorph instead of 1 / (5 + 1) -> 16%.
4520 bool const dispelCharges = aura->GetSpellInfo()->HasAttribute(SPELL_ATTR7_DISPEL_CHARGES);
4521 uint8 charges = dispelCharges ? aura->GetCharges() : aura->GetStackAmount();
4522 if (charges > 0)
4523 dispelList.emplace_back(aura, chance, charges);
4524 }
4525 }
4526}
4527
4528bool Unit::HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster) const
4529{
4530 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4531 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4532 {
4533 if (itr->second->HasEffect(effIndex)
4534 && (!caster || itr->second->GetBase()->GetCasterGUID() == caster))
4535 {
4536 return true;
4537 }
4538 }
4539 return false;
4540}
4541
4543{
4544 uint32 count = 0;
4545 AuraApplicationMapBounds range = m_appliedAuras.equal_range(spellId);
4546
4547 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
4548 {
4549 if (itr->second->GetBase()->GetStackAmount() == 0)
4550 ++count;
4551 else
4552 count += (uint32)itr->second->GetBase()->GetStackAmount();
4553 }
4554
4555 return count;
4556}
4557
4558bool Unit::HasAura(uint32 spellId, ObjectGuid casterGUID, ObjectGuid itemCasterGUID, uint8 reqEffMask) const
4559{
4560 if (GetAuraApplication(spellId, casterGUID, itemCasterGUID, reqEffMask))
4561 return true;
4562 return false;
4563}
4564
4565bool Unit::HasAuraType(AuraType auraType) const
4566{
4567 return (!m_modAuras[auraType].empty());
4568}
4569
4571{
4572 for (AuraEffect const* eff : GetAuraEffectsByType(auraType))
4573 if (caster == eff->GetCasterGUID())
4574 return true;
4575 return false;
4576}
4577
4578bool Unit::HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscvalue) const
4579{
4580 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4581 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4582 if (miscvalue == (*i)->GetMiscValue())
4583 return true;
4584 return false;
4585}
4586
4587bool Unit::HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
4588{
4589 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4590 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4591 if ((*i)->IsAffectingSpell(affectedSpell))
4592 return true;
4593 return false;
4594}
4595
4596bool Unit::HasAuraTypeWithValue(AuraType auraType, int32 value) const
4597{
4598 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4599 for (AuraEffectList::const_iterator i = mTotalAuraList.begin(); i != mTotalAuraList.end(); ++i)
4600 if (value == (*i)->GetAmount())
4601 return true;
4602 return false;
4603}
4604
4605bool Unit::HasAuraTypeWithTriggerSpell(AuraType auratype, uint32 triggerSpell) const
4606{
4607 for (AuraEffect const* aura : GetAuraEffectsByType(auratype))
4608 if (aura->GetSpellEffectInfo().TriggerSpell == triggerSpell)
4609 return true;
4610 return false;
4611}
4612
4614{
4615 if (!(m_interruptMask & flag))
4616 return false;
4617 for (AuraApplicationList::const_iterator iter = m_interruptableAuras.begin(); iter != m_interruptableAuras.end(); ++iter)
4618 {
4619 if (!(*iter)->IsPositive() && (*iter)->GetBase()->GetSpellInfo()->AuraInterruptFlags & flag && (!guid || (*iter)->GetBase()->GetCasterGUID() == guid))
4620 return true;
4621 }
4622 return false;
4623}
4624
4625bool Unit::HasAuraWithMechanic(uint32 mechanicMask) const
4626{
4627 for (AuraApplicationMap::const_iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end(); ++iter)
4628 {
4629 SpellInfo const* spellInfo = iter->second->GetBase()->GetSpellInfo();
4630 if (spellInfo->Mechanic && (mechanicMask & (1 << spellInfo->Mechanic)))
4631 return true;
4632
4633 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
4634 if (iter->second->HasEffect(spellEffectInfo.EffectIndex) && spellEffectInfo.IsEffect() && spellEffectInfo.Mechanic)
4635 if (mechanicMask & (1 << spellEffectInfo.Mechanic))
4636 return true;
4637 }
4638
4639 return false;
4640}
4641
4642bool Unit::HasStrongerAuraWithDR(SpellInfo const* auraSpellInfo, Unit* caster, bool triggered) const
4643{
4644 DiminishingGroup diminishGroup = auraSpellInfo->GetDiminishingReturnsGroupForSpell(triggered);
4645 DiminishingLevels level = GetDiminishing(diminishGroup);
4646 for (auto itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
4647 {
4648 SpellInfo const* spellInfo = itr->second->GetBase()->GetSpellInfo();
4649 if (spellInfo->GetDiminishingReturnsGroupForSpell(triggered) != diminishGroup)
4650 continue;
4651
4652 int32 existingDuration = itr->second->GetBase()->GetDuration();
4653 int32 newDuration = auraSpellInfo->GetMaxDuration();
4654 ApplyDiminishingToDuration(auraSpellInfo, triggered, newDuration, caster, level);
4655 if (newDuration > 0 && newDuration < existingDuration)
4656 return true;
4657 }
4658
4659 return false;
4660}
4661
4663{
4665 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4666 {
4667 if ((*i)->GetMiscValue() == script)
4668 if ((*i)->IsAffectingSpell(spell))
4669 return (*i);
4670 }
4671 return nullptr;
4672}
4673
4675{
4676 static const AuraType diseaseAuraTypes[] =
4677 {
4678 SPELL_AURA_PERIODIC_DAMAGE, // Frost Fever and Blood Plague
4679 SPELL_AURA_LINKED // Crypt Fever and Ebon Plague
4680 };
4681
4682 uint32 diseases = 0;
4683 for (AuraType aType : diseaseAuraTypes)
4684 {
4685 for (auto itr = m_modAuras[aType].begin(); itr != m_modAuras[aType].end();)
4686 {
4687 // Get auras with disease dispel type by caster
4688 if ((*itr)->GetSpellInfo()->Dispel == DISPEL_DISEASE
4689 && (*itr)->GetCasterGUID() == casterGUID)
4690 {
4691 ++diseases;
4692
4693 if (remove)
4694 {
4695 RemoveAura((*itr)->GetId(), (*itr)->GetCasterGUID());
4696 itr = m_modAuras[aType].begin();
4697 continue;
4698 }
4699 }
4700 ++itr;
4701 }
4702 }
4703 return diseases;
4704}
4705
4707{
4708 static const AuraType diseaseAuraTypes[] =
4709 {
4713 };
4714
4715 uint32 dots = 0;
4716 for (AuraType const* itr = &diseaseAuraTypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr)
4717 {
4718 Unit::AuraEffectList const& auras = GetAuraEffectsByType(*itr);
4719 for (AuraEffectList::const_iterator i = auras.begin(); i != auras.end(); ++i)
4720 {
4721 // Get auras by caster
4722 if ((*i)->GetCasterGUID() == casterGUID)
4723 ++dots;
4724 }
4725 }
4726 return dots;
4727}
4728
4729int32 Unit::GetTotalAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4730{
4731 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4732 if (mTotalAuraList.empty())
4733 return 0;
4734
4735 std::map<SpellGroup, int32> sameEffectSpellGroup;
4736 int32 modifier = 0;
4737
4738 for (AuraEffect const* aurEff : mTotalAuraList)
4739 {
4740 if (predicate(aurEff))
4741 {
4742 // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
4743 // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
4744 if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), static_cast<uint32>(auraType), aurEff->GetAmount(), sameEffectSpellGroup))
4745 modifier += aurEff->GetAmount();
4746 }
4747 }
4748
4749 // Add the highest of the Same Effect Stack Rule SpellGroups to the accumulator
4750 for (auto itr = sameEffectSpellGroup.begin(); itr != sameEffectSpellGroup.end(); ++itr)
4751 modifier += itr->second;
4752
4753 return modifier;
4754}
4755
4756float Unit::GetTotalAuraMultiplier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4757{
4758 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4759 if (mTotalAuraList.empty())
4760 return 1.0f;
4761
4762 std::map<SpellGroup, int32> sameEffectSpellGroup;
4763 float multiplier = 1.0f;
4764
4765 for (AuraEffect const* aurEff : mTotalAuraList)
4766 {
4767 if (predicate(aurEff))
4768 {
4769 // Check if the Aura Effect has a the Same Effect Stack Rule and if so, use the highest amount of that SpellGroup
4770 // If the Aura Effect does not have this Stack Rule, it returns false so we can add to the multiplier as usual
4771 if (!sSpellMgr->AddSameEffectStackRuleSpellGroups(aurEff->GetSpellInfo(), static_cast<uint32>(auraType), aurEff->GetAmount(), sameEffectSpellGroup))
4772 AddPct(multiplier, aurEff->GetAmount());
4773 }
4774 }
4775
4776 // Add the highest of the Same Effect Stack Rule SpellGroups to the multiplier
4777 for (auto itr = sameEffectSpellGroup.begin(); itr != sameEffectSpellGroup.end(); ++itr)
4778 AddPct(multiplier, itr->second);
4779
4780 return multiplier;
4781}
4782
4783int32 Unit::GetMaxPositiveAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4784{
4785 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4786 if (mTotalAuraList.empty())
4787 return 0;
4788
4789 int32 modifier = 0;
4790 for (AuraEffect const* aurEff : mTotalAuraList)
4791 {
4792 if (predicate(aurEff))
4793 modifier = std::max(modifier, aurEff->GetAmount());
4794 }
4795
4796 return modifier;
4797}
4798
4799int32 Unit::GetMaxNegativeAuraModifier(AuraType auraType, std::function<bool(AuraEffect const*)> const& predicate) const
4800{
4801 AuraEffectList const& mTotalAuraList = GetAuraEffectsByType(auraType);
4802 if (mTotalAuraList.empty())
4803 return 0;
4804
4805 int32 modifier = 0;
4806 for (AuraEffect const* aurEff : mTotalAuraList)
4807 {
4808 if (predicate(aurEff))
4809 modifier = std::min(modifier, aurEff->GetAmount());
4810 }
4811
4812 return modifier;
4813}
4814
4816{
4817 return GetTotalAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
4818}
4819
4821{
4822 return GetTotalAuraMultiplier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
4823}
4824
4826{
4827 return GetMaxPositiveAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
4828}
4829
4831{
4832 return GetMaxNegativeAuraModifier(auraType, [](AuraEffect const* /*aurEff*/) { return true; });
4833}
4834
4836{
4837 return GetTotalAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
4838 {
4839 if ((aurEff->GetMiscValue() & miscMask) != 0)
4840 return true;
4841 return false;
4842 });
4843}
4844
4846{
4847 return GetTotalAuraMultiplier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
4848 {
4849 if ((aurEff->GetMiscValue() & miscMask) != 0)
4850 return true;
4851 return false;
4852 });
4853}
4854
4855int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auraType, uint32 miscMask, AuraEffect const* except /*= nullptr*/) const
4856{
4857 return GetMaxPositiveAuraModifier(auraType, [miscMask, except](AuraEffect const* aurEff) -> bool
4858 {
4859 if (except != aurEff && (aurEff->GetMiscValue() & miscMask) != 0)
4860 return true;
4861 return false;
4862 });
4863}
4864
4866{
4867 return GetMaxNegativeAuraModifier(auraType, [miscMask](AuraEffect const* aurEff) -> bool
4868 {
4869 if ((aurEff->GetMiscValue() & miscMask) != 0)
4870 return true;
4871 return false;
4872 });
4873}
4874
4876{
4877 return GetTotalAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
4878 {
4879 if (aurEff->GetMiscValue() == miscValue)
4880 return true;
4881 return false;
4882 });
4883}
4884
4886{
4887 return GetTotalAuraMultiplier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
4888 {
4889 if (aurEff->GetMiscValue() == miscValue)
4890 return true;
4891 return false;
4892 });
4893}
4894
4896{
4897 return GetMaxPositiveAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
4898 {
4899 if (aurEff->GetMiscValue() == miscValue)
4900 return true;
4901 return false;
4902 });
4903}
4904
4906{
4907 return GetMaxNegativeAuraModifier(auraType, [miscValue](AuraEffect const* aurEff) -> bool
4908 {
4909 if (aurEff->GetMiscValue() == miscValue)
4910 return true;
4911 return false;
4912 });
4913}
4914
4916{
4917 return GetTotalAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
4918 {
4919 if (aurEff->IsAffectingSpell(affectedSpell))
4920 return true;
4921 return false;
4922 });
4923}
4924
4925float Unit::GetTotalAuraMultiplierByAffectMask(AuraType auraType, SpellInfo const* affectedSpell) const
4926{
4927 return GetTotalAuraMultiplier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
4928 {
4929 if (aurEff->IsAffectingSpell(affectedSpell))
4930 return true;
4931 return false;
4932 });
4933}
4934
4936{
4937 return GetMaxPositiveAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
4938 {
4939 if (aurEff->IsAffectingSpell(affectedSpell))
4940 return true;
4941 return false;
4942 });
4943}
4944
4946{
4947 return GetMaxNegativeAuraModifier(auraType, [affectedSpell](AuraEffect const* aurEff) -> bool
4948 {
4949 if (aurEff->IsAffectingSpell(affectedSpell))
4950 return true;
4951 return false;
4952 });
4953}
4954
4956{
4957 float modPos = 0.0f;
4958 float modNeg = 0.0f;
4959
4960 // these auras are always positive
4962 modPos += GetTotalAuraModifier(SPELL_AURA_MOD_RESISTANCE, [school](AuraEffect const* aurEff) -> bool
4963 {
4964 if ((aurEff->GetMiscValue() & (1 << school)) && aurEff->GetAmount() > 0)
4965 return true;
4966 return false;
4967 });
4968
4969 modNeg = GetTotalAuraModifier(SPELL_AURA_MOD_RESISTANCE, [school](AuraEffect const* aurEff) -> bool
4970 {
4971 if ((aurEff->GetMiscValue() & (1 << school)) && aurEff->GetAmount() < 0)
4972 return true;
4973 return false;
4974 });
4975
4977 modPos *= factor;
4978 modNeg *= factor;
4979
4982}
4983
4985{
4986 for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
4988 for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
4990}
4991
4993{
4994 float modPos = 0.0f;
4995 float modNeg = 0.0f;
4996 float factor = 0.0f;
4997
4998 UnitMods const unitMod = static_cast<UnitMods>(UNIT_MOD_STAT_START + AsUnderlyingType(stat));
4999
5000 // includes value from items and enchantments
5001 float modValue = GetFlatModifierValue(unitMod, BASE_VALUE);
5002 if (modValue > 0.f)
5003 modPos += modValue;
5004 else
5005 modNeg += modValue;
5006
5007 if (IsGuardian())
5008 {
5009 modValue = static_cast<Guardian*>(this)->GetBonusStatFromOwner(stat);
5010 if (modValue > 0.f)
5011 modPos += modValue;
5012 else
5013 modNeg += modValue;
5014 }
5015
5016 modPos += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
5017 {
5018 if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() > 0)
5019 return true;
5020 return false;
5021 });
5022
5023 modNeg += GetTotalAuraModifier(SPELL_AURA_MOD_STAT, [stat](AuraEffect const* aurEff) -> bool
5024 {
5025 if ((aurEff->GetMiscValue() < 0 || aurEff->GetMiscValue() == stat) && aurEff->GetAmount() < 0)
5026 return true;
5027 return false;
5028 });
5029
5030 factor = GetTotalAuraMultiplier(SPELL_AURA_MOD_PERCENT_STAT, [stat](AuraEffect const* aurEff) -> bool
5031 {
5032 if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat)
5033 return true;
5034 return false;
5035 });
5036
5037 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE, [stat](AuraEffect const* aurEff) -> bool
5038 {
5039 if (aurEff->GetMiscValue() == -1 || aurEff->GetMiscValue() == stat)
5040 return true;
5041 return false;
5042 });
5043
5044 modPos *= factor;
5045 modNeg *= factor;
5046
5049}
5050
5052{
5053 m_dynObj.push_back(dynObj);
5054}
5055
5057{
5058 m_dynObj.remove(dynObj);
5059}
5060
5062{
5063 std::vector<DynamicObject*> dynamicobjects = GetDynObjects(spellId);
5064 return dynamicobjects.empty() ? nullptr : dynamicobjects.front();
5065}
5066
5067std::vector<DynamicObject*> Unit::GetDynObjects(uint32 spellId) const
5068{
5069 std::vector<DynamicObject*> dynamicobjects;
5070 for (DynObjectList::const_iterator i = m_dynObj.begin(); i != m_dynObj.end(); ++i)
5071 if ((*i)->GetSpellId() == spellId)
5072 dynamicobjects.push_back(*i);
5073
5074 return dynamicobjects;
5075}
5076
5078{
5079 if (m_dynObj.empty())
5080 return;
5081 for (DynObjectList::iterator i = m_dynObj.begin(); i != m_dynObj.end();)
5082 {
5083 DynamicObject* dynObj = *i;
5084 if (dynObj->GetSpellId() == spellId)
5085 {
5086 dynObj->Remove();
5087 i = m_dynObj.begin();
5088 }
5089 else
5090 ++i;
5091 }
5092}
5093
5095{
5096 while (!m_dynObj.empty())
5097 m_dynObj.front()->Remove();
5098}
5099
5101{
5102 std::vector<GameObject*> gameobjects = GetGameObjects(spellId);
5103 return gameobjects.empty() ? nullptr : gameobjects.front();
5104}
5105
5106std::vector<GameObject*> Unit::GetGameObjects(uint32 spellId) const
5107{
5108 std::vector<GameObject*> gameobjects;
5109 for (GameObjectList::const_iterator i = m_gameObj.begin(); i != m_gameObj.end(); ++i)
5110 if ((*i)->GetSpellId() == spellId)
5111 gameobjects.push_back(*i);
5112
5113 return gameobjects;
5114}
5115
5117{
5118 if (!gameObj || !gameObj->GetOwnerGUID().IsEmpty())
5119 return;
5120
5121 m_gameObj.push_back(gameObj);
5122 gameObj->SetOwnerGUID(GetGUID());
5123
5124 if (gameObj->GetSpellId())
5125 {
5126 SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(gameObj->GetSpellId());
5127 // Need disable spell use for owner
5128 if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
5129 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
5130 GetSpellHistory()->StartCooldown(createBySpell, 0, nullptr, true);
5131 }
5132}
5133
5135{
5137
5138 auto objectSlotItr = std::ranges::find(m_ObjectSlot, gameObj->GetGUID());
5139 if (objectSlotItr != std::ranges::end(m_ObjectSlot))
5140 objectSlotItr->Clear();
5141
5142 // GO created by some spell
5143 if (uint32 spellid = gameObj->GetSpellId())
5144 {
5145 RemoveAurasDueToSpell(spellid);
5146
5147 SpellInfo const* createBySpell = sSpellMgr->GetSpellInfo(spellid);
5148 // Need activate spell use for owner
5149 if (createBySpell && createBySpell->IsCooldownStartedOnEvent())
5150 // note: item based cooldowns and cooldown spell mods with charges ignored (unknown existing cases)
5151 GetSpellHistory()->SendCooldownEvent(createBySpell);
5152 }
5153
5154 if (del)
5155 {
5156 gameObj->SetRespawnTime(0);
5157 gameObj->Delete();
5158 }
5159}
5160
5161void Unit::RemoveGameObject(GameObject* gameObj, bool del)
5162{
5163 if (!gameObj || gameObj->GetOwnerGUID() != GetGUID())
5164 return;
5165
5166 RemoveGameObjectImpl(gameObj, del);
5167
5168 m_gameObj.remove(gameObj);
5169}
5170
5171void Unit::RemoveGameObject(uint32 spellid, bool del)
5172{
5173 if (m_gameObj.empty())
5174 return;
5175
5176 for (auto i = m_gameObj.begin(); i != m_gameObj.end(); )
5177 {
5178 if (spellid == 0 || (*i)->GetSpellId() == spellid)
5179 {
5180 RemoveGameObjectImpl(*i, del);
5181 i = m_gameObj.erase(i);
5182 }
5183 else
5184 ++i;
5185 }
5186}
5187
5189{
5190 // remove references to unit
5191 while (!m_gameObj.empty())
5192 {
5193 GameObject* gameObj = m_gameObj.front();
5194 m_gameObj.pop_front();
5195 RemoveGameObjectImpl(gameObj, true);
5196 }
5197}
5198
5200{
5202 packet.Me = log->target->GetGUID();
5203 packet.CasterGUID = Object::GetGUID(log->attacker);
5204 packet.SpellID = log->SpellID;
5205 packet.Damage = log->damage;
5206 if (log->damage > log->target->GetHealth())
5207 packet.Overkill = log->damage - log->target->GetHealth();
5208
5209 packet.SchoolMask = log->schoolMask;
5210 packet.Absorbed = log->absorb;
5211 packet.Resisted = log->resist;
5212 packet.ShieldBlock = log->blocked;
5213 packet.Periodic = log->periodicLog;
5214 packet.Flags = log->HitInfo;
5215 SendMessageToSet(packet.Write(), true);
5216}
5217
5218/*static*/ void Unit::ProcSkillsAndAuras(Unit* actor, Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
5219{
5220 WeaponAttackType attType = damageInfo ? damageInfo->GetAttackType() : BASE_ATTACK;
5221 if (typeMaskActor && actor)
5222 actor->ProcSkillsAndReactives(false, actionTarget, typeMaskActor, hitMask, attType);
5223
5224 if (typeMaskActionTarget && actionTarget)
5225 actionTarget->ProcSkillsAndReactives(true, actor, typeMaskActionTarget, hitMask, attType);
5226
5227 if (actor)
5228 actor->TriggerAurasProcOnEvent(actionTarget, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
5229}
5230
5232{
5233 AuraEffect const* aura = pInfo->auraEff;
5234
5236 data << GetPackGUID();
5237 data << aura->GetCasterGUID().WriteAsPacked();
5238 data << uint32(aura->GetId()); // spellId
5239 data << uint32(1); // count
5240 data << uint32(aura->GetAuraType()); // auraId
5241 switch (aura->GetAuraType())
5242 {
5245 data << uint32(pInfo->damage); // damage
5246 data << uint32(pInfo->overDamage); // overkill?
5247 data << uint32(aura->GetSpellInfo()->GetSchoolMask());
5248 data << uint32(pInfo->absorb); // absorb
5249 data << uint32(pInfo->resist); // resist
5250 data << uint8(pInfo->critical); // new 3.1.2 critical tick
5251 break;
5254 data << uint32(pInfo->damage); // damage
5255 data << uint32(pInfo->overDamage); // overheal
5256 data << uint32(pInfo->absorb); // absorb
5257 data << uint8(pInfo->critical); // new 3.1.2 critical tick
5258 break;
5261 data << uint32(aura->GetMiscValue()); // power type
5262 data << uint32(pInfo->damage); // damage
5263 break;
5265 data << uint32(aura->GetMiscValue()); // power type
5266 data << uint32(pInfo->damage); // amount
5267 data << float(pInfo->multiplier); // gain multiplier
5268 break;
5269 default:
5270 TC_LOG_ERROR("entities.unit", "Unit::SendPeriodicAuraLog: unknown aura {}", uint32(aura->GetAuraType()));
5271 return;
5272 }
5273
5274 SendMessageToSet(&data, true);
5275}
5276
5278{
5279 WorldPacket data(SMSG_PROCRESIST, 8+8+4+1);
5280 data << GetGUID();
5281 data << target->GetGUID();
5282 data << uint32(spellId);
5283 data << uint8(0); // bool - log format: 0-default, 1-debug
5284 SendMessageToSet(&data, true);
5285}
5286
5288{
5290 data << GetGUID();
5291 data << target->GetGUID();
5292 data << uint32(spellId);
5293 data << uint8(0); // bool - log format: 0-default, 1-debug
5294 SendMessageToSet(&data, true);
5295}
5296
5298{
5300 packet.Flags = damageInfo->HitInfo;
5301 packet.AttackerGUID = damageInfo->Attacker->GetGUID();
5302 packet.VictimGUID = damageInfo->Target->GetGUID();
5303 packet.Damage = damageInfo->Damages[0].Damage + damageInfo->Damages[1].Damage;
5304 int32 overkill = damageInfo->Damages[0].Damage + damageInfo->Damages[1].Damage - damageInfo->Target->GetHealth();
5305 packet.OverDamage = (overkill < 0 ? 0 : overkill);
5306
5307 for (std::size_t i = 0; i < packet.SubDmg.size(); ++i)
5308 {
5309 WorldPackets::CombatLog::SubDamage& subDmg = packet.SubDmg[i];
5310 subDmg.SchoolMask = damageInfo->Damages[i].DamageSchoolMask; // School of sub damage
5311 subDmg.FDamage = damageInfo->Damages[i].Damage; // sub damage
5312 subDmg.Damage = damageInfo->Damages[i].Damage; // Sub Damage
5313 subDmg.Absorbed = damageInfo->Damages[i].Absorb; // Absorb
5314 subDmg.Resisted = damageInfo->Damages[i].Resist; // Resist
5315 }
5316
5317 packet.VictimState = damageInfo->TargetState;
5318 packet.BlockAmount = damageInfo->Blocked;
5319 packet.RageGained = 0;
5320
5321 packet.SubDmgCount = 1;
5322 if (damageInfo->Damages[1].Damage || damageInfo->Damages[1].Absorb || damageInfo->Damages[1].Resist)
5323 ++packet.SubDmgCount;
5324
5325 SendMessageToSet(packet.Write(), true);
5326}
5327
5328void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit* target, uint8 /*SwingType*/, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount)
5329{
5330 CalcDamageInfo dmgInfo;
5331 dmgInfo.HitInfo = HitInfo;
5332 dmgInfo.Attacker = this;
5333 dmgInfo.Target = target;
5334
5335 dmgInfo.Damages[0].Damage = Damage - AbsorbDamage - Resist - BlockedAmount;
5336 dmgInfo.Damages[0].DamageSchoolMask = damageSchoolMask;
5337 dmgInfo.Damages[0].Absorb = AbsorbDamage;
5338 dmgInfo.Damages[0].Resist = Resist;
5339
5340 dmgInfo.Damages[1].Damage = 0;
5341 dmgInfo.Damages[1].DamageSchoolMask = 0;
5342 dmgInfo.Damages[1].Absorb = 0;
5343 dmgInfo.Damages[1].Resist = 0;
5344
5345 dmgInfo.TargetState = TargetState;
5346 dmgInfo.Blocked = BlockedAmount;
5347 SendAttackStateUpdate(&dmgInfo);
5348}
5349
5350void Unit::SetPowerType(Powers new_powertype, bool sendUpdate/* = true*/)
5351{
5352 if (GetPowerType() == new_powertype)
5353 return;
5354
5356
5357 if (!sendUpdate)
5358 return;
5359
5360 if (GetTypeId() == TYPEID_PLAYER)
5361 {
5362 if (ToPlayer()->GetGroup())
5364 }
5365 else if (Pet* pet = ToCreature()->ToPet())
5366 {
5367 if (pet->isControlled())
5368 {
5369 Unit* owner = GetOwner();
5370 if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
5372 }
5373 }
5374
5375 // Update max power
5376 UpdateMaxPower(new_powertype);
5377
5378 // Update current power
5379 switch (new_powertype)
5380 {
5381 case POWER_MANA: // Keep the same (druid form switching...)
5382 case POWER_ENERGY:
5383 break;
5384 case POWER_RAGE: // Reset to zero
5385 SetPower(POWER_RAGE, 0);
5386 break;
5387 case POWER_FOCUS: // Make it full
5388 SetFullPower(new_powertype);
5389 break;
5390 default:
5391 break;
5392 }
5393}
5394
5396{
5397 Powers displayPower = POWER_MANA;
5398 switch (GetShapeshiftForm())
5399 {
5400 case FORM_GHOUL:
5401 case FORM_CAT:
5402 displayPower = POWER_ENERGY;
5403 break;
5404 case FORM_BEAR:
5405 case FORM_DIREBEAR:
5406 displayPower = POWER_RAGE;
5407 break;
5408 case FORM_TRAVEL:
5409 case FORM_GHOSTWOLF:
5410 displayPower = POWER_MANA;
5411 break;
5412 default:
5413 {
5414 if (GetTypeId() == TYPEID_PLAYER)
5415 {
5416 ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(GetClass());
5417 if (cEntry && cEntry->DisplayPower < MAX_POWERS)
5418 displayPower = Powers(cEntry->DisplayPower);
5419 }
5420 else if (GetTypeId() == TYPEID_UNIT)
5421 {
5422 if (Vehicle* vehicle = GetVehicleKit())
5423 {
5424 if (PowerDisplayEntry const* powerDisplay = sPowerDisplayStore.LookupEntry(vehicle->GetVehicleInfo()->PowerDisplayID))
5425 displayPower = Powers(powerDisplay->ActualType);
5426 else if (GetClass() == CLASS_ROGUE)
5427 displayPower = POWER_ENERGY;
5428 }
5429 else if (Pet* pet = ToPet())
5430 {
5431 if (pet->getPetType() == HUNTER_PET) // Hunter pets have focus
5432 displayPower = POWER_FOCUS;
5433 else if (pet->IsPetGhoul() || pet->IsRisenAlly()) // DK pets have energy
5434 displayPower = POWER_ENERGY;
5435 }
5436 }
5437 break;
5438 }
5439 }
5440
5441 SetPowerType(displayPower);
5442}
5443
5444void Unit::_addAttacker(Unit* pAttacker)
5445{
5446 m_attackers.insert(pAttacker);
5447}
5448
5450{
5451 m_attackers.erase(pAttacker);
5452}
5453
5454Unit* Unit::getAttackerForHelper() const // If someone wants to help, who to give them
5455{
5456 if (!IsEngaged())
5457 return nullptr;
5458
5459 if (Unit* victim = GetVictim())
5460 if ((!IsPet() && !IsCharmerOrSelfPlayer()) || IsInCombatWith(victim))
5461 return victim;
5462
5463 CombatManager const& mgr = GetCombatManager();
5464 // pick arbitrary targets; our pvp combat > owner's pvp combat > our pve combat > owner's pve combat
5465 Unit* owner = GetCharmerOrOwner();
5466 if (mgr.HasPvPCombat())
5467 return mgr.GetPvPCombatRefs().begin()->second->GetOther(this);
5468 if (owner && (owner->GetCombatManager().HasPvPCombat()))
5469 return owner->GetCombatManager().GetPvPCombatRefs().begin()->second->GetOther(owner);
5470 if (mgr.HasPvECombat())
5471 return mgr.GetPvECombatRefs().begin()->second->GetOther(this);
5472 if (owner && (owner->GetCombatManager().HasPvECombat()))
5473 return owner->GetCombatManager().GetPvECombatRefs().begin()->second->GetOther(owner);
5474 return nullptr;
5475}
5476
5477bool Unit::Attack(Unit* victim, bool meleeAttack)
5478{
5479 if (!victim || victim == this)
5480 return false;
5481
5482 // dead units can neither attack nor be attacked
5483 if (!IsAlive() || !victim->IsInWorld() || !victim->IsAlive())
5484 return false;
5485
5486 // player cannot attack in mount state
5487 if (GetTypeId() == TYPEID_PLAYER && IsMounted())
5488 return false;
5489
5490 Creature* creature = ToCreature();
5491 // creatures cannot attack while evading
5492 if (creature && creature->IsInEvadeMode())
5493 return false;
5494
5495 // nobody can attack GM in GM-mode
5496 if (victim->GetTypeId() == TYPEID_PLAYER)
5497 {
5498 if (victim->ToPlayer()->IsGameMaster())
5499 return false;
5500 }
5501 else
5502 {
5503 if (victim->ToCreature()->IsEvadingAttacks())
5504 return false;
5505 }
5506
5507 // remove SPELL_AURA_MOD_UNATTACKABLE at attack (in case non-interruptible spells stun aura applied also that not let attack)
5510
5511 if (m_attacking)
5512 {
5513 if (m_attacking == victim)
5514 {
5515 // switch to melee attack from ranged/magic
5516 if (meleeAttack)
5517 {
5519 {
5521 SendMeleeAttackStart(victim);
5522 return true;
5523 }
5524 }
5526 {
5528 SendMeleeAttackStop(victim);
5529 return true;
5530 }
5531 return false;
5532 }
5533
5534 // switch target
5536 if (!meleeAttack)
5538 }
5539
5540 if (m_attacking)
5542
5543 m_attacking = victim;
5545
5546 // Set our target
5547 SetTarget(victim->GetGUID());
5548
5549 if (meleeAttack)
5551
5552 // set position before any AI calls/assistance
5553 //if (GetTypeId() == TYPEID_UNIT)
5554 // ToCreature()->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
5555
5556 if (creature && !IsControlledByPlayer())
5557 {
5558 EngageWithTarget(victim); // ensure that anything we're attacking has threat
5559
5561 creature->CallAssistance();
5562
5563 // Remove emote state - will be restored on creature reset
5565 }
5566
5567 // delay offhand weapon attack by 50% of the base attack time
5570
5571 if (meleeAttack)
5572 SendMeleeAttackStart(victim);
5573
5574 // Let the pet know we've started attacking someting. Handles melee attacks only
5575 // Spells such as auto-shot and others handled in WorldSession::HandleCastSpellOpcode
5576 if (GetTypeId() == TYPEID_PLAYER)
5577 {
5578 for (Unit* controlled : m_Controlled)
5579 if (Creature* cControlled = controlled->ToCreature())
5580 if (CreatureAI* controlledAI = cControlled->AI())
5581 controlledAI->OwnerAttacked(victim);
5582 }
5583
5584 return true;
5585}
5586
5588{
5589 if (!m_attacking)
5590 return false;
5591
5592 Unit* victim = m_attacking;
5593
5595 m_attacking = nullptr;
5596
5597 // Clear our target
5599
5601
5603
5604 // reset only at real combat stop
5605 if (Creature* creature = ToCreature())
5606 {
5607 creature->SetNoCallAssistance(false);
5608 }
5609
5610 SendMeleeAttackStop(victim);
5611
5612 return true;
5613}
5614
5616{
5617 // iterate attackers
5618 UnitVector toRemove;
5619 AttackerSet const& attackers = getAttackers();
5620 for (Unit* attacker : attackers)
5621 if (!attacker->IsValidAttackTarget(this))
5622 toRemove.push_back(attacker);
5623
5624 for (Unit* attacker : toRemove)
5625 attacker->AttackStop();
5626
5627 // remove our own victim
5628 if (Unit* victim = GetVictim())
5629 if (!IsValidAttackTarget(victim))
5630 AttackStop();
5631}
5632
5633void Unit::CombatStop(bool includingCast, bool mutualPvP)
5634{
5635 if (includingCast && IsNonMeleeSpellCast(false))
5637
5638 AttackStop();
5640 if (GetTypeId() == TYPEID_PLAYER)
5641 ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
5642
5643 if (mutualPvP)
5644 ClearInCombat();
5645 else
5646 { // vanish and brethren are weird
5649 }
5650}
5651
5652void Unit::CombatStopWithPets(bool includingCast)
5653{
5654 CombatStop(includingCast);
5655
5656 for (Unit* minion : m_Controlled)
5657 minion->CombatStop(includingCast);
5658}
5659
5661{
5663 return true;
5664
5665 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
5666 if ((*itr)->isAttackingPlayer())
5667 return true;
5668
5669 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
5670 if (!m_SummonSlot[i].IsEmpty())
5671 if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
5672 if (summon->isAttackingPlayer())
5673 return true;
5674
5675 return false;
5676}
5677
5679{
5680 while (!m_attackers.empty())
5681 {
5682 AttackerSet::iterator iter = m_attackers.begin();
5683 if (!(*iter)->AttackStop())
5684 {
5685 TC_LOG_ERROR("entities.unit", "WORLD: Unit has an attacker that isn't attacking it!");
5686 m_attackers.erase(iter);
5687 }
5688 }
5689}
5690
5692{
5693 if (apply)
5694 {
5695 if (!HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)))
5696 {
5697 SetFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
5698 if (GetTypeId() == TYPEID_PLAYER)
5699 {
5700 PlayerSpellMap const& sp_list = ToPlayer()->GetSpellMap();
5701 for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
5702 {
5703 if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
5704 continue;
5705 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
5706 if (!spellInfo || !spellInfo->IsPassive())
5707 continue;
5708 if (spellInfo->CasterAuraState == uint32(flag))
5709 CastSpell(this, itr->first, true);
5710 }
5711 }
5712 else if (Pet* pet = ToCreature()->ToPet())
5713 {
5714 for (PetSpellMap::const_iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
5715 {
5716 if (itr->second.state == PETSPELL_REMOVED)
5717 continue;
5718 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
5719 if (!spellInfo || !spellInfo->IsPassive())
5720 continue;
5721 if (spellInfo->CasterAuraState == uint32(flag))
5722 CastSpell(this, itr->first, true);
5723 }
5724 }
5725 }
5726 }
5727 else
5728 {
5729 if (HasFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1)))
5730 {
5731 RemoveFlag(UNIT_FIELD_AURASTATE, 1<<(flag-1));
5732
5734 for (Unit::AuraApplicationMap::iterator itr = tAuras.begin(); itr != tAuras.end();)
5735 {
5736 SpellInfo const* spellProto = itr->second->GetBase()->GetSpellInfo();
5737 if (itr->second->GetBase()->GetCasterGUID() == GetGUID() && spellProto->CasterAuraState == uint32(flag) && (spellProto->IsPassive() || flag != AURA_STATE_ENRAGE))
5738 RemoveAura(itr);
5739 else
5740 ++itr;
5741 }
5742 }
5743 }
5744}
5745
5747{
5749 for (AuraStateAurasMap::const_iterator itr = m_auraStateAuras.begin(); itr != m_auraStateAuras.end(); ++itr)
5750 if ((1 << (itr->first - 1)) & PER_CASTER_AURA_STATE_MASK)
5751 if (itr->second->GetBase()->GetCasterGUID() == target->GetGUID())
5752 auraStates |= (1 << (itr->first - 1));
5753
5754 return auraStates;
5755}
5756
5757bool Unit::HasAuraState(AuraStateType flag, SpellInfo const* spellProto, Unit const* Caster) const
5758{
5759 if (Caster)
5760 {
5761 if (spellProto)
5762 {
5764 return true;
5765 }
5766
5767 // Check per caster aura state
5768 // If aura with aurastate by caster not found return false
5769 if ((1 << (flag - 1)) & PER_CASTER_AURA_STATE_MASK)
5770 {
5771 AuraStateAurasMapBounds range = m_auraStateAuras.equal_range(flag);
5772 for (AuraStateAurasMap::const_iterator itr = range.first; itr != range.second; ++itr)
5773 if (itr->second->GetBase()->GetCasterGUID() == Caster->GetGUID())
5774 return true;
5775 return false;
5776 }
5777 }
5778
5779 return HasFlag(UNIT_FIELD_AURASTATE, 1 << (flag - 1));
5780}
5781
5783{
5784 if (GetOwnerGUID() == owner)
5785 return;
5786
5788 if (!owner)
5789 return;
5790
5791 // Update owner dependent fields
5792 Player* player = ObjectAccessor::GetPlayer(*this, owner);
5793 if (!player || !player->HaveAtClient(this)) // if player cannot see this unit yet, he will receive needed data with create object
5794 return;
5795
5797
5798 UpdateData udata;
5799 WorldPacket packet;
5800 BuildValuesUpdateBlockForPlayer(&udata, player);
5801 udata.BuildPacket(&packet);
5802 player->SendDirectMessage(&packet);
5803
5805}
5806
5808{
5810 if (!guid.IsEmpty())
5811 {
5812 if (Unit* master = ObjectAccessor::GetUnit(*this, guid))
5813 return master->GetControllingPlayer();
5814 return nullptr;
5815 }
5816 else
5817 return const_cast<Player*>(ToPlayer());
5818}
5819
5821{
5822 ObjectGuid pet_guid = GetMinionGUID();
5823 if (!pet_guid.IsEmpty())
5824 {
5825 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
5826 if (pet->HasUnitTypeMask(UNIT_MASK_MINION))
5827 return (Minion*)pet;
5828
5829 TC_LOG_ERROR("entities.unit", "Unit::GetFirstMinion: Minion {} not exist.", pet_guid.ToString());
5830 const_cast<Unit*>(this)->SetMinionGUID(ObjectGuid::Empty);
5831 }
5832
5833 return nullptr;
5834}
5835
5837{
5838 ObjectGuid pet_guid = GetPetGUID();
5839 if (!pet_guid.IsEmpty())
5840 {
5841 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, pet_guid))
5842 if (pet->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
5843 return (Guardian*)pet;
5844
5845 TC_LOG_FATAL("entities.unit", "Unit::GetGuardianPet: Guardian {} not exist.", pet_guid.ToString());
5846 const_cast<Unit*>(this)->SetPetGUID(ObjectGuid::Empty);
5847 }
5848
5849 return nullptr;
5850}
5851
5852void Unit::SetMinion(Minion *minion, bool apply)
5853{
5854 TC_LOG_DEBUG("entities.unit", "SetMinion {} for {}, apply {}", minion->GetEntry(), GetEntry(), apply);
5855
5856 if (apply)
5857 {
5858 if (!minion->GetOwnerGUID().IsEmpty())
5859 {
5860 TC_LOG_FATAL("entities.unit", "SetMinion: Minion {} is not the minion of owner {}", minion->GetEntry(), GetEntry());
5861 return;
5862 }
5863
5864 if (!IsInWorld())
5865 {
5866 TC_LOG_FATAL("entities.unit", "SetMinion: Minion being added to owner not in world. Minion: {}, Owner: {}", minion->GetGUID().ToString(), GetDebugInfo());
5867 return;
5868 }
5869
5870 minion->SetOwnerGUID(GetGUID());
5871
5872 m_Controlled.insert(minion);
5873
5874 if (GetTypeId() == TYPEID_PLAYER)
5875 {
5876 minion->m_ControlledByPlayer = true;
5878 }
5879
5880 // Can only have one pet. If a new one is summoned, dismiss the old one.
5881 if (minion->IsGuardianPet())
5882 {
5883 if (Guardian* oldPet = GetGuardianPet())
5884 {
5885 if (oldPet != minion && (oldPet->IsPet() || minion->IsPet() || oldPet->GetEntry() != minion->GetEntry()))
5886 {
5887 // remove existing minion pet
5888 if (Pet* oldPetAsPet = oldPet->ToPet())
5889 oldPetAsPet->Remove(PET_SAVE_NOT_IN_SLOT);
5890 else
5891 oldPet->UnSummon();
5892 SetPetGUID(minion->GetGUID());
5894 }
5895 }
5896 else
5897 {
5898 SetPetGUID(minion->GetGUID());
5900 }
5901 }
5902
5905
5906 if (minion->m_Properties && minion->m_Properties->Title == SUMMON_TYPE_MINIPET)
5907 SetCritterGUID(minion->GetGUID());
5908
5909 // PvP, FFAPvP
5911
5912 // FIXME: hack, speed must be set only at follow
5913 if (GetTypeId() == TYPEID_PLAYER && minion->IsPet())
5914 for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i)
5915 minion->SetSpeedRate(UnitMoveType(i), m_speed_rate[i]);
5916
5917 // Send infinity cooldown - client does that automatically but after relog cooldown needs to be set again
5918 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
5919 if (spellInfo && spellInfo->IsCooldownStartedOnEvent())
5920 GetSpellHistory()->StartCooldown(spellInfo, 0, nullptr, true);
5921 }
5922 else
5923 {
5924 if (minion->GetOwnerGUID() != GetGUID())
5925 {
5926 TC_LOG_FATAL("entities.unit", "SetMinion: Minion {} is not the minion of owner {}", minion->GetEntry(), GetEntry());
5927 return;
5928 }
5929
5930 m_Controlled.erase(minion);
5931
5932 if (minion->m_Properties && minion->m_Properties->Title == SUMMON_TYPE_MINIPET)
5933 if (GetCritterGUID() == minion->GetGUID())
5935
5936 if (minion->IsGuardianPet())
5937 {
5938 if (GetPetGUID() == minion->GetGUID())
5940 }
5941 else if (minion->IsTotem())
5942 {
5943 // All summoned by totem minions must disappear when it is removed.
5944 if (SpellInfo const* spInfo = sSpellMgr->GetSpellInfo(minion->ToTotem()->GetSpell()))
5945 {
5946 for (SpellEffectInfo const& spellEffectInfo : spInfo->GetEffects())
5947 {
5948 if (!spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON))
5949 continue;
5950
5951 RemoveAllMinionsByEntry(spellEffectInfo.MiscValue);
5952 }
5953 }
5954 }
5955
5956 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(minion->GetUInt32Value(UNIT_CREATED_BY_SPELL));
5957 // Remove infinity cooldown
5958 if (spellInfo && (spellInfo->IsCooldownStartedOnEvent()))
5959 GetSpellHistory()->SendCooldownEvent(spellInfo);
5960
5961 //if (minion->HasUnitTypeMask(UNIT_MASK_GUARDIAN))
5962 {
5964 {
5965 // Check if there is another minion
5966 for (ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
5967 {
5968 // do not use this check, creature do not have charm guid
5969 //if (GetCharmedGUID() == (*itr)->GetGUID())
5970 if (GetGUID() == (*itr)->GetCharmerGUID())
5971 continue;
5972
5973 //ASSERT((*itr)->GetOwnerGUID() == GetGUID());
5974 if ((*itr)->GetOwnerGUID() != GetGUID())
5975 {
5976 OutDebugInfo();
5977 (*itr)->OutDebugInfo();
5978 ABORT();
5979 }
5980 ASSERT((*itr)->GetTypeId() == TYPEID_UNIT);
5981
5982 if (!(*itr)->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN))
5983 continue;
5984
5985 if (AddGuidValue(UNIT_FIELD_SUMMON, (*itr)->GetGUID()))
5986 {
5987 // show another pet bar if there is no charm bar
5988 if (GetTypeId() == TYPEID_PLAYER && !GetCharmedGUID())
5989 {
5990 if ((*itr)->IsPet())
5992 else
5994 }
5995 }
5996 break;
5997 }
5998 }
5999 }
6000 }
6002}
6003
6004void Unit::GetAllMinionsByEntry(std::list<TempSummon*>& Minions, uint32 entry)
6005{
6006 for (Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
6007 {
6008 Unit* unit = *itr;
6009 if (unit->GetEntry() == entry && unit->IsSummon()) // minion, actually
6010 Minions.push_back(unit->ToTempSummon());
6011 }
6012}
6013
6015{
6016 for (Unit::ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end();)
6017 {
6018 Unit* unit = *itr;
6019 ++itr;
6020 if (unit->GetEntry() == entry && unit->GetTypeId() == TYPEID_UNIT
6021 && unit->IsSummon()) // minion, actually
6022 unit->ToTempSummon()->UnSummon();
6023 // i think this is safe because i have never heard that a despawned minion will trigger a same minion
6024 }
6025}
6026
6027void Unit::SetCharm(Unit* charm, bool apply)
6028{
6029 if (apply)
6030 {
6031 if (GetTypeId() == TYPEID_PLAYER)
6032 {
6034 "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());
6035 m_charmed = charm;
6036
6037 charm->m_ControlledByPlayer = true;
6040 }
6041 else
6042 charm->m_ControlledByPlayer = false;
6043
6044 // PvP, FFAPvP
6046
6048 "Unit %u is being charmed, but it already has a charmer %s", charm->GetEntry(), charm->GetCharmerGUID().ToString().c_str());
6049 charm->m_charmer = this;
6050
6053 charm->SetWalk(false);
6054
6055 m_Controlled.insert(charm);
6056 }
6057 else
6058 {
6060
6061 if (GetTypeId() == TYPEID_PLAYER)
6062 {
6064 "Player %s is trying to uncharm unit %u, but it has another charmed unit %s", GetName().c_str(), charm->GetEntry(), GetCharmedGUID().ToString().c_str());
6065 m_charmed = nullptr;
6066 }
6067
6069 "Unit %u is being uncharmed, but it has another charmer %s", charm->GetEntry(), charm->GetCharmerGUID().ToString().c_str());
6070 charm->m_charmer = nullptr;
6071
6072 if (charm->GetTypeId() == TYPEID_PLAYER)
6073 {
6074 charm->m_ControlledByPlayer = true;
6076 charm->ToPlayer()->UpdatePvPState();
6077 }
6078 else if (Player* player = charm->GetCharmerOrOwnerPlayerOrPlayerItself())
6079 {
6080 charm->m_ControlledByPlayer = true;
6082 charm->ReplaceAllPvpFlags(player->GetPvpFlags());
6083 }
6084 else
6085 {
6086 charm->m_ControlledByPlayer = false;
6089 }
6090
6091 if (charm->IsWalking() != _isWalkingBeforeCharm)
6093
6094 if (charm->GetTypeId() == TYPEID_PLAYER
6096 || charm->GetOwnerGUID() != GetGUID())
6097 {
6098 m_Controlled.erase(charm);
6099 }
6100 }
6102}
6103
6104/*static*/ void Unit::DealHeal(HealInfo& healInfo)
6105{
6106 int32 gain = 0;
6107 Unit* healer = healInfo.GetHealer();
6108 Unit* victim = healInfo.GetTarget();
6109 uint32 addhealth = healInfo.GetHeal();
6110
6111 if (UnitAI* victimAI = victim->GetAI())
6112 victimAI->HealReceived(healer, addhealth);
6113
6114 if (UnitAI* healerAI = healer ? healer->GetAI() : nullptr)
6115 healerAI->HealDone(victim, addhealth);
6116
6117 if (addhealth)
6118 gain = victim->ModifyHealth(int32(addhealth));
6119
6120 // Hook for OnHeal Event
6121 sScriptMgr->OnHeal(healer, victim, (uint32&)gain);
6122
6123 Unit* unit = healer;
6124 if (healer && healer->GetTypeId() == TYPEID_UNIT && healer->IsTotem())
6125 unit = healer->GetOwner();
6126
6127 if (unit)
6128 {
6129 if (Player* player = unit->ToPlayer())
6130 {
6131 if (Battleground* bg = player->GetBattleground())
6132 bg->UpdatePlayerScore(player, SCORE_HEALING_DONE, gain);
6133
6134 // use the actual gain, as the overheal shall not be counted, skip gain 0 (it ignored anyway in to criteria)
6135 if (gain)
6136 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, gain, 0, victim);
6137
6138 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST, addhealth);
6139 }
6140 }
6141
6142 if (Player* player = victim->ToPlayer())
6143 {
6144 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED, gain);
6145 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED, addhealth);
6146 }
6147
6148 if (gain)
6149 healInfo.SetEffectiveHeal(gain > 0 ? static_cast<uint32>(gain) : 0UL);
6150}
6151
6152bool Unit::IsMagnet() const
6153{
6154 // Grounding Totem
6156 return true;
6157
6158 return false;
6159}
6160
6162{
6164 for (AuraEffectList::const_iterator i = hitTriggerAuras.begin(); i != hitTriggerAuras.end(); ++i)
6165 {
6166 if (Unit* magnet = (*i)->GetBase()->GetCaster())
6167 if (IsValidAttackTarget(magnet, spellInfo) && magnet->IsWithinLOSInMap(this)
6168 && (!spellInfo || (spellInfo->CheckExplicitTarget(this, magnet) == SPELL_CAST_OK
6169 && spellInfo->CheckTarget(this, magnet, false) == SPELL_CAST_OK)))
6170 if (roll_chance_i((*i)->GetAmount()))
6171 {
6172 (*i)->GetBase()->DropCharge(AURA_REMOVE_BY_EXPIRE);
6173 return magnet;
6174 }
6175 }
6176 return victim;
6177}
6178
6180{
6181 // Sequence: charmed, pet, other guardians
6182 Unit* unit = GetCharmed();
6183 if (!unit)
6184 {
6185 ObjectGuid guid = GetMinionGUID();
6186 if (!guid.IsEmpty())
6187 unit = ObjectAccessor::GetUnit(*this, guid);
6188 }
6189
6190 return unit;
6191}
6192
6194{
6195 // possessed pet and vehicle
6196 if (GetTypeId() == TYPEID_PLAYER)
6198
6199 while (!m_Controlled.empty())
6200 {
6201 Unit* target = *m_Controlled.begin();
6202 m_Controlled.erase(m_Controlled.begin());
6203 if (target->GetCharmerGUID() == GetGUID())
6204 target->RemoveCharmAuras();
6205 else if (target->GetOwnerGUID() == GetGUID() && target->IsSummon())
6206 target->ToTempSummon()->UnSummon();
6207 else
6208 TC_LOG_ERROR("entities.unit", "Unit {} is trying to release unit {} which is neither charmed nor owned by it", GetEntry(), target->GetEntry());
6209 }
6210 if (!GetPetGUID().IsEmpty())
6211 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its pet {}", GetEntry(), GetPetGUID().ToString());
6212 if (!GetMinionGUID().IsEmpty())
6213 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its minion {}", GetEntry(), GetMinionGUID().ToString());
6214 if (!GetCharmedGUID().IsEmpty())
6215 TC_LOG_FATAL("entities.unit", "Unit {} is not able to release its charm {}", GetEntry(), GetCharmedGUID().ToString());
6216 if (!IsPet()) // pets don't use the flag for this
6217 RemoveUnitFlag(UNIT_FLAG_PET_IN_COMBAT); // m_controlled is now empty, so we know none of our minions are in combat
6218}
6219
6224
6226{
6227 return u->isPossessed() && GetCharmedGUID() == u->GetGUID();
6228}
6229
6231{
6232 if (Unit* u = GetCharmed())
6233 return u->isPossessed();
6234 else
6235 return false;
6236}
6237
6239{
6240 if (IsCharmed())
6241 return GetCharmer();
6242 else
6243 return const_cast<Unit*>(this);
6244}
6245
6247{
6248 Player* player = nullptr;
6249 if (GetTypeId() == TYPEID_PLAYER)
6250 player = ToPlayer();
6251 // Should we enable this also for charmed units?
6252 else if (GetTypeId() == TYPEID_UNIT && IsPet())
6253 player = GetOwner()->ToPlayer();
6254
6255 if (!player)
6256 return nullptr;
6257 Group* group = player->GetGroup();
6258 // When there is no group check pet presence
6259 if (!group)
6260 {
6261 // We are pet now, return owner
6262 if (player != this)
6263 return IsWithinDistInMap(player, radius) ? player : nullptr;
6264 Unit* pet = GetGuardianPet();
6265 // No pet, no group, nothing to return
6266 if (!pet)
6267 return nullptr;
6268 // We are owner now, return pet
6269 return IsWithinDistInMap(pet, radius) ? pet : nullptr;
6270 }
6271
6272 std::vector<Unit*> nearMembers;
6273 // reserve place for players and pets because resizing vector every unit push is unefficient (vector is reallocated then)
6274 nearMembers.reserve(group->GetMembersCount() * 2);
6275
6276 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
6277 if (Player* Target = itr->GetSource())
6278 {
6279 // IsHostileTo check duel and controlled by enemy
6280 if (Target != this && IsWithinDistInMap(Target, radius) && Target->IsAlive() && !IsHostileTo(Target))
6281 nearMembers.push_back(Target);
6282
6283 // Push player's pet to vector
6284 if (Unit* pet = Target->GetGuardianPet())
6285 if (pet != this && IsWithinDistInMap(pet, radius) && pet->IsAlive() && !IsHostileTo(pet))
6286 nearMembers.push_back(pet);
6287 }
6288
6289 if (nearMembers.empty())
6290 return nullptr;
6291
6292 uint32 randTarget = urand(0, nearMembers.size()-1);
6293 return nearMembers[randTarget];
6294}
6295
6296// only called in Player::SetSeer
6297// so move it to Player?
6299{
6300 if (m_sharedVision.empty())
6301 {
6302 setActive(true);
6304 }
6305 m_sharedVision.push_back(player);
6306}
6307
6308// only called in Player::SetSeer
6310{
6311 m_sharedVision.remove(player);
6312 if (m_sharedVision.empty())
6313 {
6314 setActive(false);
6316 }
6317}
6318
6323
6331
6333{
6334 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
6335 {
6336 if (!m_SummonSlot[i])
6337 continue;
6338
6339 if (Creature* OldTotem = GetMap()->GetCreature(m_SummonSlot[i]))
6340 if (OldTotem->IsSummon())
6341 OldTotem->ToTempSummon()->UnSummon();
6342 }
6343}
6344
6345void Unit::SendHealSpellLog(HealInfo& healInfo, bool critical /*= false*/)
6346{
6347 // we guess size
6348 WorldPacket data(SMSG_SPELLHEALLOG, 8 + 8 + 4 + 4 + 4 + 4 + 1 + 1);
6349 data << healInfo.GetTarget()->GetPackGUID();
6350 data << healInfo.GetHealer()->GetPackGUID();
6351 data << uint32(healInfo.GetSpellInfo()->Id);
6352 data << uint32(healInfo.GetHeal());
6353 data << uint32(healInfo.GetHeal() - healInfo.GetEffectiveHeal());
6354 data << uint32(healInfo.GetAbsorb()); // Absorb amount
6355 data << uint8(critical ? 1 : 0);
6356 data << uint8(0); // unused
6357 SendMessageToSet(&data, true);
6358}
6359
6360int32 Unit::HealBySpell(HealInfo& healInfo, bool critical /*= false*/)
6361{
6362 // calculate heal absorb and reduce healing
6363 Unit::CalcHealAbsorb(healInfo);
6364 Unit::DealHeal(healInfo);
6365 SendHealSpellLog(healInfo, critical);
6366 return healInfo.GetEffectiveHeal();
6367}
6368
6369void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellId, int32 damage, Powers powerType)
6370{
6371 WorldPacket data(SMSG_SPELLENERGIZELOG, (8+8+4+4+4+1));
6372 data << victim->GetPackGUID();
6373 data << GetPackGUID();
6374 data << uint32(spellId);
6375 data << uint32(powerType);
6376 data << int32(damage);
6377 SendMessageToSet(&data, true);
6378}
6379
6380void Unit::EnergizeBySpell(Unit* victim, uint32 spellId, int32 damage, Powers powerType)
6381{
6382 if (SpellInfo const* info = sSpellMgr->GetSpellInfo(spellId))
6383 EnergizeBySpell(victim, info, damage, powerType);
6384}
6385
6386void Unit::EnergizeBySpell(Unit* victim, SpellInfo const* spellInfo, int32 damage, Powers powerType)
6387{
6388 victim->ModifyPower(powerType, damage, false);
6389 victim->GetThreatManager().ForwardThreatForAssistingMe(this, float(damage)/2, spellInfo, true);
6390 SendEnergizeSpellLog(victim, spellInfo->Id, damage, powerType);
6391}
6392
6393uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, Optional<float> const& donePctTotal, uint32 stack /*= 1*/) const
6394{
6395 if (!spellProto || !victim || damagetype == DIRECT_DAMAGE)
6396 return pdamage;
6397
6398 // Some spells don't benefit from done mods
6399 if (spellProto->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS))
6400 return pdamage;
6401
6402 // For totems get damage bonus from owner
6403 if (GetTypeId() == TYPEID_UNIT && IsTotem())
6404 if (Unit* owner = GetOwner())
6405 return owner->SpellDamageBonusDone(victim, spellProto, pdamage, damagetype, spellEffectInfo, donePctTotal, stack);
6406
6407 float ApCoeffMod = 1.0f;
6408 int32 DoneTotal = 0;
6409 float DoneTotalMod = donePctTotal ? *donePctTotal : SpellDamagePctDone(victim, spellProto, damagetype);
6410
6411 // done scripted mod (take it from owner)
6412 Unit const* owner = GetOwner() ? GetOwner() : this;
6413 DoneTotal += owner->GetTotalAuraModifier(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS, [spellProto](AuraEffect const* aurEff) -> bool
6414 {
6415 if (!aurEff->IsAffectingSpell(spellProto))
6416 return false;
6417
6418 switch (aurEff->GetMiscValue())
6419 {
6420 case 4418: // Increased Shock Damage
6421 case 4554: // Increased Lightning Damage
6422 case 4555: // Improved Moonfire
6423 case 5142: // Increased Lightning Damage
6424 case 5147: // Improved Consecration / Libram of Resurgence
6425 case 5148: // Idol of the Shooting Star
6426 case 6008: // Increased Lightning Damage
6427 case 8627: // Totem of Hex
6428 return true;
6429 default:
6430 break;
6431 }
6432
6433 return false;
6434 });
6435
6436 // Some spells don't benefit from pct done mods
6439
6440 // Custom scripted damage
6441 switch (spellProto->SpellFamilyName)
6442 {
6444 // Impurity (dummy effect)
6445 if (GetTypeId() == TYPEID_PLAYER)
6446 {
6447 PlayerSpellMap const& playerSpells = ToPlayer()->GetSpellMap();
6448 for (auto itr = playerSpells.begin(); itr != playerSpells.end(); ++itr)
6449 {
6450 if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
6451 continue;
6452
6453 switch (itr->first)
6454 {
6455 case 49220:
6456 case 49633:
6457 case 49635:
6458 case 49636:
6459 case 49638:
6460 if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first))
6461 AddPct(ApCoeffMod, proto->GetEffect(EFFECT_0).CalcValue());
6462 break;
6463 }
6464 }
6465 }
6466 break;
6467 }
6468
6469 // Done fixed damage bonus auras
6470 int32 DoneAdvertisedBenefit = SpellBaseDamageBonusDone(spellProto->GetSchoolMask());
6471 // modify spell power by victim's SPELL_AURA_MOD_DAMAGE_TAKEN auras (eg Amplify/Dampen Magic)
6472 DoneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_TAKEN, spellProto->GetSchoolMask());
6473
6474 // Pets just add their bonus damage to their spell damage
6475 // note that their spell damage is just gain of their own auras
6477 DoneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
6478
6479 // Check for table values
6480 float coeff = spellEffectInfo.BonusCoefficient;
6481 if (SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id))
6482 {
6483 WeaponAttackType const attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
6485 APbonus += GetTotalAttackPowerValue(attType);
6486
6487 if (damagetype == DOT)
6488 {
6489 coeff = bonus->dot_damage;
6490 if (bonus->ap_dot_bonus > 0)
6491 DoneTotal += int32(bonus->ap_dot_bonus * stack * ApCoeffMod * APbonus);
6492 }
6493 else
6494 {
6495 coeff = bonus->direct_damage;
6496 if (bonus->ap_bonus > 0)
6497 DoneTotal += int32(bonus->ap_bonus * stack * ApCoeffMod * APbonus);
6498 }
6499 }
6500 else
6501 {
6502 // No bonus damage for SPELL_DAMAGE_CLASS_NONE class spells by default
6503 if (spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE)
6504 return uint32(std::max(pdamage * DoneTotalMod, 0.0f));
6505 }
6506
6507 // Default calculation
6508 if (DoneAdvertisedBenefit)
6509 {
6510 if (coeff < 0.f)
6511 coeff = CalculateDefaultCoefficient(spellProto, damagetype); // As wowwiki says: C = (Cast Time / 3.5)
6512
6513 float factorMod = CalculateSpellpowerCoefficientLevelPenalty(spellProto) * stack;
6514 if (Player* modOwner = GetSpellModOwner())
6515 {
6516 coeff *= 100.0f;
6517 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
6518 coeff /= 100.0f;
6519 }
6520
6521 DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod);
6522 }
6523
6524 float tmpDamage = float(int32(pdamage) + DoneTotal) * DoneTotalMod;
6525
6526 // apply spellmod to Done damage (flat and pct)
6527 if (Player* modOwner = GetSpellModOwner())
6528 modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, tmpDamage);
6529
6530 return uint32(std::max(tmpDamage, 0.0f));
6531}
6532
6533float Unit::SpellDamagePctDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype) const
6534{
6535 if (!spellProto || !victim || damagetype == DIRECT_DAMAGE)
6536 return 1.0f;
6537
6538 // Some spells don't benefit from done mods
6539 if (spellProto->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS))
6540 return 1.0f;
6541
6542 // Some spells don't benefit from pct done mods
6544 return 1.0f;
6545
6546 // For totems get damage bonus from owner
6547 if (GetTypeId() == TYPEID_UNIT && IsTotem())
6548 if (Unit* owner = GetOwner())
6549 return owner->SpellDamagePctDone(victim, spellProto, damagetype);
6550
6551 // Done total percent damage auras
6552 float DoneTotalMod = 1.0f;
6553
6554 // Pet damage?
6555 if (GetTypeId() == TYPEID_UNIT && !IsPet())
6556 DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureTemplate()->rank);
6557
6558 float maxModDamagePercentSchool = 0.0f;
6559 if (GetTypeId() == TYPEID_PLAYER)
6560 {
6561 for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i)
6562 if (spellProto->GetSchoolMask() & (1 << i))
6563 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, GetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i));
6564 }
6565 else
6566 maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, spellProto->GetSchoolMask());
6567
6568 DoneTotalMod *= maxModDamagePercentSchool;
6569
6570 uint32 creatureTypeMask = victim->GetCreatureTypeMask();
6571
6573
6574 // bonus against aurastate
6575 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim](AuraEffect const* aurEff) -> bool
6576 {
6577 if (victim->HasAuraState(static_cast<AuraStateType>(aurEff->GetMiscValue())))
6578 return true;
6579 return false;
6580 });
6581
6582 // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
6583 if (spellProto->Mechanic)
6585
6586 // done scripted mod (take it from owner)
6587 Unit const* owner = GetOwner() ? GetOwner() : this;
6588 AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
6589 for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
6590 {
6591 if (!(*i)->IsAffectingSpell(spellProto))
6592 continue;
6593
6594 switch ((*i)->GetMiscValue())
6595 {
6596 case 4920: // Molten Fury
6597 case 4919:
6598 case 6917: // Death's Embrace
6599 case 6926:
6600 case 6928:
6601 {
6602 if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
6603 AddPct(DoneTotalMod, (*i)->GetAmount());
6604 break;
6605 }
6606 // Soul Siphon
6607 case 4992:
6608 case 4993:
6609 {
6610 // effect 1 m_amount
6611 int32 maxPercent = (*i)->GetAmount();
6612 // effect 0 m_amount
6613 int32 stepPercent = CalculateSpellDamage((*i)->GetSpellInfo()->GetEffect(EFFECT_0));
6614 // count affliction effects and calc additional damage in percentage
6615 int32 modPercent = 0;
6616 AuraApplicationMap const& victimAuras = victim->GetAppliedAuras();
6617 for (AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
6618 {
6619 Aura const* aura = itr->second->GetBase();
6620 SpellInfo const* spell = aura->GetSpellInfo();
6621 if (spell->SpellFamilyName != SPELLFAMILY_WARLOCK || !(spell->SpellFamilyFlags[1] & 0x0004071B || spell->SpellFamilyFlags[0] & 0x8044C402))
6622 continue;
6623 modPercent += stepPercent * aura->GetStackAmount();
6624 if (modPercent >= maxPercent)
6625 {
6626 modPercent = maxPercent;
6627 break;
6628 }
6629 }
6630 AddPct(DoneTotalMod, modPercent);
6631 break;
6632 }
6633 case 6916: // Death's Embrace
6634 case 6925:
6635 case 6927:
6636 if (HasAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, spellProto, this))
6637 AddPct(DoneTotalMod, (*i)->GetAmount());
6638 break;
6639 case 5481: // Starfire Bonus
6640 {
6641 if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_DRUID, 0x200002, 0, 0))
6642 AddPct(DoneTotalMod, (*i)->GetAmount());
6643 break;
6644 }
6645 // Tundra Stalker
6646 // Merciless Combat
6647 case 7277:
6648 {
6649 // Merciless Combat
6650 if ((*i)->GetSpellInfo()->SpellIconID == 2656)
6651 {
6652 if (!victim->HealthAbovePct(35))
6653 AddPct(DoneTotalMod, (*i)->GetAmount());
6654 }
6655 // Tundra Stalker
6656 else
6657 {
6658 // Frost Fever (target debuff)
6659 if (victim->HasAura(55095))
6660 AddPct(DoneTotalMod, (*i)->GetAmount());
6661 break;
6662 }
6663 break;
6664 }
6665 // Rage of Rivendare
6666 case 7293:
6667 {
6669 AddPct(DoneTotalMod, (*i)->GetSpellInfo()->GetRank() * 2.0f);
6670 break;
6671 }
6672 // Twisted Faith
6673 case 7377:
6674 {
6676 AddPct(DoneTotalMod, (*i)->GetAmount());
6677 break;
6678 }
6679 // Marked for Death
6680 case 7598:
6681 case 7599:
6682 case 7600:
6683 case 7601:
6684 case 7602:
6685 {
6686 if (victim->GetAuraEffect(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, 0x400, 0, 0))
6687 AddPct(DoneTotalMod, (*i)->GetAmount());
6688 break;
6689 }
6690 // Dirty Deeds
6691 case 6427:
6692 case 6428:
6693 case 6579:
6694 case 6580:
6695 {
6696 if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
6697 {
6698 // effect 0 has expected value but in negative state
6699 int32 bonus = -(*i)->GetBase()->GetEffect(0)->GetAmount();
6700 AddPct(DoneTotalMod, bonus);
6701 }
6702 break;
6703 }
6704 }
6705 }
6706
6707 // Custom scripted damage
6708 switch (spellProto->SpellFamilyName)
6709 {
6710 case SPELLFAMILY_MAGE:
6711 // Ice Lance
6712 if (spellProto->SpellIconID == 186)
6713 {
6714 if (victim->HasAuraState(AURA_STATE_FROZEN, spellProto, this))
6715 {
6716 // Glyph of Ice Lance
6717 if (owner->HasAura(56377) && victim->GetLevel() > owner->GetLevel())
6718 DoneTotalMod *= 4.0f;
6719 else
6720 DoneTotalMod *= 3.0f;
6721 }
6722 }
6723
6724 // Torment the weak
6725 if (spellProto->SpellFamilyFlags[0] & 0x20600021 || spellProto->SpellFamilyFlags[1] & 0x9000)
6726 {
6727 if (victim->HasAuraWithMechanic((1 << MECHANIC_SNARE) | (1 << MECHANIC_SLOW_ATTACK)))
6728 {
6730 for (AuraEffectList::const_iterator i = mDumyAuras.begin(); i != mDumyAuras.end(); ++i)
6731 {
6732 if ((*i)->GetSpellInfo()->SpellIconID == 3263)
6733 {
6734 AddPct(DoneTotalMod, (*i)->GetAmount());
6735 break;
6736 }
6737 }
6738 }
6739 }
6740 break;
6741 case SPELLFAMILY_PRIEST:
6742 // Mind Flay
6743 if (spellProto->SpellFamilyFlags[0] & 0x800000)
6744 {
6745 // Glyph of Shadow Word: Pain
6746 if (AuraEffect* aurEff = GetAuraEffect(55687, 0))
6747 // Increase Mind Flay damage if Shadow Word: Pain present on target
6749 AddPct(DoneTotalMod, aurEff->GetAmount());
6750
6751 // Twisted Faith - Mind Flay part
6753 // Increase Mind Flay damage if Shadow Word: Pain present on target
6755 AddPct(DoneTotalMod, aurEff->GetAmount());
6756 }
6757 // Smite
6758 else if (spellProto->SpellFamilyFlags[0] & 0x80)
6759 {
6760 // Glyph of Smite
6761 if (AuraEffect* aurEff = GetAuraEffect(55692, 0))
6762 if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_PRIEST, 0x100000, 0, 0, GetGUID()))
6763 AddPct(DoneTotalMod, aurEff->GetAmount());
6764 }
6765 // Shadow Word: Death
6766 else if (spellProto->SpellFamilyFlags[1] & 0x2)
6767 {
6768 // Glyph of Shadow Word: Death
6769 if (AuraEffect* aurEff = GetAuraEffect(55682, 1))
6771 AddPct(DoneTotalMod, aurEff->GetAmount());
6772 }
6773 break;
6775 // Judgement of Vengeance/Judgement of Corruption
6776 if ((spellProto->SpellFamilyFlags[1] & 0x400000) && spellProto->SpellIconID == 2292)
6777 {
6778 // Get stack of Holy Vengeance/Blood Corruption on the target added by caster
6779 uint32 stacks = 0;
6781 for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
6782 {
6783 if (((*itr)->GetId() == 31803 || (*itr)->GetId() == 53742) && (*itr)->GetCasterGUID() == GetGUID())
6784 {
6785 stacks = (*itr)->GetBase()->GetStackAmount();
6786 break;
6787 }
6788 }
6789 // + 10% for each application of Holy Vengeance/Blood Corruption on the target
6790 if (stacks)
6791 AddPct(DoneTotalMod, 10 * stacks);
6792 }
6793 break;
6794 case SPELLFAMILY_DRUID:
6795 // Thorns
6796 if (spellProto->SpellFamilyFlags[0] & 0x100)
6797 {
6798 // Brambles
6799 if (AuraEffect* aurEff = GetAuraEffectOfRankedSpell(16836, 0))
6800 AddPct(DoneTotalMod, aurEff->GetAmount());
6801 }
6802 break;
6804 // Fire and Brimstone
6805 if (spellProto->SpellFamilyFlags[1] & 0x00020040)
6806 {
6807 if (victim->HasAuraState(AURA_STATE_CONFLAGRATE, nullptr, this))
6808 {
6809 if (AuraEffect const* aurEFf = GetDummyAuraEffect(SPELLFAMILY_WARLOCK, 3173, EFFECT_0))
6810 AddPct(DoneTotalMod, aurEFf->GetAmount());
6811 }
6812 }
6813 // Shadow Bite (15% increase from each dot)
6814 if (spellProto->SpellFamilyFlags[1] & 0x00400000 && IsPet())
6815 if (uint8 count = victim->GetDoTsByCaster(GetOwnerGUID()))
6816 AddPct(DoneTotalMod, 15 * count);
6817
6818 // Drain Soul - If the target is at or below 25% health, Drain Soul causes four times the normal damage
6819 if (spellProto->SpellFamilyFlags[0] & 0x00004000 && !victim->HealthAbovePct(25))
6820 DoneTotalMod *= 4;
6821
6822 // Don't let Conflagrate double dip from damage done bonuses (from Immolate/Shadowflame and then for itself)
6823 if (spellProto->SpellFamilyFlags[1] & 0x800000)
6824 DoneTotalMod = 1.0f;
6825 break;
6826 case SPELLFAMILY_HUNTER:
6827 // Steady Shot
6828 if (spellProto->SpellFamilyFlags[1] & 0x1)
6829 if (AuraEffect* aurEff = GetAuraEffect(56826, 0)) // Glyph of Steady Shot
6830 if (victim->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_HUNTER, 0x00004000, 0, 0, GetGUID()))
6831 AddPct(DoneTotalMod, aurEff->GetAmount());
6832 break;
6834 // Improved Icy Touch
6835 if (spellProto->SpellFamilyFlags[0] & 0x2)
6837 AddPct(DoneTotalMod, aurEff->GetAmount());
6838
6839 // Glacier Rot
6840 if (spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6)
6842 if (victim->GetDiseasesByCaster(owner->GetGUID()) > 0)
6843 AddPct(DoneTotalMod, aurEff->GetAmount());
6844 break;
6845 }
6846
6847 return DoneTotalMod;
6848}
6849
6850uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 pdamage, DamageEffectType damagetype) const
6851{
6852 if (!spellProto || damagetype == DIRECT_DAMAGE)
6853 return pdamage;
6854
6855 float TakenTotalMod = 1.0f;
6856
6857 // Mod damage from spell mechanic
6858 if (uint32 mechanicMask = spellProto->GetAllEffectsMechanicMask())
6859 {
6860 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
6861 {
6862 if (mechanicMask & uint32(1 << (aurEff->GetMiscValue())))
6863 return true;
6864 return false;
6865 });
6866 }
6867
6868 //.. taken pct: dummy auras
6870 for (AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
6871 {
6872 switch ((*i)->GetSpellInfo()->SpellIconID)
6873 {
6874 // Cheat Death
6875 case 2109:
6876 if ((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
6877 {
6878 // Patch 2.4.3: The resilience required to reach the 90% damage reduction cap
6879 // is 22.5% critical strike damage reduction, or 444 resilience.
6880 // To calculate for 90%, we multiply the 100% by 4 (22.5% * 4 = 90%)
6881 float mod = -1.0f * GetMeleeCritDamageReduction(400);
6882 AddPct(TakenTotalMod, std::max(mod, float((*i)->GetAmount())));
6883 }
6884 break;
6885 }
6886 }
6887
6888 // Spells with SPELL_ATTR4_FIXED_DAMAGE should only benefit from mechanic damage mod auras.
6889 if (!spellProto->HasAttribute(SPELL_ATTR4_FIXED_DAMAGE))
6890 {
6891 // from positive and negative SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
6892 // multiplicative bonus, for example Dispersion + Shadowform (0.10*0.85=0.085)
6894
6895 // From caster spells
6896 if (caster)
6897 {
6898 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER, [caster, spellProto](AuraEffect const* aurEff) -> bool
6899 {
6900 if (aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectingSpell(spellProto))
6901 return true;
6902 return false;
6903 });
6904 }
6905 }
6906
6907 // Sanctified Wrath (bypass damage reduction)
6908 if (caster && TakenTotalMod < 1.0f)
6909 {
6910 float damageReduction = 1.0f - TakenTotalMod;
6912 for (AuraEffect const* aurEff : casterIgnoreResist)
6913 {
6914 if (!(aurEff->GetMiscValue() & spellProto->GetSchoolMask()))
6915 continue;
6916
6917 AddPct(damageReduction, -aurEff->GetAmount());
6918 }
6919
6920 TakenTotalMod = 1.0f - damageReduction;
6921 }
6922
6923 float tmpDamage = pdamage * TakenTotalMod;
6924 return uint32(std::max(tmpDamage, 0.0f));
6925}
6926
6928{
6929 int32 DoneAdvertisedBenefit = GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE, schoolMask);
6930
6931 if (GetTypeId() == TYPEID_PLAYER)
6932 {
6933 // Base value
6934 DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
6935
6936 // Damage bonus from stats
6938 for (AuraEffect const* aurEff : mDamageDoneOfStatPercent)
6939 {
6940 if ((aurEff->GetMiscValue() & schoolMask) != 0)
6941 {
6942 // stat used stored in miscValueB for this aura
6943 Stats const usedStat = static_cast<Stats>(aurEff->GetMiscValueB());
6944 DoneAdvertisedBenefit += static_cast<int32>(CalculatePct(GetStat(usedStat), aurEff->GetAmount()));
6945 }
6946 }
6947
6948 // ... and attack power
6950 }
6951
6952 return DoneAdvertisedBenefit;
6953}
6954
6955float Unit::SpellCritChanceDone(SpellInfo const* spellInfo, SpellSchoolMask schoolMask, WeaponAttackType attackType /*= BASE_ATTACK*/, bool isPeriodic /*= false*/) const
6956{
6958 if (GetTypeId() == TYPEID_UNIT && !GetSpellModOwner())
6959 return 0.0f;
6960
6961 // not critting spell
6962 if (!isPeriodic && !spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
6963 return 0.0f;
6964
6965 float crit_chance = 0.0f;
6966 switch (spellInfo->DmgClass)
6967 {
6970 {
6971 auto getPhysicalCritChance = [&]
6972 {
6974 };
6975
6976 auto getMagicCritChance = [&]
6977 {
6978 if (IsPlayer())
6980
6982 };
6983
6984 if (schoolMask & SPELL_SCHOOL_MASK_NORMAL)
6985 crit_chance = std::max(crit_chance, getPhysicalCritChance());
6986
6987 if (schoolMask & ~SPELL_SCHOOL_MASK_NORMAL)
6988 crit_chance = std::max(crit_chance, getMagicCritChance());
6989 break;
6990 }
6993 {
6994 crit_chance += GetUnitCriticalChanceDone(attackType);
6996 break;
6997 }
6998 default:
6999 return 0.0f;
7000 }
7001 // percent done
7002 // only players use intelligence for critical chance computations
7003 if (Player* modOwner = GetSpellModOwner())
7004 modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRITICAL_CHANCE, crit_chance);
7005
7006 return std::max(crit_chance, 0.0f);
7007}
7008
7009float Unit::SpellCritChanceTaken(Unit const* caster, SpellInfo const* spellInfo, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType /*= BASE_ATTACK*/, bool isPeriodic /*= false*/) const
7010{
7011 // not critting spell
7012 if (!isPeriodic && !spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
7013 return 0.0f;
7014
7015 float crit_chance = doneChance;
7016 switch (spellInfo->DmgClass)
7017 {
7019 {
7020 // taken
7021 if (!spellInfo->IsPositive())
7022 {
7023 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
7025
7026 if (caster && caster->CanApplyResilience())
7027 Unit::ApplyResilience(this, &crit_chance, nullptr, false, CR_CRIT_TAKEN_SPELL);
7028
7029 // Modify critical chance by victim SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
7030 // applied after resilience
7032 }
7033
7034 // scripted (increase crit chance ... against ... target by x%
7035 if (caster)
7036 {
7037 AuraEffectList const& mOverrideClassScript = caster->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7038 for (AuraEffect const* aurEff : mOverrideClassScript)
7039 {
7040 if (!aurEff->IsAffectingSpell(spellInfo))
7041 continue;
7042
7043 float modChance = 0.f;
7044 switch (aurEff->GetMiscValue())
7045 {
7046 case 911: // Shatter (Rank 3)
7047 modChance += 16.f;
7048 [[fallthrough]];
7049 case 910: // Shatter (Rank 2)
7050 modChance += 17.f;
7051 [[fallthrough]];
7052 case 849: // Shatter (Rank 1)
7053 modChance += 17.f;
7054 if (!HasAuraState(AURA_STATE_FROZEN, spellInfo, caster))
7055 break;
7056
7057 crit_chance += modChance;
7058 break;
7059 case 7917: // Glyph of Shadowburn
7060 if (HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellInfo, caster))
7061 crit_chance += aurEff->GetAmount();
7062 break;
7063 case 7997: // Renewed Hope
7064 case 7998:
7065 if (HasAura(6788))
7066 crit_chance += aurEff->GetAmount();
7067 break;
7068 default:
7069 break;
7070 }
7071 }
7072 // Custom crit by class
7073 switch (spellInfo->SpellFamilyName)
7074 {
7075 case SPELLFAMILY_MAGE:
7076 // Glyph of Fire Blast
7077 if (spellInfo->SpellFamilyFlags[0] == 0x2 && spellInfo->SpellIconID == 12)
7079 if (AuraEffect const* aurEff = caster->GetAuraEffect(56369, EFFECT_0))
7080 crit_chance += aurEff->GetAmount();
7081 break;
7082 case SPELLFAMILY_DRUID:
7083 // Improved Faerie Fire
7085 if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 109, 0))
7086 crit_chance += aurEff->GetAmount();
7087
7088 // cumulative effect - don't break
7089
7090 // Starfire
7091 if (spellInfo->SpellFamilyFlags[0] & 0x4 && spellInfo->SpellIconID == 1485)
7092 {
7093 // Improved Insect Swarm
7094 if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 1771, 0))
7096 crit_chance += aurEff->GetAmount();
7097 break;
7098 }
7099 break;
7100 case SPELLFAMILY_ROGUE:
7101 // Shiv-applied poisons can't crit
7102 if (caster->FindCurrentSpellBySpellId(5938))
7103 crit_chance = 0.0f;
7104 break;
7106 // Flash of light
7107 if (spellInfo->SpellFamilyFlags[0] & 0x40000000)
7108 {
7109 // Sacred Shield
7110 if (AuraEffect const* aura = GetAuraEffect(58597, 1, GetGUID()))
7111 crit_chance += aura->GetAmount();
7112 break;
7113 }
7114 // Exorcism
7115 else if (spellInfo->GetCategory() == 19)
7116 {
7118 return 100.0f;
7119 break;
7120 }
7121 break;
7122 case SPELLFAMILY_SHAMAN:
7123 // Lava Burst
7124 if (spellInfo->SpellFamilyFlags[1] & 0x00001000)
7125 {
7126 if (GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0, 0, caster->GetGUID()))
7128 return 100.0f;
7129 break;
7130 }
7131 break;
7132 }
7133
7134 // Spell crit suppression
7135 if (GetTypeId() == TYPEID_UNIT)
7136 {
7137 int32 const levelDiff = static_cast<int32>(GetLevelForTarget(caster)) - caster->GetLevel();
7138 crit_chance -= levelDiff * 0.7f;
7139 }
7140 }
7141 break;
7142 }
7144 {
7145 // Custom crit by class
7146 if (caster)
7147 {
7148 switch (spellInfo->SpellFamilyName)
7149 {
7150 case SPELLFAMILY_DRUID:
7151 // Rend and Tear - bonus crit chance for Ferocious Bite on bleeding targets
7152 if (spellInfo->SpellFamilyFlags[0] & 0x00800000
7153 && spellInfo->SpellIconID == 1680
7155 {
7156 if (AuraEffect const* rendAndTear = caster->GetDummyAuraEffect(SPELLFAMILY_DRUID, 2859, 1))
7157 crit_chance += rendAndTear->GetAmount();
7158 break;
7159 }
7160 break;
7162 // Victory Rush
7163 if (spellInfo->SpellFamilyFlags[1] & 0x100)
7164 {
7165 // Glyph of Victory Rush
7166 if (AuraEffect const* aurEff = caster->GetAuraEffect(58382, 0))
7167 crit_chance += aurEff->GetAmount();
7168 break;
7169 }
7170 break;
7171 }
7172 }
7173 [[fallthrough]]; // Calculate critical strike chance for both Ranged and Melee spells
7174 }
7176 if (caster)
7177 crit_chance = GetUnitCriticalChanceTaken(caster, attackType, crit_chance);
7178 break;
7180 default:
7181 return 0.f;
7182 }
7183
7184 if (caster)
7185 {
7186 crit_chance += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER, [caster, spellInfo](AuraEffect const* aurEff) -> bool
7187 {
7188 if (aurEff->GetCasterGUID() == caster->GetGUID() && aurEff->IsAffectingSpell(spellInfo))
7189 return true;
7190 return false;
7191 });
7192 }
7193
7194 return std::max(crit_chance, 0.0f);
7195}
7196
7197/*static*/ uint32 Unit::SpellCriticalDamageBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim)
7198{
7199 // Calculate critical bonus
7200 int32 crit_bonus = damage;
7201 float crit_mod = 0.0f;
7202
7203 switch (spellProto->DmgClass)
7204 {
7205 case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100%
7208 crit_bonus += damage;
7209 break;
7210 default:
7211 crit_bonus += damage / 2; // for spells is 50%
7212 break;
7213 }
7214
7215 if (caster)
7216 {
7217 crit_mod += (caster->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS, spellProto->GetSchoolMask()) - 1.0f) * 100;
7218
7219 if (victim)
7221
7222 if (crit_bonus != 0)
7223 AddPct(crit_bonus, crit_mod);
7224
7225 crit_bonus -= damage;
7226
7227 if (damage > uint32(crit_bonus))
7228 {
7229 // adds additional damage to critBonus (from talents)
7230 if (Player* modOwner = caster->GetSpellModOwner())
7231 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
7232 }
7233
7234 crit_bonus += damage;
7235 }
7236
7237 return crit_bonus;
7238}
7239
7240/*static*/ uint32 Unit::SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim)
7241{
7242 // Calculate critical bonus
7243 int32 crit_bonus;
7244 switch (spellProto->DmgClass)
7245 {
7246 case SPELL_DAMAGE_CLASS_MELEE: // for melee based spells is 100%
7249 crit_bonus = damage;
7250 break;
7251 default:
7252 crit_bonus = damage / 2; // for spells is 50%
7253 break;
7254 }
7255
7256 if (caster)
7257 {
7258 if (victim)
7259 {
7260 uint32 creatureTypeMask = victim->GetCreatureTypeMask();
7261 crit_bonus = int32(crit_bonus * caster->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, creatureTypeMask));
7262 }
7263 }
7264
7265 if (crit_bonus > 0)
7266 damage += crit_bonus;
7267
7268 if (caster)
7269 damage = int32(float(damage) * caster->GetTotalAuraMultiplier(SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT));
7270
7271 return damage;
7272}
7273
7274uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype, SpellEffectInfo const& spellEffectInfo, Optional<float> const& donePctTotal, uint32 stack /*= 1*/) const
7275{
7276 // For totems get healing bonus from owner (statue isn't totem in fact)
7277 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7278 if (Unit* owner = GetOwner())
7279 return owner->SpellHealingBonusDone(victim, spellProto, healamount, damagetype, spellEffectInfo, donePctTotal, stack);
7280
7281 // No bonus healing for potion spells
7282 if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
7283 return healamount;
7284
7285 float ApCoeffMod = 1.0f;
7286 int32 DoneTotal = 0;
7287 float DoneTotalMod = donePctTotal ? *donePctTotal : SpellHealingPctDone(victim, spellProto);
7288
7289 // done scripted mod (take it from owner)
7290 Unit const* owner = GetOwner() ? GetOwner() : this;
7291 AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7292 for (AuraEffect const* aurEff : mOverrideClassScript)
7293 {
7294 if (!aurEff->IsAffectingSpell(spellProto))
7295 continue;
7296
7297 switch (aurEff->GetMiscValue())
7298 {
7299 case 4415: // Increased Rejuvenation Healing
7300 case 4953:
7301 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
7302 DoneTotal += aurEff->GetAmount();
7303 break;
7304 default:
7305 break;
7306 }
7307 }
7308
7309 // Custom scripted damage
7310 switch (spellProto->SpellFamilyName)
7311 {
7313 // Impurity (dummy effect)
7314 if (GetTypeId() == TYPEID_PLAYER)
7315 {
7316 PlayerSpellMap const& playerSpells = ToPlayer()->GetSpellMap();
7317 for (auto itr = playerSpells.begin(); itr != playerSpells.end(); ++itr)
7318 {
7319 if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
7320 continue;
7321
7322 switch (itr->first)
7323 {
7324 case 49220:
7325 case 49633:
7326 case 49635:
7327 case 49636:
7328 case 49638:
7329 if (SpellInfo const* proto = sSpellMgr->GetSpellInfo(itr->first))
7330 AddPct(ApCoeffMod, proto->GetEffect(EFFECT_0).CalcValue());
7331 break;
7332 }
7333 }
7334 }
7335 break;
7336 }
7337
7338 // Done fixed damage bonus auras
7339 int32 DoneAdvertisedBenefit = SpellBaseHealingBonusDone(spellProto->GetSchoolMask());
7340 // modify spell power by victim's SPELL_AURA_MOD_HEALING auras (eg Amplify/Dampen Magic)
7341 DoneAdvertisedBenefit += victim->GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_HEALING, spellProto->GetSchoolMask());
7342
7343 // Pets just add their bonus damage to their spell damage
7344 // note that their spell damage is just gain of their own auras
7346 DoneAdvertisedBenefit += static_cast<Guardian const*>(this)->GetBonusDamage();
7347
7348 // Check for table values
7349 float coeff = spellEffectInfo.BonusCoefficient;
7350 if (SpellBonusEntry const* bonus = sSpellMgr->GetSpellBonusData(spellProto->Id))
7351 {
7352 WeaponAttackType const attType = (spellProto->IsRangedWeaponSpell() && spellProto->DmgClass != SPELL_DAMAGE_CLASS_MELEE) ? RANGED_ATTACK : BASE_ATTACK;
7354 APbonus += GetTotalAttackPowerValue(attType);
7355
7356 if (damagetype == DOT)
7357 {
7358 coeff = bonus->dot_damage;
7359 if (bonus->ap_dot_bonus > 0)
7360 DoneTotal += int32(bonus->ap_dot_bonus * stack * ApCoeffMod * APbonus);
7361 }
7362 else
7363 {
7364 coeff = bonus->direct_damage;
7365 if (bonus->ap_bonus > 0)
7366 DoneTotal += int32(bonus->ap_bonus * stack * ApCoeffMod * APbonus);
7367 }
7368 }
7369 else
7370 {
7371 // No bonus healing for SPELL_DAMAGE_CLASS_NONE class spells by default
7372 if (spellProto->DmgClass == SPELL_DAMAGE_CLASS_NONE)
7373 return uint32(std::max(healamount * DoneTotalMod, 0.0f));
7374 }
7375
7376 // Default calculation
7377 if (DoneAdvertisedBenefit)
7378 {
7379 if (coeff < 0.f)
7380 coeff = CalculateDefaultCoefficient(spellProto, damagetype) * 1.88f; // As wowwiki says: C = (Cast Time / 3.5) * 1.88 (for healing spells)
7381
7382 float factorMod = CalculateSpellpowerCoefficientLevelPenalty(spellProto) * stack;
7383 if (Player* modOwner = GetSpellModOwner())
7384 {
7385 coeff *= 100.0f;
7386 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_BONUS_MULTIPLIER, coeff);
7387 coeff /= 100.0f;
7388 }
7389
7390 DoneTotal += int32(DoneAdvertisedBenefit * coeff * factorMod);
7391 }
7392
7393 for (SpellEffectInfo const& otherSpellEffect : spellProto->GetEffects())
7394 {
7395 switch (otherSpellEffect.ApplyAuraName)
7396 {
7397 // Bonus healing does not apply to these spells
7400 DoneTotal = 0;
7401 break;
7402 default:
7403 break;
7404 }
7405 if (otherSpellEffect.IsEffect(SPELL_EFFECT_HEALTH_LEECH))
7406 DoneTotal = 0;
7407 }
7408
7409 float heal = float(int32(healamount) + DoneTotal) * DoneTotalMod;
7410
7411 // apply spellmod to Done amount
7412 if (Player* modOwner = GetSpellModOwner())
7413 modOwner->ApplySpellMod(spellProto->Id, damagetype == DOT ? SPELLMOD_DOT : SPELLMOD_DAMAGE, heal);
7414
7415 return uint32(std::max(heal, 0.0f));
7416}
7417
7418float Unit::SpellHealingPctDone(Unit* victim, SpellInfo const* spellProto) const
7419{
7420 // For totems get healing bonus from owner
7421 if (GetTypeId() == TYPEID_UNIT && IsTotem())
7422 if (Unit* owner = GetOwner())
7423 return owner->SpellHealingPctDone(victim, spellProto);
7424
7425 // Some spells don't benefit from done mods
7426 if (spellProto->HasAttribute(SPELL_ATTR3_NO_DONE_BONUS))
7427 return 1.0f;
7428
7429 // Some spells don't benefit from done mods
7431 return 1.0f;
7432
7433 // No bonus healing for potion spells
7434 if (spellProto->SpellFamilyName == SPELLFAMILY_POTION)
7435 return 1.0f;
7436
7437 float DoneTotalMod = 1.0f;
7438
7439 // Healing done percent
7441
7442 // done scripted mod (take it from owner)
7443 Unit const* owner = GetOwner() ? GetOwner() : this;
7444 AuraEffectList const& mOverrideClassScript= owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7445 for (AuraEffect const* aurEff : mOverrideClassScript)
7446 {
7447 if (!aurEff->IsAffectingSpell(spellProto))
7448 continue;
7449
7450 switch (aurEff->GetMiscValue())
7451 {
7452 case 21: // Test of Faith
7453 case 6935:
7454 case 6918:
7455 if (victim->HealthBelowPct(50))
7456 AddPct(DoneTotalMod, aurEff->GetAmount());
7457 break;
7458 case 7798: // Glyph of Regrowth
7459 {
7461 AddPct(DoneTotalMod, aurEff->GetAmount());
7462 break;
7463 }
7464 case 8477: // Nourish Heal Boost
7465 {
7466 int32 stepPercent = aurEff->GetAmount();
7467 int32 modPercent = 0;
7468 AuraApplicationMap const& victimAuras = victim->GetAppliedAuras();
7469 for (AuraApplicationMap::const_iterator itr = victimAuras.begin(); itr != victimAuras.end(); ++itr)
7470 {
7471 Aura const* aura = itr->second->GetBase();
7472 if (aura->GetCasterGUID() != GetGUID())
7473 continue;
7474
7475 SpellInfo const* m_spell = aura->GetSpellInfo();
7476 if (m_spell->SpellFamilyName != SPELLFAMILY_DRUID ||
7477 !(m_spell->SpellFamilyFlags[1] & 0x00000010 || m_spell->SpellFamilyFlags[0] & 0x50))
7478 continue;
7479 modPercent += stepPercent * aura->GetStackAmount();
7480 }
7481 AddPct(DoneTotalMod, modPercent);
7482 break;
7483 }
7484 case 7871: // Glyph of Lesser Healing Wave
7485 {
7486 if (victim->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_SHAMAN, 0, 0x00000400, 0))
7487 AddPct(DoneTotalMod, aurEff->GetAmount());
7488 break;
7489 }
7490 default:
7491 break;
7492 }
7493 }
7494
7495 return DoneTotalMod;
7496}
7497
7498uint32 Unit::SpellHealingBonusTaken(Unit* caster, SpellInfo const* spellProto, uint32 healamount, DamageEffectType damagetype) const
7499{
7500 float TakenTotalMod = 1.0f;
7501
7502 // Healing taken percent
7504 if (minval)
7505 AddPct(TakenTotalMod, minval);
7506
7508 if (maxval)
7509 AddPct(TakenTotalMod, maxval);
7510
7511 // Nourish cast
7512 if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[1] & 0x2000000)
7513 {
7514 // Rejuvenation, Regrowth, Lifebloom, or Wild Growth
7516 // increase healing by 20%
7517 TakenTotalMod *= 1.2f;
7518 }
7519
7520 if (damagetype == DOT)
7521 {
7522 // Healing over time taken percent
7523 float minval_hot = float(GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HOT_PCT));
7524 if (minval_hot)
7525 AddPct(TakenTotalMod, minval_hot);
7526
7527 float maxval_hot = float(GetMaxPositiveAuraModifier(SPELL_AURA_MOD_HOT_PCT));
7528 if (maxval_hot)
7529 AddPct(TakenTotalMod, maxval_hot);
7530 }
7531
7532 if (caster)
7533 {
7534 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_HEALING_RECEIVED, [caster, spellProto](AuraEffect const* aurEff) -> bool
7535 {
7536 if (caster->GetGUID() == aurEff->GetCasterGUID() && aurEff->IsAffectingSpell(spellProto))
7537 return true;
7538 return false;
7539 });
7540 }
7541
7542 float heal = healamount * TakenTotalMod;
7543 return uint32(std::max(heal, 0.0f));
7544}
7545
7547{
7548 int32 advertisedBenefit = GetTotalAuraModifier(SPELL_AURA_MOD_HEALING_DONE, [schoolMask](AuraEffect const* aurEff) -> bool
7549 {
7550 if (!aurEff->GetMiscValue() || (aurEff->GetMiscValue() & schoolMask) != 0)
7551 return true;
7552 return false;
7553 });
7554
7555 // Healing bonus of spirit, intellect and strength
7556 if (GetTypeId() == TYPEID_PLAYER)
7557 {
7558 // Base value
7559 advertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
7560
7561 // Healing bonus from stats
7563 for (AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i)
7564 {
7565 // stat used dependent from misc value (stat index)
7566 Stats usedStat = Stats((*i)->GetSpellEffectInfo().MiscValue);
7567 advertisedBenefit += int32(CalculatePct(GetStat(usedStat), (*i)->GetAmount()));
7568 }
7569
7570 // ... and attack power
7572 for (AuraEffectList::const_iterator i = mHealingDonebyAP.begin(); i != mHealingDonebyAP.end(); ++i)
7573 if ((*i)->GetMiscValue() & schoolMask)
7574 advertisedBenefit += int32(CalculatePct(GetTotalAttackPowerValue(BASE_ATTACK), (*i)->GetAmount()));
7575 }
7576 return advertisedBenefit;
7577}
7578
7580{
7581 if (schoolMask == SPELL_SCHOOL_MASK_NONE)
7582 return false;
7583
7584 // If m_immuneToSchool type contain this school type, IMMUNE damage.
7585 uint32 schoolImmunityMask = GetSchoolImmunityMask();
7586 if ((schoolImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7587 return true;
7588
7589 // If m_immuneToDamage type contain magic, IMMUNE damage.
7590 uint32 damageImmunityMask = GetDamageImmunityMask();
7591 if ((damageImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7592 return true;
7593
7594 return false;
7595}
7596
7597bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
7598{
7599 if (!spellInfo)
7600 return false;
7601
7602 // for example 40175
7604 return false;
7605
7607 return false;
7608
7609 if (uint32 schoolMask = spellInfo->GetSchoolMask())
7610 {
7611 // If m_immuneToSchool type contain this school type, IMMUNE damage.
7612 uint32 schoolImmunityMask = 0;
7614 for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7615 if ((itr->first & schoolMask) && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->second)))
7616 schoolImmunityMask |= itr->first;
7617
7618 // // We need to be immune to all types
7619 if ((schoolImmunityMask & schoolMask) == schoolMask)
7620 return true;
7621
7622 // If m_immuneToDamage type contain magic, IMMUNE damage.
7623 uint32 damageImmunityMask = GetDamageImmunityMask();
7624 if ((damageImmunityMask & schoolMask) == schoolMask) // We need to be immune to all types
7625 return true;
7626 }
7627
7628 return false;
7629}
7630
7631bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute /*= false*/) const
7632{
7633 if (!spellInfo)
7634 return false;
7635
7636 auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
7637 {
7639 if (!requireImmunityPurgesEffectAttribute)
7640 return range.begin() != range.end();
7641
7642 return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
7643 {
7644 if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second))
7645 if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
7646 return true;
7647
7648 return false;
7649 });
7650 };
7651
7652 // Single spell immunity.
7654 if (hasImmunity(idList, spellInfo->Id))
7655 return true;
7656
7658 return false;
7659
7660 if (uint32 dispel = spellInfo->Dispel)
7661 {
7663 if (hasImmunity(dispelList, dispel))
7664 return true;
7665 }
7666
7667 // Spells that don't have effectMechanics.
7668 if (uint32 mechanic = spellInfo->Mechanic)
7669 {
7671 if (hasImmunity(mechanicList, mechanic))
7672 return true;
7673 }
7674
7675 bool immuneToAllEffects = true;
7676 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
7677 {
7678 // State/effect immunities applied by aura expect full spell immunity
7679 // Ignore effects with mechanic, they are supposed to be checked separately
7680 if (!spellEffectInfo.IsEffect())
7681 continue;
7682
7683 if (!IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute))
7684 {
7685 immuneToAllEffects = false;
7686 break;
7687 }
7688 }
7689
7690 if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
7691 return true;
7692
7693 if (uint32 schoolMask = spellInfo->GetSchoolMask())
7694 {
7695 uint32 schoolImmunityMask = 0;
7697 for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7698 {
7699 if ((itr->first & schoolMask) == 0)
7700 continue;
7701
7702 SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second);
7703 if (requireImmunityPurgesEffectAttribute)
7704 if (!immuneSpellInfo || !immuneSpellInfo->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
7705 continue;
7706
7707 // Consider the school immune if any of these conditions are not satisfied.
7708 // In case of no immuneSpellInfo, ignore that condition and check only the other conditions
7709 if ((immuneSpellInfo && !immuneSpellInfo->IsPositive()) || !spellInfo->IsPositive() || !caster || !IsFriendlyTo(caster))
7710 if (!spellInfo->CanPierceImmuneAura(immuneSpellInfo))
7711 schoolImmunityMask |= itr->first;
7712 }
7713
7714 if ((schoolImmunityMask & schoolMask) == schoolMask)
7715 return true;
7716 }
7717
7718 return false;
7719}
7720
7722{
7723 uint32 mask = 0;
7725 for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
7726 mask |= itr->first;
7727
7728 return mask;
7729}
7730
7732{
7733 uint32 mask = 0;
7735 for (auto itr = damageList.begin(); itr != damageList.end(); ++itr)
7736 mask |= itr->first;
7737
7738 return mask;
7739}
7740
7742{
7743 uint32 mask = 0;
7745 for (auto itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
7746 mask |= (1 << itr->first);
7747
7748 return mask;
7749}
7750
7751bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster,
7752 bool requireImmunityPurgesEffectAttribute /*= false*/) const
7753{
7754 if (!spellInfo || !spellEffectInfo.IsEffect())
7755 return false;
7756
7758 return false;
7759
7760 auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
7761 {
7763 if (!requireImmunityPurgesEffectAttribute)
7764 return range.begin() != range.end();
7765
7766 return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
7767 {
7768 if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second))
7769 if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
7770 return true;
7771
7772 return false;
7773 });
7774 };
7775
7776 // If m_immuneToEffect type contain this effect type, IMMUNE effect.
7778 if (hasImmunity(effectList, spellEffectInfo.Effect))
7779 return true;
7780
7781 if (uint32 mechanic = spellEffectInfo.Mechanic)
7782 {
7784 if (hasImmunity(mechanicList, mechanic))
7785 return true;
7786 }
7787
7788 if (AuraType aura = spellEffectInfo.ApplyAuraName)
7789 {
7791 {
7793 if (hasImmunity(list, aura))
7794 return true;
7795 }
7796
7798 {
7799 // Check for immune to application of harmful magical effects
7801 for (AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
7802 if (((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) && // Check school
7803 ((caster && !IsFriendlyTo(caster)) || !spellInfo->IsPositiveEffect(spellEffectInfo.EffectIndex))) // Harmful
7804 return true;
7805 }
7806 }
7807
7808 return false;
7809}
7810
7811uint32 Unit::MeleeDamageBonusDone(Unit* victim, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/)
7812{
7813 if (!victim || pdamage == 0)
7814 return 0;
7815
7816 uint32 creatureTypeMask = victim->GetCreatureTypeMask();
7817
7818 // Done fixed damage bonus auras
7819 int32 DoneFlatBenefit = 0;
7820
7821 // ..done
7822 DoneFlatBenefit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE, creatureTypeMask);
7823
7824 // ..done
7825 // SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
7826
7827 // ..done (base at attack power for marked target and base at attack power for creature type)
7828 int32 APbonus = 0;
7829
7830 if (attType == RANGED_ATTACK)
7831 {
7833
7834 // ..done (base at attack power and creature type)
7836 }
7837 else
7838 {
7840
7841 // ..done (base at attack power and creature type)
7843 }
7844
7845 if (APbonus != 0) // Can be negative
7846 {
7847 bool const normalized = spellProto && spellProto->HasEffect(SPELL_EFFECT_NORMALIZED_WEAPON_DMG);
7848 DoneFlatBenefit += int32(APbonus / 14.0f * GetAPMultiplier(attType, normalized));
7849 }
7850
7851 // Done total percent damage auras
7852 float DoneTotalMod = 1.0f;
7853
7854 SpellSchoolMask schoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask;
7855
7856 // mods for SPELL_SCHOOL_MASK_NORMAL are already factored in base melee damage calculation
7857 if (!(schoolMask & SPELL_SCHOOL_MASK_NORMAL))
7858 {
7859 // Some spells don't benefit from pct done mods
7860 if (!spellProto || !spellProto->HasAttribute(SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS))
7861 {
7862 float maxModDamagePercentSchool = 0.0f;
7863 if (GetTypeId() == TYPEID_PLAYER)
7864 {
7865 for (uint32 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
7866 if (schoolMask & (1 << i))
7867 maxModDamagePercentSchool = std::max(maxModDamagePercentSchool, GetFloatValue(PLAYER_FIELD_MOD_DAMAGE_DONE_PCT + i));
7868 }
7869 else
7870 maxModDamagePercentSchool = GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, schoolMask);
7871
7872 DoneTotalMod *= maxModDamagePercentSchool;
7873 }
7874 }
7875
7877
7878 // bonus against aurastate
7879 DoneTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE, [victim](AuraEffect const* aurEff) -> bool
7880 {
7881 if (victim->HasAuraState(AuraStateType(aurEff->GetMiscValue())))
7882 return true;
7883 return false;
7884 });
7885
7886 // Add SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC percent bonus
7887 if (spellProto && spellProto->Mechanic)
7889
7890 // done scripted mod (take it from owner)
7891 Unit* owner = GetOwner() ? GetOwner() : this;
7892 AuraEffectList const& mOverrideClassScript = owner->GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
7893 for (AuraEffectList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
7894 {
7895 if (!(*i)->IsAffectingSpell(spellProto))
7896 continue;
7897
7898 switch ((*i)->GetMiscValue())
7899 {
7900 // Tundra Stalker
7901 // Merciless Combat
7902 case 7277:
7903 {
7904 // Merciless Combat
7905 if ((*i)->GetSpellInfo()->SpellIconID == 2656)
7906 {
7907 if (!victim->HealthAbovePct(35))
7908 AddPct(DoneTotalMod, (*i)->GetAmount());
7909 }
7910 // Tundra Stalker
7911 else
7912 {
7913 // Frost Fever (target debuff)
7914 if (victim->HasAura(55095))
7915 AddPct(DoneTotalMod, (*i)->GetAmount());
7916 }
7917 break;
7918 }
7919 // Rage of Rivendare
7920 case 7293:
7921 {
7923 AddPct(DoneTotalMod, (*i)->GetSpellInfo()->GetRank() * 2.0f);
7924 break;
7925 }
7926 // Marked for Death
7927 case 7598:
7928 case 7599:
7929 case 7600:
7930 case 7601:
7931 case 7602:
7932 {
7933 if (victim->GetAuraEffect(SPELL_AURA_MOD_STALKED, SPELLFAMILY_HUNTER, 0x400, 0, 0))
7934 AddPct(DoneTotalMod, (*i)->GetAmount());
7935 break;
7936 }
7937 // Dirty Deeds
7938 case 6427:
7939 case 6428:
7940 {
7941 if (victim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, spellProto, this))
7942 {
7943 // effect 0 has expected value but in negative state
7944 int32 bonus = -(*i)->GetBase()->GetEffect(0)->GetAmount();
7945 AddPct(DoneTotalMod, bonus);
7946 }
7947 break;
7948 }
7949 }
7950 }
7951
7952 // Custom scripted damage
7953 if (spellProto)
7954 {
7955 switch (spellProto->SpellFamilyName)
7956 {
7958 // Glacier Rot
7959 if (spellProto->SpellFamilyFlags[0] & 0x2 || spellProto->SpellFamilyFlags[1] & 0x6)
7961 if (victim->GetDiseasesByCaster(owner->GetGUID()) > 0)
7962 AddPct(DoneTotalMod, aurEff->GetAmount());
7963 break;
7964 }
7965 }
7966
7967 float tmpDamage = float(int32(pdamage) + DoneFlatBenefit) * DoneTotalMod;
7968
7969 // bonus result can be negative
7970 return uint32(std::max(tmpDamage, 0.0f));
7971}
7972
7973uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const* spellProto /*= nullptr*/, SpellSchoolMask damageSchoolMask /*= SPELL_SCHOOL_MASK_NORMAL*/)
7974{
7975 if (pdamage == 0)
7976 return 0;
7977
7978 int32 TakenFlatBenefit = 0;
7979
7980 // ..taken
7982
7983 if (attType != RANGED_ATTACK)
7985 else
7987
7988 if ((TakenFlatBenefit < 0) && (pdamage < static_cast<uint32>(-TakenFlatBenefit)))
7989 return 0;
7990
7991 // Taken total percent damage auras
7992 float TakenTotalMod = 1.0f;
7993
7994 // ..taken
7996
7997 // .. taken pct (special attacks)
7998 if (spellProto)
7999 {
8000 // From caster spells
8001 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER, [attacker, spellProto](AuraEffect const* aurEff) -> bool
8002 {
8003 if (aurEff->GetCasterGUID() == attacker->GetGUID() && aurEff->IsAffectingSpell(spellProto))
8004 return true;
8005 return false;
8006 });
8007
8008 // Mod damage from spell mechanic
8009 uint32 mechanicMask = spellProto->GetAllEffectsMechanicMask();
8010
8011 // Shred, Maul - "Effects which increase Bleed damage also increase Shred damage"
8012 if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x00008800)
8013 mechanicMask |= (1 << MECHANIC_BLEED);
8014
8015 if (mechanicMask)
8016 {
8017 TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
8018 {
8019 if (mechanicMask & uint32(1 << (aurEff->GetMiscValue())))
8020 return true;
8021 return false;
8022 });
8023 }
8024 }
8025
8026 // .. taken pct: dummy auras
8028 for (AuraEffectList::const_iterator i = mDummyAuras.begin(); i != mDummyAuras.end(); ++i)
8029 {
8030 switch ((*i)->GetSpellInfo()->SpellIconID)
8031 {
8032 // Cheat Death
8033 case 2109:
8034 if ((*i)->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL)
8035 {
8036 // Patch 2.4.3: The resilience required to reach the 90% damage reduction cap
8037 // is 22.5% critical strike damage reduction, or 444 resilience.
8038 // To calculate for 90%, we multiply the 100% by 4 (22.5% * 4 = 90%)
8039 float mod = -1.0f * GetMeleeCritDamageReduction(400);
8040 AddPct(TakenTotalMod, std::max(mod, float((*i)->GetAmount())));
8041 }
8042 break;
8043 }
8044 }
8045
8046 // .. taken pct: class scripts
8047 //*AuraEffectList const& mclassScritAuras = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
8048 //for (AuraEffectList::const_iterator i = mclassScritAuras.begin(); i != mclassScritAuras.end(); ++i)
8049 //{
8050 // switch ((*i)->GetMiscValue())
8051 // {
8052 // }
8053 //}*/
8054
8055 if (attType != RANGED_ATTACK)
8057 else
8059
8060 // Sanctified Wrath (bypass damage reduction)
8061 if (TakenTotalMod < 1.0f)
8062 {
8063 SpellSchoolMask const attackSchoolMask = spellProto ? spellProto->GetSchoolMask() : damageSchoolMask;
8064
8065 float damageReduction = 1.0f - TakenTotalMod;
8067 for (AuraEffect const* aurEff : casterIgnoreResist)
8068 {
8069 if (!(aurEff->GetMiscValue() & attackSchoolMask))
8070 continue;
8071
8072 AddPct(damageReduction, -aurEff->GetAmount());
8073 }
8074
8075 TakenTotalMod = 1.0f - damageReduction;
8076 }
8077
8078 float tmpDamage = float(pdamage + TakenFlatBenefit) * TakenTotalMod;
8079 return uint32(std::max(tmpDamage, 0.0f));
8080}
8081
8082void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
8083{
8084 if (apply)
8085 m_spellImmune[op].emplace(type, spellId);
8086 else
8087 {
8088 auto bounds = m_spellImmune[op].equal_range(type);
8089 for (auto itr = bounds.first; itr != bounds.second;)
8090 {
8091 if (itr->second == spellId)
8092 itr = m_spellImmune[op].erase(itr);
8093 else
8094 ++itr;
8095 }
8096 }
8097}
8098
8100{
8101 // normalized proc chance for weapon attack speed
8102 // (odd formula...)
8104 return (GetAttackTime(BASE_ATTACK) * 1.8f / 1000.0f);
8106 return (GetAttackTime(OFF_ATTACK) * 1.6f / 1000.0f);
8107 return 0;
8108}
8109
8110float Unit::GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const* spellProto) const
8111{
8112 // proc per minute chance calculation
8113 if (PPM <= 0)
8114 return 0.0f;
8115
8116 // Apply chance modifer aura
8117 if (spellProto)
8118 if (Player* modOwner = GetSpellModOwner())
8119 modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_PROC_PER_MINUTE, PPM);
8120
8121 return std::floor((WeaponSpeed * PPM) / 600.0f); // result is chance in percents (probability = Speed_in_sec * (PPM / 60))
8122}
8123
8124void Unit::Mount(uint32 mount, uint32 VehicleId, uint32 creatureEntry)
8125{
8126 if (mount)
8127 SetMountDisplayId(mount);
8128
8130
8131 if (Player* player = ToPlayer())
8132 {
8133 // mount as a vehicle
8134 if (VehicleId)
8135 {
8136 if (CreateVehicleKit(VehicleId, creatureEntry))
8137 {
8138 // Send others that we now have a vehicle
8140 data << GetPackGUID();
8141 data << uint32(VehicleId);
8142 SendMessageToSet(&data, true);
8143
8144 player->SendOnCancelExpectedVehicleRideAura();
8145
8146 // mounts can also have accessories
8148 }
8149 }
8150
8151 // unsummon pet
8152 Pet* pet = player->GetPet();
8153 if (pet)
8154 {
8156 // don't unsummon pet in arena but SetFlag UNIT_FLAG_STUNNED to disable pet's interface
8157 if (bg && bg->isArena())
8159 else
8160 player->UnsummonPetTemporaryIfAny();
8161 }
8162
8163 // if we have charmed npc, stun him also (everywhere)
8164 if (Unit* charm = player->GetCharmed())
8165 if (charm->GetTypeId() == TYPEID_UNIT)
8166 charm->SetUnitFlag(UNIT_FLAG_STUNNED);
8167
8168 player->SendMovementSetCollisionHeight(player->GetCollisionHeight());
8169 }
8170
8172}
8173
8175{
8176 if (!IsMounted())
8177 return;
8178
8181
8182 if (Player* thisPlayer = ToPlayer())
8183 thisPlayer->SendMovementSetCollisionHeight(thisPlayer->GetCollisionHeight());
8184
8185 WorldPacket data(SMSG_DISMOUNT, 8);
8186 data << GetPackGUID();
8187 SendMessageToSet(&data, true);
8188
8189 // dismount as a vehicle
8191 {
8192 // Send other players that we are no longer a vehicle
8194 data << GetPackGUID();
8195 data << uint32(0);
8196 ToPlayer()->SendMessageToSet(&data, true);
8197 // Remove vehicle from player
8199 }
8200
8202
8203 // only resummon old pet if the player is already added to a map
8204 // this prevents adding a pet to a not created map which would otherwise cause a crash
8205 // (it could probably happen when logging in after a previous crash)
8206 if (Player* player = ToPlayer())
8207 {
8208 if (Pet* pPet = player->GetPet())
8209 {
8210 if (pPet->HasUnitFlag(UNIT_FLAG_STUNNED) && !pPet->HasUnitState(UNIT_STATE_STUNNED))
8211 pPet->RemoveUnitFlag(UNIT_FLAG_STUNNED);
8212 }
8213 else
8214 player->ResummonPetTemporaryUnSummonedIfAny();
8215
8216 // if we have charmed npc, remove stun also
8217 if (Unit* charm = player->GetCharmed())
8218 if (charm->GetTypeId() == TYPEID_UNIT && charm->HasUnitFlag(UNIT_FLAG_STUNNED) && !charm->HasUnitState(UNIT_STATE_STUNNED))
8219 charm->RemoveUnitFlag(UNIT_FLAG_STUNNED);
8220 }
8221}
8222
8231
8233{
8234 if (!enemy)
8235 return;
8236
8237 if (CanHaveThreatList())
8238 m_threatManager.AddThreat(enemy, 0.0f, nullptr, true, true);
8239 else
8240 SetInCombatWith(enemy);
8241}
8242
8243void Unit::SetImmuneToAll(bool apply, bool keepCombat)
8244{
8245 if (apply)
8246 {
8249 if (!keepCombat)
8251 }
8252 else
8254}
8255
8256void Unit::SetImmuneToPC(bool apply, bool keepCombat)
8257{
8258 if (apply)
8259 {
8262 if (!keepCombat)
8263 {
8264 std::list<CombatReference*> toEnd;
8265 for (auto const& pair : m_combatManager.GetPvECombatRefs())
8266 if (pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8267 toEnd.push_back(pair.second);
8268 for (auto const& pair : m_combatManager.GetPvPCombatRefs())
8269 if (pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8270 toEnd.push_back(pair.second);
8271 for (CombatReference* ref : toEnd)
8272 ref->EndCombat();
8273 }
8274 }
8275 else
8277}
8278
8279void Unit::SetImmuneToNPC(bool apply, bool keepCombat)
8280{
8281 if (apply)
8282 {
8285 if (!keepCombat)
8286 {
8287 std::list<CombatReference*> toEnd;
8288 for (auto const& pair : m_combatManager.GetPvECombatRefs())
8289 if (!pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8290 toEnd.push_back(pair.second);
8291 for (auto const& pair : m_combatManager.GetPvPCombatRefs())
8292 if (!pair.second->GetOther(this)->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
8293 toEnd.push_back(pair.second);
8294 for (CombatReference* ref : toEnd)
8295 ref->EndCombat();
8296 }
8297 }
8298 else
8300}
8301
8303{
8305}
8306
8307bool Unit::isTargetableForAttack(bool checkFakeDeath) const
8308{
8309 if (!IsAlive())
8310 return false;
8311
8313 return false;
8314
8315 if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->IsGameMaster())
8316 return false;
8317
8318 return !HasUnitState(UNIT_STATE_UNATTACKABLE) && (!checkFakeDeath || !HasUnitState(UNIT_STATE_DIED));
8319}
8320
8322{
8323 int32 gain = 0;
8324
8325 if (dVal == 0)
8326 return 0;
8327
8328 int32 curHealth = (int32)GetHealth();
8329
8330 int32 val = dVal + curHealth;
8331 if (val <= 0)
8332 {
8333 SetHealth(0);
8334 return -curHealth;
8335 }
8336
8337 int32 maxHealth = (int32)GetMaxHealth();
8338
8339 if (val < maxHealth)
8340 {
8341 SetHealth(val);
8342 gain = val - curHealth;
8343 }
8344 else if (curHealth != maxHealth)
8345 {
8346 SetHealth(maxHealth);
8347 gain = maxHealth - curHealth;
8348 }
8349
8350 return gain;
8351}
8352
8354{
8355 int32 gain = 0;
8356
8357 if (dVal == 0)
8358 return 0;
8359
8360 int32 curHealth = (int32)GetHealth();
8361
8362 int32 val = dVal + curHealth;
8363 if (val <= 0)
8364 {
8365 return -curHealth;
8366 }
8367
8368 int32 maxHealth = (int32)GetMaxHealth();
8369
8370 if (val < maxHealth)
8371 gain = dVal;
8372 else if (curHealth != maxHealth)
8373 gain = maxHealth - curHealth;
8374
8375 return gain;
8376}
8377
8378// returns negative amount on power reduction
8379int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true*/)
8380{
8381 int32 gain = 0;
8382
8383 if (dVal == 0)
8384 return 0;
8385
8386 int32 curPower = (int32)GetPower(power);
8387
8388 int32 val = dVal + curPower;
8389 if (val <= GetMinPower(power))
8390 {
8391 SetPower(power, GetMinPower(power), withPowerUpdate);
8392 return -curPower;
8393 }
8394
8395 int32 maxPower = (int32)GetMaxPower(power);
8396
8397 if (val < maxPower)
8398 {
8399 SetPower(power, val, withPowerUpdate);
8400 gain = val - curPower;
8401 }
8402 else if (curPower != maxPower)
8403 {
8404 SetPower(power, maxPower, withPowerUpdate);
8405 gain = maxPower - curPower;
8406 }
8407
8408 return gain;
8409}
8410
8412{
8413 float f_BaseAttackTime = GetFloatValue(UNIT_FIELD_BASEATTACKTIME + AsUnderlyingType(att)) / m_modAttackSpeedPct[att];
8414 return (uint32)f_BaseAttackTime;
8415}
8416
8418{
8420 return true;
8421
8422 // Always seen by owner
8424 if (!guid.IsEmpty())
8425 if (seer->GetGUID() == guid)
8426 return true;
8427
8428 if (Player const* seerPlayer = seer->ToPlayer())
8429 if (Unit* owner = GetOwner())
8430 if (Player* ownerPlayer = owner->ToPlayer())
8431 if (ownerPlayer->IsGroupVisibleFor(seerPlayer))
8432 return true;
8433
8434 return false;
8435}
8436
8438{
8440 return true;
8441
8443 return true;
8444
8445 return false;
8446}
8447
8449{
8451}
8452
8462
8464{
8465 int32 main_speed_mod = 0;
8466 float stack_bonus = 1.0f;
8467 float non_stack_bonus = 1.0f;
8468
8469 switch (mtype)
8470 {
8471 // Only apply debuffs
8472 case MOVE_FLIGHT_BACK:
8473 case MOVE_RUN_BACK:
8474 case MOVE_SWIM_BACK:
8475 break;
8476 case MOVE_WALK:
8477 return;
8478 case MOVE_RUN:
8479 {
8480 if (IsMounted()) // Use on mount auras
8481 {
8485 }
8486 else
8487 {
8491 }
8492 break;
8493 }
8494 case MOVE_SWIM:
8495 {
8497 break;
8498 }
8499 case MOVE_FLIGHT:
8500 {
8501 if (GetTypeId() == TYPEID_UNIT && IsControlledByPlayer()) // not sure if good for pet
8502 {
8505
8506 // for some spells this mod is applied on vehicle owner
8507 int32 owner_speed_mod = 0;
8508
8509 if (Unit* owner = GetCharmer())
8510 owner_speed_mod = owner->GetMaxPositiveAuraModifier(SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED);
8511
8512 main_speed_mod = std::max(main_speed_mod, owner_speed_mod);
8513 }
8514 else if (IsMounted())
8515 {
8518 }
8519 else // Use not mount (shapeshift for example) auras (should stack)
8521
8523
8524 // Update speed for vehicle if available
8525 if (GetTypeId() == TYPEID_PLAYER && GetVehicle())
8527 break;
8528 }
8529 default:
8530 TC_LOG_ERROR("entities.unit", "Unit::UpdateSpeed: Unsupported move type ({})", mtype);
8531 return;
8532 }
8533
8534 // now we ready for speed calculation
8535 float speed = std::max(non_stack_bonus, stack_bonus);
8536 if (main_speed_mod)
8537 AddPct(speed, main_speed_mod);
8538
8539 switch (mtype)
8540 {
8541 case MOVE_RUN:
8542 case MOVE_SWIM:
8543 case MOVE_FLIGHT:
8544 {
8545 // Set creature speed rate
8546 if (GetTypeId() == TYPEID_UNIT)
8547 speed *= ToCreature()->GetCreatureTemplate()->speed_run; // at this point, MOVE_WALK is never reached
8548
8549 // Normalize speed by 191 aura SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED if need
8552 {
8553 if (Creature* creature = ToCreature())
8554 {
8555 uint32 immuneMask = creature->GetCreatureTemplate()->MechanicImmuneMask;
8556 if (immuneMask & (1 << (MECHANIC_SNARE - 1)) || immuneMask & (1 << (MECHANIC_DAZE - 1)))
8557 break;
8558 }
8559
8560 // Use speed from aura
8561 float max_speed = normalization / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8562 if (speed > max_speed)
8563 speed = max_speed;
8564 }
8565 break;
8566 }
8567 default:
8568 break;
8569 }
8570
8571 if (Creature* creature = ToCreature())
8572 {
8573 if (creature->HasUnitTypeMask(UNIT_MASK_MINION) && !creature->IsInCombat())
8574 {
8576 {
8577 Unit* followed = ASSERT_NOTNULL(dynamic_cast<AbstractFollower*>(GetMotionMaster()->GetCurrentMovementGenerator()))->GetTarget();
8578 if (followed && followed->GetGUID() == GetOwnerGUID() && !followed->IsInCombat())
8579 {
8580 float ownerSpeed = followed->GetSpeedRate(mtype);
8581 if (speed < ownerSpeed || creature->IsWithinDist3d(followed, 10.0f))
8582 speed = ownerSpeed;
8583 speed *= std::min(std::max(1.0f, 0.75f + (GetDistance(followed) - PET_FOLLOW_DIST) * 0.05f), 1.3f);
8584 }
8585 }
8586 }
8587 }
8588
8589 // Apply strongest slow aura mod to speed
8591 if (slow)
8592 AddPct(speed, slow);
8593
8594 if (float minSpeedMod = (float)GetMaxPositiveAuraModifier(SPELL_AURA_MOD_MINIMUM_SPEED))
8595 {
8596 float baseMinSpeed = 1.0f;
8597 if (!GetOwnerGUID().IsPlayer() && !IsHunterPet() && GetTypeId() == TYPEID_UNIT)
8598 baseMinSpeed = ToCreature()->GetCreatureTemplate()->speed_run;
8599
8600 float min_speed = CalculatePct(baseMinSpeed, minSpeedMod);
8601 if (speed < min_speed)
8602 speed = min_speed;
8603 }
8604
8605 SetSpeedRate(mtype, speed);
8606}
8607
8609{
8610 return m_speed_rate[mtype]*(IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8611}
8612
8613void Unit::SetSpeed(UnitMoveType mtype, float newValue)
8614{
8615 SetSpeedRate(mtype, newValue / (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]));
8616}
8617
8618void Unit::SetSpeedRate(UnitMoveType mtype, float rate)
8619{
8620 if (rate < 0)
8621 rate = 0.0f;
8622
8623 // Update speed only on change
8625 if (m_speed_rate[mtype] == rate && !HasPendingMovementChange(changeType)) //todo: is the "!HasPendingMovementChange" part necessary here?
8626 return;
8627
8628 float newSpeedFlat = rate * (IsControlledByPlayer() ? playerBaseMoveSpeed[mtype] : baseMoveSpeed[mtype]);
8629 if (IsMovedByClient() && IsInWorld())
8630 MovementPacketSender::SendSpeedChangeToMover(this, mtype, newSpeedFlat);
8631 else if (IsMovedByClient() && !IsInWorld()) // (1)
8632 SetSpeedRateReal(mtype, rate);
8633 else // <=> if(!IsMovedByPlayer())
8634 {
8635 SetSpeedRateReal(mtype, rate);
8636 MovementPacketSender::SendSpeedChangeToAll(this, mtype, newSpeedFlat);
8637 }
8638
8639 // explaination of (1):
8640 // If the player is not in the world yet, it won't reply to the packets requiring an ack. And once the player is in the world, next time a movement
8641 // packet which requires an ack is sent to the client (change of speed for example), the client is kicked from the
8642 // server on the ground that it should have replied to the first packet first. That line is a hacky fix
8643 // in the sense that it doesn't work like that in retail since buffs are applied only after the player has been
8644 // initialized in the world. cf description of PR #18771
8645}
8646
8648{
8649 if (!IsInCombat() && ToPlayer())
8650 if (Pet* pet = ToPlayer()->GetPet())
8651 pet->SetSpeedRate(mtype, rate);
8652
8653 m_speed_rate[mtype] = rate;
8655}
8656
8658{
8659 while (!m_followingMe.empty())
8660 (*m_followingMe.begin())->SetTarget(nullptr);
8661}
8662
8664{
8666}
8667
8669{
8670 // Death state needs to be updated before RemoveAllAurasOnDeath() is called, to prevent entering combat
8671 m_deathState = s;
8672
8673 bool isOnVehicle = GetVehicle() != nullptr;
8674
8675 if (s != ALIVE && s != JUST_RESPAWNED)
8676 {
8677 CombatStop();
8678 ClearComboPointHolders(); // any combo points pointed to unit lost at it death
8679
8680 if (IsNonMeleeSpellCast(false))
8682
8683 ExitVehicle(); // Exit vehicle before calling RemoveAllControlled
8684 // vehicles use special type of charm that is not removed by the next function
8685 // triggering an assert
8689 }
8690
8691 if (s == JUST_DIED)
8692 {
8693 // remove aurastates allowing special moves
8696
8697 // Don't clear the movement if the Unit was on a vehicle as we are exiting now
8698 if (!isOnVehicle)
8699 {
8700 if (GetMotionMaster()->StopOnDeath())
8701 DisableSpline();
8702 }
8703
8704 // without this when removing IncreaseMaxHealth aura player may stuck with 1 hp
8705 // do not why since in IncreaseMaxHealth currenthealth is checked
8706 SetHealth(0);
8707 SetPower(GetPowerType(), 0);
8709
8710 // players in instance don't have ZoneScript, but they have InstanceScript
8711 if (ZoneScript* zoneScript = GetZoneScript() ? GetZoneScript() : GetInstanceScript())
8712 zoneScript->OnUnitDeath(this);
8713 }
8714 else if (s == JUST_RESPAWNED)
8715 RemoveUnitFlag(UNIT_FLAG_SKINNABLE); // clear skinnable for creature and player (at battleground)
8716}
8717
8718//======================================================================
8719
8724
8730
8731void Unit::AtTargetAttacked(Unit* target, bool canInitialAggro)
8732{
8733 if (!target->IsEngaged() && !canInitialAggro)
8734 return;
8735 target->EngageWithTarget(this);
8736 if (Unit* targetOwner = target->GetCharmerOrOwner())
8737 targetOwner->EngageWithTarget(this);
8738
8739 //Patch 3.0.8: All player spells which cause a creature to become aggressive to you will now also immediately cause the creature to be tapped.
8740 if (Creature* creature = target->ToCreature())
8741 if (!creature->hasLootRecipient() && GetTypeId() == TYPEID_PLAYER)
8742 creature->SetLootRecipient(this);
8743
8745 Player* targetPlayerOwner = target->GetCharmerOrOwnerPlayerOrPlayerItself();
8746 if (myPlayerOwner && targetPlayerOwner && !(myPlayerOwner->duel && myPlayerOwner->duel->Opponent == targetPlayerOwner))
8747 {
8748 myPlayerOwner->UpdatePvP(true);
8749 myPlayerOwner->SetContestedPvP(targetPlayerOwner);
8751 }
8752}
8753
8755{
8756 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
8757
8758 bool state = false;
8759 for (Unit* minion : m_Controlled)
8760 if (minion->IsInCombat())
8761 {
8762 state = true;
8763 break;
8764 }
8765
8766 if (state)
8768 else
8770}
8771
8772//======================================================================
8773
8775{
8776 DiminishingReturn const& diminish = m_Diminishing[group];
8777 if (!diminish.hitCount)
8778 return DIMINISHING_LEVEL_1;
8779
8780 // If last spell was cast more than 15 seconds ago - reset level
8781 if (!diminish.stack && GetMSTimeDiffToNow(diminish.hitTime) > 15000)
8782 return DIMINISHING_LEVEL_1;
8783
8784 return DiminishingLevels(diminish.hitCount);
8785}
8786
8787void Unit::IncrDiminishing(SpellInfo const* auraSpellInfo, bool triggered)
8788{
8789 DiminishingGroup group = auraSpellInfo->GetDiminishingReturnsGroupForSpell(triggered);
8790 uint32 currentLevel = GetDiminishing(group);
8791 uint32 const maxLevel = auraSpellInfo->GetDiminishingReturnsMaxLevel(triggered);
8792
8793 DiminishingReturn& diminish = m_Diminishing[group];
8794 if (currentLevel < maxLevel)
8795 diminish.hitCount = currentLevel + 1;
8796}
8797
8798bool Unit::ApplyDiminishingToDuration(SpellInfo const* auraSpellInfo, bool triggered, int32& duration, WorldObject* caster, DiminishingLevels previousLevel) const
8799{
8800 DiminishingGroup const group = auraSpellInfo->GetDiminishingReturnsGroupForSpell(triggered);
8801 if (duration == -1 || group == DIMINISHING_NONE)
8802 return true;
8803
8804 int32 const limitDuration = auraSpellInfo->GetDiminishingReturnsLimitDuration(triggered);
8805
8806 // test pet/charm masters instead pets/charmeds
8807 Unit const* targetOwner = GetCharmerOrOwner();
8808 Unit const* casterOwner = caster->GetCharmerOrOwner();
8809
8810 // Duration of crowd control abilities on pvp target is limited by 10 sec. (2.2.0)
8811 if (limitDuration > 0 && duration > limitDuration)
8812 {
8813 Unit const* target = targetOwner ? targetOwner : this;
8814 WorldObject const* source = casterOwner ? casterOwner : caster;
8815
8816 if (target->IsAffectedByDiminishingReturns() && source->GetTypeId() == TYPEID_PLAYER)
8817 duration = limitDuration;
8818 }
8819
8820 float mod = 1.0f;
8821 if (group == DIMINISHING_TAUNT)
8822 {
8823 if (GetTypeId() == TYPEID_UNIT && (ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS))
8824 {
8825 DiminishingLevels diminish = previousLevel;
8826 switch (diminish)
8827 {
8828 case DIMINISHING_LEVEL_1: break;
8829 case DIMINISHING_LEVEL_2: mod = 0.65f; break;
8830 case DIMINISHING_LEVEL_3: mod = 0.4225f; break;
8831 case DIMINISHING_LEVEL_4: mod = 0.274625f; break;
8832 case DIMINISHING_LEVEL_TAUNT_IMMUNE: mod = 0.0f; break;
8833 default: break;
8834 }
8835 }
8836 }
8837 // Some diminishings applies to mobs too (for example, Stun)
8838 else if (auraSpellInfo->GetDiminishingReturnsGroupType(triggered) == DRTYPE_ALL ||
8839 (auraSpellInfo->GetDiminishingReturnsGroupType(triggered) == DRTYPE_PLAYER &&
8840 (targetOwner ? targetOwner->IsAffectedByDiminishingReturns() : IsAffectedByDiminishingReturns())))
8841 {
8842 DiminishingLevels diminish = previousLevel;
8843 switch (diminish)
8844 {
8845 case DIMINISHING_LEVEL_1: break;
8846 case DIMINISHING_LEVEL_2: mod = 0.5f; break;
8847 case DIMINISHING_LEVEL_3: mod = 0.25f; break;
8848 case DIMINISHING_LEVEL_IMMUNE: mod = 0.0f; break;
8849 default: 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
8908
8910{
8912 return form == FORM_CAT || form == FORM_BEAR || form == FORM_DIREBEAR;
8913}
8914
8916{
8917 if (SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(GetTransformSpell()))
8918 if (transformSpellInfo->HasAttribute(SPELL_ATTR0_CASTABLE_WHILE_MOUNTED))
8919 return false;
8920
8921 if (ShapeshiftForm form = GetShapeshiftForm())
8922 {
8923 SpellShapeshiftFormEntry const* shapeshift = sSpellShapeshiftFormStore.LookupEntry(form);
8924 if (!shapeshift)
8925 return true;
8926
8927 if (!(shapeshift->Flags & 0x1))
8928 return true;
8929 }
8930
8932 return false;
8933
8934 CreatureDisplayInfoEntry const* display = sCreatureDisplayInfoStore.LookupEntry(GetDisplayId());
8935 if (!display)
8936 return true;
8937
8939 if (!displayExtra)
8940 return true;
8941
8942 CreatureModelDataEntry const* model = sCreatureModelDataStore.LookupEntry(display->ModelID);
8943 ChrRacesEntry const* race = sChrRacesStore.LookupEntry(displayExtra->DisplayRaceID);
8944
8945 if (model && !(model->HasFlag(CREATURE_MODEL_DATA_FLAGS_CAN_MOUNT)))
8946 if (race && !(race->HasFlag(CHRRACES_FLAGS_CAN_MOUNT)))
8947 return true;
8948
8949 return false;
8950}
8951
8952/*#######################################
8953######## ########
8954######## STAT SYSTEM ########
8955######## ########
8956#######################################*/
8957
8958void ApplyPercentModFloatVar(float& var, float val, bool apply)
8959{
8960 var *= (apply ? (100.0f + val) / 100.0f : 100.0f / (100.0f + val));
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:
8977 case TOTAL_VALUE:
8978 m_auraFlatModifiersGroup[unitMod][modifierType] += apply ? amount : -amount;
8979 break;
8980 default:
8981 break;
8982 }
8983
8984 UpdateUnitMod(unitMod);
8985}
8986
8987void Unit::ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float pct)
8988{
8989 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
8990 {
8991 TC_LOG_ERROR("entities.unit", "ERROR in ApplyStatPctModifier(): non-existing UnitMods or wrong UnitModifierType!");
8992 return;
8993 }
8994
8995 if (!pct)
8996 return;
8997
8998 switch (modifierType)
8999 {
9000 case BASE_PCT:
9001 case TOTAL_PCT:
9002 AddPct(m_auraPctModifiersGroup[unitMod][modifierType], pct);
9003 break;
9004 default:
9005 break;
9006 }
9007
9008 UpdateUnitMod(unitMod);
9009}
9010
9011void Unit::SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
9012{
9013 if (m_auraFlatModifiersGroup[unitMod][modifierType] == val)
9014 return;
9015
9016 m_auraFlatModifiersGroup[unitMod][modifierType] = val;
9017 UpdateUnitMod(unitMod);
9018}
9019
9020void Unit::SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
9021{
9022 if (m_auraPctModifiersGroup[unitMod][modifierType] == val)
9023 return;
9024
9025 m_auraPctModifiersGroup[unitMod][modifierType] = val;
9026 UpdateUnitMod(unitMod);
9027}
9028
9030{
9031 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_FLAT_END)
9032 {
9033 TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
9034 return 0.0f;
9035 }
9036
9037 return m_auraFlatModifiersGroup[unitMod][modifierType];
9038}
9039
9041{
9042 if (unitMod >= UNIT_MOD_END || modifierType >= MODIFIER_TYPE_PCT_END)
9043 {
9044 TC_LOG_ERROR("entities.unit", "attempt to access non-existing modifier value from UnitMods!");
9045 return 1.0f;
9046 }
9047
9048 return m_auraPctModifiersGroup[unitMod][modifierType];
9049}
9050
9052{
9053 if (!CanModifyStats())
9054 return;
9055
9056 switch (unitMod)
9057 {
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:
9071 case UNIT_MOD_HAPPINESS:
9072 case UNIT_MOD_RUNE:
9074
9081
9085
9086 default:
9087 break;
9088 }
9089}
9090
9091void Unit::HandleAttackPowerModifier(AttackPowerModIndex index, AttackPowerModType modifierType, float amount, bool apply)
9092{
9093 if (index >= AttackPowerModIndex::End || modifierType >= AttackPowerModType::End)
9094 {
9095 TC_LOG_ERROR("entities.unit", "ERROR in HandleAttackPowerModifier(): non-existing AttackPowerModIndex or wrong AttackPowerModType!");
9096 return;
9097 }
9098
9099 switch (modifierType)
9100 {
9102 ApplyPercentModFloatVar(m_attackPowerMods[uint32(index)][uint32(modifierType)], amount, apply);
9103 break;
9104 default:
9105 m_attackPowerMods[uint32(index)][uint32(modifierType)] += apply ? amount : -amount;
9106 break;
9107 }
9108
9109 if (!CanModifyStats())
9110 return;
9111
9113}
9114
9116{
9117 if (index >= AttackPowerModIndex::End || modifierType >= AttackPowerModType::End)
9118 {
9119 TC_LOG_ERROR("entities.unit", "ERROR in GetAttackPowerModifierValue(): non-existing AttackPowerModIndex or wrong AttackPowerModType!");
9120 return 0.0f;
9121 }
9122
9123 return m_attackPowerMods[uint32(index)][uint32(modifierType)];
9124}
9125
9126void Unit::UpdateDamageDoneMods(WeaponAttackType attackType, int32 /*skipEnchantSlot = -1*/)
9127{
9128 UnitMods unitMod;
9129 switch (attackType)
9130 {
9131 case BASE_ATTACK:
9132 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
9133 break;
9134 case OFF_ATTACK:
9135 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
9136 break;
9137 case RANGED_ATTACK:
9138 unitMod = UNIT_MOD_DAMAGE_RANGED;
9139 break;
9140 default:
9141 ABORT();
9142 break;
9143 }
9144
9145 float amount = GetTotalAuraModifier(SPELL_AURA_MOD_DAMAGE_DONE, [&](AuraEffect const* aurEff) -> bool
9146 {
9147 if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
9148 return false;
9149
9150 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9151 });
9152
9153 SetStatFlatModifier(unitMod, TOTAL_VALUE, amount);
9154}
9155
9161
9163{
9164 float factor;
9165 UnitMods unitMod;
9166 switch (attackType)
9167 {
9168 case BASE_ATTACK:
9169 factor = 1.0f;
9170 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
9171 break;
9172 case OFF_ATTACK:
9173 // off hand has 50% penalty
9174 factor = 0.5f;
9175 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
9176 break;
9177 case RANGED_ATTACK:
9178 factor = 1.0f;
9179 unitMod = UNIT_MOD_DAMAGE_RANGED;
9180 break;
9181 default:
9182 ABORT();
9183 break;
9184 }
9185
9186 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_DAMAGE_PERCENT_DONE, [attackType, this](AuraEffect const* aurEff) -> bool
9187 {
9188 if (!(aurEff->GetMiscValue() & SPELL_SCHOOL_MASK_NORMAL))
9189 return false;
9190
9191 return CheckAttackFitToAuraRequirement(attackType, aurEff);
9192 });
9193
9194 if (attackType == OFF_ATTACK)
9195 factor *= GetTotalAuraMultiplier(SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT, std::bind(&Unit::CheckAttackFitToAuraRequirement, this, attackType, std::placeholders::_1));
9196
9197 SetStatPctModifier(unitMod, TOTAL_PCT, factor);
9198}
9199
9205
9207{
9209
9210 // value = ((base_value * base_pct) + total_value) * total_pct
9211 float value = GetFlatModifierValue(unitMod, BASE_VALUE) + GetCreateStat(stat);
9212 value *= GetPctModifierValue(unitMod, BASE_PCT);
9213 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9214 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9215
9216 return value;
9217}
9218
9220{
9221 if (unitMod >= UNIT_MOD_END)
9222 {
9223 TC_LOG_ERROR("entities.unit", "attempt to access non-existing UnitMods in GetTotalAuraModValue()!");
9224 return 0.0f;
9225 }
9226
9227 float value = GetFlatModifierValue(unitMod, BASE_VALUE);
9228 value *= GetPctModifierValue(unitMod, BASE_PCT);
9229 value += GetFlatModifierValue(unitMod, TOTAL_VALUE);
9230 value *= GetPctModifierValue(unitMod, TOTAL_PCT);
9231
9232 return value;
9233}
9234
9236{
9238
9239 switch (unitMod)
9240 {
9241 case UNIT_MOD_RESISTANCE_HOLY: school = SPELL_SCHOOL_HOLY; break;
9242 case UNIT_MOD_RESISTANCE_FIRE: school = SPELL_SCHOOL_FIRE; break;
9243 case UNIT_MOD_RESISTANCE_NATURE: school = SPELL_SCHOOL_NATURE; break;
9244 case UNIT_MOD_RESISTANCE_FROST: school = SPELL_SCHOOL_FROST; break;
9245 case UNIT_MOD_RESISTANCE_SHADOW: school = SPELL_SCHOOL_SHADOW; break;
9246 case UNIT_MOD_RESISTANCE_ARCANE: school = SPELL_SCHOOL_ARCANE; break;
9247
9248 default:
9249 break;
9250 }
9251
9252 return school;
9253}
9254
9256{
9257 Stats stat = STAT_STRENGTH;
9258
9259 switch (unitMod)
9260 {
9261 case UNIT_MOD_STAT_STRENGTH: stat = STAT_STRENGTH; break;
9262 case UNIT_MOD_STAT_AGILITY: stat = STAT_AGILITY; break;
9263 case UNIT_MOD_STAT_STAMINA: stat = STAT_STAMINA; break;
9264 case UNIT_MOD_STAT_INTELLECT: stat = STAT_INTELLECT; break;
9265 case UNIT_MOD_STAT_SPIRIT: stat = STAT_SPIRIT; break;
9266
9267 default:
9268 break;
9269 }
9270
9271 return stat;
9272}
9273
9275{
9276 switch (unitMod)
9277 {
9278 case UNIT_MOD_RAGE: return POWER_RAGE;
9279 case UNIT_MOD_FOCUS: return POWER_FOCUS;
9280 case UNIT_MOD_ENERGY: return POWER_ENERGY;
9282 case UNIT_MOD_RUNE: return POWER_RUNE;
9284 default:
9285 case UNIT_MOD_MANA: return POWER_MANA;
9286 }
9287}
9288
9306
9307float Unit::GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type, uint8 damageIndex /*= 0*/) const
9308{
9309 if (attType == OFF_ATTACK && !haveOffhandWeapon())
9310 return 0.0f;
9311
9312 return m_weaponDamage[attType][type][damageIndex];
9313}
9314
9320
9321void Unit::SetLevel(uint8 lvl, bool sendUpdate/* = true*/)
9322{
9324
9325 if (!sendUpdate)
9326 return;
9327
9328 if (Player* player = ToPlayer())
9329 {
9330 // group update
9331 if (player->GetGroup())
9332 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL);
9333
9334 sCharacterCache->UpdateCharacterLevel(GetGUID(), lvl);
9335 }
9336}
9337
9339{
9341 val = 0;
9342 else if (GetTypeId() == TYPEID_PLAYER && getDeathState() == DEAD)
9343 val = 1;
9344 else
9345 {
9346 uint32 maxHealth = GetMaxHealth();
9347 if (maxHealth < val)
9348 val = maxHealth;
9349 }
9350
9352
9353 // group update
9354 if (Player* player = ToPlayer())
9355 {
9356 if (player->GetGroup())
9357 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_HP);
9358 }
9359 else if (Pet* pet = ToCreature()->ToPet())
9360 {
9361 if (pet->isControlled())
9362 {
9363 Unit* owner = GetOwner();
9364 if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
9366 }
9367 }
9368}
9369
9371{
9372 if (!val)
9373 val = 1;
9374
9375 uint32 health = GetHealth();
9377
9378 // group update
9379 if (GetTypeId() == TYPEID_PLAYER)
9380 {
9381 if (ToPlayer()->GetGroup())
9383 }
9384 else if (Pet* pet = ToCreature()->ToPet())
9385 {
9386 if (pet->isControlled())
9387 {
9388 Unit* owner = GetOwner();
9389 if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
9391 }
9392 }
9393
9394 if (val < health)
9395 SetHealth(val);
9396}
9397
9398void Unit::SetPower(Powers power, uint32 val, bool withPowerUpdate /*= true*/, bool force /*= false*/)
9399{
9400 if (!force && GetPower(power) == val)
9401 return;
9402
9403 uint32 maxPower = GetMaxPower(power);
9404 if (maxPower < val)
9405 val = maxPower;
9406
9408
9409 if (withPowerUpdate)
9410 {
9411 WorldPacket data(SMSG_POWER_UPDATE, 8 + 1 + 4);
9412 data << GetPackGUID();
9413 data << uint8(power);
9414 data << uint32(val);
9416 }
9417
9418 // group update
9419 if (Player* player = ToPlayer())
9420 {
9421 if (player->GetGroup())
9422 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_CUR_POWER);
9423 }
9424 else if (Pet* pet = ToCreature()->ToPet())
9425 {
9426 if (pet->isControlled())
9427 {
9428 Unit* owner = GetOwner();
9429 if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
9431 }
9432
9433 // Update the pet's character sheet with happiness damage bonus
9434 if (pet->getPetType() == HUNTER_PET && power == POWER_HAPPINESS)
9435 pet->UpdateDamagePhysical(BASE_ATTACK);
9436 }
9437}
9438
9440{
9441 uint32 cur_power = GetPower(power);
9443
9444 // group update
9445 if (GetTypeId() == TYPEID_PLAYER)
9446 {
9447 if (ToPlayer()->GetGroup())
9449 }
9450 else if (Pet* pet = ToCreature()->ToPet())
9451 {
9452 if (pet->isControlled())
9453 {
9454 Unit* owner = GetOwner();
9455 if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
9457 }
9458 }
9459
9460 if (val < cur_power)
9461 SetPower(power, val);
9462}
9463
9465{
9466 // Only hunter pets have POWER_FOCUS and POWER_HAPPINESS
9467 switch (power)
9468 {
9469 case POWER_MANA:
9470 return GetCreateMana();
9471 case POWER_RAGE:
9472 return 1000;
9473 case POWER_FOCUS:
9474 return (GetTypeId() != TYPEID_UNIT || !ToCreature()->IsPet() || ToPet()->getPetType() != HUNTER_PET) ? 0 : 100;
9475 case POWER_ENERGY:
9476 return 100;
9477 case POWER_HAPPINESS:
9478 return (GetTypeId() != TYPEID_UNIT || !ToCreature()->IsPet() || ToPet()->getPetType() != HUNTER_PET) ? 0 : 1050000;
9479 case POWER_RUNIC_POWER:
9480 return 1000;
9481 case POWER_RUNE:
9482 case POWER_HEALTH:
9483 return 0;
9484 default:
9485 break;
9486 }
9487
9488 return 0;
9489}
9490
9492{
9493 if (UnitAI* ai = GetAI())
9494 {
9495 m_aiLocked = true;
9496 ai->UpdateAI(diff);
9497 m_aiLocked = false;
9498 }
9499}
9500
9502{
9503 i_AIs.emplace(newAI);
9504}
9505
9507{
9508 PushAI(newAI);
9509 RefreshAI();
9510}
9511
9513{
9514 if (!i_AIs.empty())
9515 {
9516 i_AIs.pop();
9517 return true;
9518 }
9519 else
9520 return false;
9521}
9522
9524{
9525 ASSERT(!m_aiLocked, "Tried to change current AI during UpdateAI()");
9526 if (i_AIs.empty())
9527 i_AI = nullptr;
9528 else
9529 i_AI = i_AIs.top();
9530}
9531
9533{
9534 bool const charmed = IsCharmed();
9535
9536 if (charmed)
9538 else
9539 {
9541 PushAI(GetScheduledChangeAI()); //This could actually be PopAI() to get the previous AI but it's required atm to trigger UpdateCharmAI()
9542 }
9543}
9544
9546{
9547 // Keep popping the stack until we either reach the bottom or find a valid AI
9548 while (PopAI())
9549 if (GetTopAI() && dynamic_cast<ScheduledChangeAI*>(GetTopAI()) == nullptr)
9550 return;
9551}
9552
9554{
9555 if (Creature* creature = ToCreature())
9556 return new ScheduledChangeAI(creature);
9557 else
9558 return nullptr;
9559}
9560
9562{
9563 if (UnitAI* ai = GetAI())
9564 return dynamic_cast<ScheduledChangeAI*>(ai) != nullptr;
9565 else
9566 return true;
9567}
9568
9570{
9571 if (IsInWorld())
9572 return;
9573
9576}
9577
9579{
9580 // cleanup
9581 ASSERT(GetGUID());
9582
9583 if (IsInWorld())
9584 {
9586 if (UnitAI* ai = GetAI())
9587 ai->OnDespawn();
9588
9589 if (IsVehicle())
9591
9595
9598
9599 ExitVehicle(); // Remove applied auras with SPELL_AURA_CONTROL_VEHICLE
9602
9604
9606
9607 if (IsCharmed())
9608 RemoveCharmedBy(nullptr);
9609
9610 ASSERT(!GetCharmedGUID(), "Unit %u has charmed guid when removed from world", GetEntry());
9611 ASSERT(!GetCharmerGUID(), "Unit %u has charmer guid when removed from world", GetEntry());
9612
9613 if (Unit* owner = GetOwner())
9614 {
9615 if (owner->m_Controlled.find(this) != owner->m_Controlled.end())
9616 {
9617 TC_LOG_FATAL("entities.unit", "Unit {} is in controlled list of {} when removed from world", GetEntry(), owner->GetEntry());
9618 ABORT();
9619 }
9620 }
9621
9624 }
9625}
9626
9628{
9629 // This needs to be before RemoveFromWorld to make GetCaster() return a valid pointer on aura removal
9631
9632 if (IsInWorld())
9634 else
9635 {
9636 // cleanup that must happen even if not in world
9637 if (IsVehicle())
9639 }
9640
9641 ASSERT(GetGUID());
9642
9643 // A unit may be in removelist and not in world, but it is still in grid
9644 // and may have some references during delete
9647
9648 if (finalCleanup)
9649 m_cleanupDone = true;
9650
9651 CombatStop();
9654}
9655
9656void Unit::CleanupsBeforeDelete(bool finalCleanup)
9657{
9658 CleanupBeforeRemoveFromMap(finalCleanup);
9659
9661}
9662
9664{
9665 if (IsCharmed())
9666 {
9667 UnitAI* newAI = nullptr;
9668 if (GetTypeId() == TYPEID_PLAYER)
9669 {
9670 if (Unit* charmer = GetCharmer())
9671 {
9672 // first, we check if the creature's own AI specifies an override playerai for its owned players
9673 if (Creature* creatureCharmer = charmer->ToCreature())
9674 {
9675 if (CreatureAI* charmerAI = creatureCharmer->AI())
9676 newAI = charmerAI->GetAIForCharmedPlayer(ToPlayer());
9677 }
9678 else
9679 TC_LOG_ERROR("entities.unit.ai", "Attempt to assign charm AI to player {} who is charmed by non-creature {}.", GetGUID().ToString(), GetCharmerGUID().ToString());
9680 }
9681 if (!newAI) // otherwise, we default to the generic one
9682 newAI = new SimpleCharmedPlayerAI(ToPlayer());
9683 }
9684 else
9685 {
9687 if (isPossessed() || IsVehicle())
9688 newAI = new PossessedAI(ToCreature());
9689 else
9690 newAI = new PetAI(ToCreature());
9691 }
9692
9693 ASSERT(newAI);
9694 SetAI(newAI);
9695 newAI->OnCharmed(true);
9696 }
9697 else
9698 {
9700 // Hack: this is required because we want to call OnCharmed(true) on the restored AI
9701 RefreshAI();
9702 if (UnitAI* ai = GetAI())
9703 ai->OnCharmed(true);
9704 }
9705}
9706
9708{
9709 if (!m_charmInfo)
9710 m_charmInfo = new CharmInfo(this);
9711
9712 return m_charmInfo;
9713}
9714
9716{
9717 if (!m_charmInfo)
9718 return;
9719
9721 delete m_charmInfo;
9722 m_charmInfo = nullptr;
9723}
9724
9726: _unit(unit), _CommandState(COMMAND_FOLLOW), _petnumber(0), _oldReactState(REACT_PASSIVE),
9727 _isCommandAttack(false), _isCommandFollow(false), _isAtStay(false), _isFollowing(false), _isReturning(false),
9728 _stayX(0.0f), _stayY(0.0f), _stayZ(0.0f)
9729{
9730 for (uint8 i = 0; i < MAX_SPELL_CHARM; ++i)
9731 _charmspells[i].SetActionAndType(0, ACT_DISABLED);
9732
9733 if (Creature* creature = _unit->ToCreature())
9734 {
9735 _oldReactState = creature->GetReactState();
9736 creature->SetReactState(REACT_PASSIVE);
9737 }
9738}
9739
9741
9743{
9744 if (Creature* creature = _unit->ToCreature())
9745 creature->SetReactState(_oldReactState);
9746}
9747
9749{
9750 // the first 3 SpellOrActions are attack, follow and stay
9753
9754 // middle 4 SpellOrActions are spells/special attacks/abilities
9757
9758 // last 3 SpellOrActions are reactions
9761}
9762
9772
9774{
9775 if (_unit->GetTypeId() == TYPEID_UNIT)
9776 {
9777 // Adding switch until better way is found. Malcrom
9778 // Adding entrys to this switch will prevent COMMAND_ATTACK being added to pet bar.
9779 switch (_unit->GetEntry())
9780 {
9781 case 23575: // Mindless Abomination
9782 case 24783: // Trained Rock Falcon
9783 case 27664: // Crashin' Thrashin' Racer
9784 case 40281: // Crashin' Thrashin' Racer
9785 case 28511: // Eye of Acherus
9786 break;
9787 default:
9789 break;
9790 }
9791
9792 for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)
9793 {
9794 uint32 spellId = _unit->ToCreature()->m_spells[i];
9795 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
9796 if (spellInfo)
9797 {
9798 if (spellInfo->IsPassive())
9799 _unit->CastSpell(_unit, spellInfo->Id, true);
9800 else
9802 }
9803 }
9804 }
9805 else
9807}
9808
9810{
9811 if (_unit->GetTypeId() == TYPEID_PLAYER) // charmed players don't have spells
9812 {
9814 return;
9815 }
9816
9818
9819 for (uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
9820 {
9821 uint32 spellId = _unit->ToCreature()->m_spells[x];
9822 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
9823
9824 if (!spellInfo)
9825 {
9827 continue;
9828 }
9829
9830 if (spellInfo->IsPassive())
9831 {
9832 _unit->CastSpell(_unit, spellInfo->Id, true);
9834 }
9835 else
9836 {
9838
9839 ActiveStates newstate = ACT_PASSIVE;
9840
9841 if (!spellInfo->IsAutocastable())
9842 newstate = ACT_PASSIVE;
9843 else
9844 {
9845 if (spellInfo->NeedsExplicitUnitTarget())
9846 {
9847 newstate = ACT_ENABLED;
9848 ToggleCreatureAutocast(spellInfo, true);
9849 }
9850 else
9851 newstate = ACT_DISABLED;
9852 }
9853
9854 AddSpellToActionBar(spellInfo, newstate);
9855 }
9856 }
9857}
9858
9859bool CharmInfo::AddSpellToActionBar(SpellInfo const* spellInfo, ActiveStates newstate, uint8 preferredSlot)
9860{
9861 uint32 spell_id = spellInfo->Id;
9862 uint32 first_id = spellInfo->GetFirstRankSpell()->Id;
9863
9864 ASSERT(preferredSlot < MAX_UNIT_ACTION_BAR_INDEX);
9865 // new spell rank can be already listed
9866 for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
9867 {
9868 if (uint32 action = PetActionBar[i].GetAction())
9869 {
9870 if (PetActionBar[i].IsActionBarForSpell() && sSpellMgr->GetFirstSpellInChain(action) == first_id)
9871 {
9872 PetActionBar[i].SetAction(spell_id);
9873 return true;
9874 }
9875 }
9876 }
9877
9878 // or use empty slot in other case
9879 for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
9880 {
9881 uint8 j = (preferredSlot + i) % MAX_UNIT_ACTION_BAR_INDEX;
9882 if (!PetActionBar[j].GetAction() && PetActionBar[j].IsActionBarForSpell())
9883 {
9884 SetActionBar(j, spell_id, newstate == ACT_DECIDE ? spellInfo->IsAutocastable() ? ACT_DISABLED : ACT_PASSIVE : newstate);
9885 return true;
9886 }
9887 }
9888 return false;
9889}
9890
9892{
9893 uint32 first_id = sSpellMgr->GetFirstSpellInChain(spell_id);
9894
9895 for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
9896 {
9897 if (uint32 action = PetActionBar[i].GetAction())
9898 {
9899 if (PetActionBar[i].IsActionBarForSpell() && sSpellMgr->GetFirstSpellInChain(action) == first_id)
9900 {
9902 return true;
9903 }
9904 }
9905 }
9906
9907 return false;
9908}
9909
9910void CharmInfo::ToggleCreatureAutocast(SpellInfo const* spellInfo, bool apply)
9911{
9912 if (spellInfo->IsPassive())
9913 return;
9914
9915 for (uint32 x = 0; x < MAX_SPELL_CHARM; ++x)
9916 if (spellInfo->Id == _charmspells[x].GetAction())
9918}
9919
9920void CharmInfo::SetPetNumber(uint32 petnumber, bool statwindow)
9921{
9922 _petnumber = petnumber;
9923 if (statwindow)
9925 else
9927}
9928
9929void CharmInfo::LoadPetActionBar(const std::string& data)
9930{
9932
9933 std::vector<std::string_view> tokens = Trinity::Tokenize(data, ' ', false);
9934 if (tokens.size() != (ACTION_BAR_INDEX_END-ACTION_BAR_INDEX_START) * 2)
9935 return; // non critical, will reset to default
9936
9937 auto iter = tokens.begin();
9938 for (uint8 index = ACTION_BAR_INDEX_START; index < ACTION_BAR_INDEX_END; ++index)
9939 {
9940 Optional<uint8> type = Trinity::StringTo<uint8>(*(iter++));
9941 Optional<uint32> action = Trinity::StringTo<uint32>(*(iter++));
9942
9943 if (!type || !action)
9944 continue;
9945
9946 PetActionBar[index].SetActionAndType(*action, static_cast<ActiveStates>(*type));
9947
9948 // check correctness
9949 if (PetActionBar[index].IsActionBarForSpell())
9950 {
9951 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(PetActionBar[index].GetAction());
9952 if (!spellInfo)
9953 SetActionBar(index, 0, ACT_PASSIVE);
9954 else if (!spellInfo->IsAutocastable())
9955 SetActionBar(index, PetActionBar[index].GetAction(), ACT_PASSIVE);
9956 }
9957 }
9958}
9959
9961{
9962 for (uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
9963 *data << uint32(PetActionBar[i].packedData);
9964}
9965
9966void CharmInfo::SetSpellAutocast(SpellInfo const* spellInfo, bool state)
9967{
9968 for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
9969 {
9970 if (spellInfo->Id == PetActionBar[i].GetAction() && PetActionBar[i].IsActionBarForSpell())
9971 {
9973 break;
9974 }
9975 }
9976}
9977
9979{
9980 uint32 hitMask = PROC_HIT_NONE;
9981 // Check victim state
9982 if (missCondition != SPELL_MISS_NONE)
9983 {
9984 switch (missCondition)
9985 {
9986 case SPELL_MISS_MISS:
9987 hitMask |= PROC_HIT_MISS;
9988 break;
9989 case SPELL_MISS_DODGE:
9990 hitMask |= PROC_HIT_DODGE;
9991 break;
9992 case SPELL_MISS_PARRY:
9993 hitMask |= PROC_HIT_PARRY;
9994 break;
9995 case SPELL_MISS_BLOCK:
9996 // spells can't be partially blocked (it's damage can though)
9998 break;
9999 case SPELL_MISS_EVADE:
10000 hitMask |= PROC_HIT_EVADE;
10001 break;
10002 case SPELL_MISS_IMMUNE:
10003 case SPELL_MISS_IMMUNE2:
10004 hitMask |= PROC_HIT_IMMUNE;
10005 break;
10006 case SPELL_MISS_DEFLECT:
10007 hitMask |= PROC_HIT_DEFLECT;
10008 break;
10009 case SPELL_MISS_ABSORB:
10010 hitMask |= PROC_HIT_ABSORB;
10011 break;
10012 case SPELL_MISS_REFLECT:
10013 hitMask |= PROC_HIT_REFLECT;
10014 break;
10015 case SPELL_MISS_RESIST:
10016 hitMask |= PROC_HIT_FULL_RESIST;
10017 break;
10018 default:
10019 break;
10020 }
10021 }
10022 else
10023 {
10024 // On block
10025 if (damageInfo->blocked)
10026 {
10027 hitMask |= PROC_HIT_BLOCK;
10028 if (damageInfo->fullBlock)
10029 hitMask |= PROC_HIT_FULL_BLOCK;
10030 }
10031 // On absorb
10032 if (damageInfo->absorb)
10033 hitMask |= PROC_HIT_ABSORB;
10034
10035 // Don't set hit/crit hitMask if damage is nullified
10036 bool const damageNullified = (damageInfo->HitInfo & (HITINFO_FULL_ABSORB | HITINFO_FULL_RESIST)) != 0 || (hitMask & PROC_HIT_FULL_BLOCK) != 0;
10037 if (!damageNullified)
10038 {
10039 // On crit
10040 if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT)
10041 hitMask |= PROC_HIT_CRITICAL;
10042 else
10043 hitMask |= PROC_HIT_NORMAL;
10044 }
10045 else if ((damageInfo->HitInfo & HITINFO_FULL_RESIST) != 0)
10046 hitMask |= PROC_HIT_FULL_RESIST;
10047 }
10048
10049 return hitMask;
10050}
10051
10052void Unit::ProcSkillsAndReactives(bool isVictim, Unit* procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType attType)
10053{
10054 // Player is loaded now - do not allow passive spell casts to proc
10055 if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->GetSession()->PlayerLoading())
10056 return;
10057
10058 // For melee/ranged based attack need update skills and set some Aura states if victim present
10059 if (typeMask & MELEE_BASED_TRIGGER_MASK && procTarget)
10060 {
10061 // Update skills here for players
10062 // only when you are not fighting other players or their pets/totems (pvp)
10063 if (GetTypeId() == TYPEID_PLAYER &&
10064 procTarget->GetTypeId() != TYPEID_PLAYER &&
10065 !(procTarget->IsTotem() && procTarget->ToTotem()->GetOwner()->IsPlayer()) &&
10066 !procTarget->IsPet()
10067 )
10068 {
10069 // On melee based hit/miss/resist need update skill (for victim and attacker)
10071 {
10072 if (procTarget->GetTypeId() != TYPEID_PLAYER && !procTarget->IsCritter())
10073 ToPlayer()->UpdateCombatSkills(procTarget, attType, isVictim);
10074 }
10075 // Update defense if player is victim and parry/dodge/block
10076 else if (isVictim && (hitMask & (PROC_HIT_DODGE | PROC_HIT_PARRY | PROC_HIT_BLOCK)))
10077 ToPlayer()->UpdateCombatSkills(procTarget, attType, true);
10078 }
10079 // If exist crit/parry/dodge/block need update aura state (for victim and attacker)
10081 {
10082 // for victim
10083 if (isVictim)
10084 {
10085 // if victim and dodge attack
10086 if (hitMask & PROC_HIT_DODGE)
10087 {
10088 // Update AURA_STATE on dodge
10089 if (GetClass() != CLASS_ROGUE) // skip Rogue Riposte
10090 {
10093 }
10094 }
10095 // if victim and parry attack
10096 if (hitMask & PROC_HIT_PARRY)
10097 {
10098 // For Hunters only Counterattack (skip Mongoose bite)
10099 if (GetClass() == CLASS_HUNTER)
10100 {
10103 }
10104 else
10105 {
10108 }
10109 }
10110 // if and victim block attack
10111 if (hitMask & PROC_HIT_BLOCK)
10112 {
10115 }
10116 }
10117 else // For attacker
10118 {
10119 // Overpower on victim dodge
10120 if ((hitMask & PROC_HIT_DODGE) && GetTypeId() == TYPEID_PLAYER && GetClass() == CLASS_WARRIOR)
10121 {
10122 AddComboPoints(procTarget, 1);
10124 }
10125 else if ((hitMask & PROC_HIT_CRITICAL) && IsHunterPet())
10126 {
10127 AddComboPoints(procTarget, 1);
10129 }
10130 }
10131 }
10132 }
10133}
10134
10136{
10137 TimePoint now = GameTime::Now();
10138
10139 // use provided list of auras which can proc
10140 if (procAuras)
10141 {
10142 for (AuraApplication* aurApp : *procAuras)
10143 {
10144 ASSERT(aurApp->GetTarget() == this);
10145 if (uint8 procEffectMask = aurApp->GetBase()->GetProcEffectMask(aurApp, eventInfo, now))
10146 {
10147 aurApp->GetBase()->PrepareProcToTrigger(aurApp, eventInfo, now);
10148 aurasTriggeringProc.emplace_back(procEffectMask, aurApp);
10149 }
10150 }
10151 }
10152 // or generate one on our own
10153 else
10154 {
10155 for (AuraApplicationMap::iterator itr = GetAppliedAuras().begin(); itr != GetAppliedAuras().end(); ++itr)
10156 {
10157 if (uint8 procEffectMask = itr->second->GetBase()->GetProcEffectMask(itr->second, eventInfo, now))
10158 {
10159 itr->second->GetBase()->PrepareProcToTrigger(itr->second, eventInfo, now);
10160 aurasTriggeringProc.emplace_back(procEffectMask, itr->second);
10161 }
10162 }
10163 }
10164}
10165
10166void Unit::TriggerAurasProcOnEvent(Unit* actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell* spell, DamageInfo* damageInfo, HealInfo* healInfo)
10167{
10168 // prepare data for self trigger
10169 ProcEventInfo myProcEventInfo(this, actionTarget, typeMaskActor, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
10170 if (typeMaskActor)
10171 {
10172 AuraApplicationProcContainer myAurasTriggeringProc;
10173 GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, nullptr, myProcEventInfo);
10174
10175 // needed for example for Cobra Strikes, pet does the attack, but aura is on owner
10176 if (Player* modOwner = GetSpellModOwner())
10177 {
10178 if (modOwner != this && spell)
10179 {
10180 AuraApplicationList modAuras;
10181 for (auto itr = modOwner->GetAppliedAuras().begin(); itr != modOwner->GetAppliedAuras().end(); ++itr)
10182 {
10183 if (spell->m_appliedMods.count(itr->second->GetBase()) != 0)
10184 modAuras.push_back(itr->second);
10185 }
10186 modOwner->GetProcAurasTriggeredOnEvent(myAurasTriggeringProc, &modAuras, myProcEventInfo);
10187 }
10188 }
10189 TriggerAurasProcOnEvent(myProcEventInfo, myAurasTriggeringProc);
10190 }
10191
10192 // prepare data for target trigger
10193 ProcEventInfo targetProcEventInfo(this, actionTarget, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, spell, damageInfo, healInfo);
10194 if (typeMaskActionTarget && actionTarget)
10195 {
10196 AuraApplicationProcContainer targetAurasTriggeringProc;
10197 actionTarget->GetProcAurasTriggeredOnEvent(targetAurasTriggeringProc, nullptr, targetProcEventInfo);
10198 actionTarget->TriggerAurasProcOnEvent(targetProcEventInfo, targetAurasTriggeringProc);
10199 }
10200}
10201
10203{
10204 Spell const* triggeringSpell = eventInfo.GetProcSpell();
10205 bool const disableProcs = triggeringSpell && triggeringSpell->IsProcDisabled();
10206 if (disableProcs)
10207 SetCantProc(true);
10208
10209 for (auto const& aurAppProc : aurasTriggeringProc)
10210 {
10211 AuraApplication* aurApp;
10212 uint8 procEffectMask;
10213 std::tie(procEffectMask, aurApp) = aurAppProc;
10214
10215 if (aurApp->GetRemoveMode())
10216 continue;
10217
10218 SpellInfo const* spellInfo = aurApp->GetBase()->GetSpellInfo();
10219 if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
10220 SetCantProc(true);
10221
10222 aurApp->GetBase()->TriggerProcOnEvent(procEffectMask, aurApp, eventInfo);
10223
10224 if (spellInfo->HasAttribute(SPELL_ATTR3_DISABLE_PROC))
10225 SetCantProc(false);
10226 }
10227
10228 if (disableProcs)
10229 SetCantProc(false);
10230}
10231
10234{
10235 Unit* owner = GetOwner();
10236 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10237 return;
10238
10239 WorldPackets::Pet::PetActionFeedback petActionFeedback;
10240 petActionFeedback.SpellID = spellId;
10241 petActionFeedback.Response = msg;
10242 owner->ToPlayer()->SendDirectMessage(petActionFeedback.Write());
10243}
10244
10246{
10247 WorldPackets::Pet::PetActionSound petActionSound;
10248 petActionSound.UnitGUID = GetGUID();
10249 petActionSound.Action = action;
10250 SendMessageToSet(petActionSound.Write(), false);
10251}
10252
10254{
10255 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.LookupEntry(GetNativeDisplayId());
10256 if (!displayInfo)
10257 return;
10258
10259 WorldPackets::Pet::PetDismissSound petDismissSound;
10260 petDismissSound.ModelId = displayInfo->ModelID;
10261 petDismissSound.ModelPosition = GetPosition();
10262 SendMessageToSet(petDismissSound.Write(), false);
10263}
10264
10266{
10267 Unit* owner = GetOwner();
10268 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
10269 return;
10270
10272 packet.UnitGUID = guid;
10274 owner->ToPlayer()->SendDirectMessage(packet.Write());
10275}
10276
10278
10283
10288
10289void Unit::StopMoving(bool force /*= false*/)
10290{
10292
10293 // not need send any packets if not in world or not moving
10294 if (!IsInWorld() || (!force && movespline->Finalized()))
10295 return;
10296
10297 // Update position now since Stop does not start a new movement that can be updated later
10298 if (movespline->HasStarted())
10300 Movement::MoveSplineInit init(this);
10301 init.Stop(force);
10302}
10303
10304void Unit::PauseMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/, bool forced/* = true*/)
10305{
10306 if (IsInvalidMovementSlot(slot))
10307 return;
10308
10309 if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot)))
10310 movementGenerator->Pause(timer);
10311
10312 if (forced && GetMotionMaster()->GetCurrentSlot() == MovementSlot(slot))
10313 StopMoving();
10314}
10315
10316void Unit::ResumeMovement(uint32 timer/* = 0*/, uint8 slot/* = 0*/)
10317{
10318 if (IsInvalidMovementSlot(slot))
10319 return;
10320
10321 if (MovementGenerator* movementGenerator = GetMotionMaster()->GetCurrentMovementGenerator(MovementSlot(slot)))
10322 movementGenerator->Resume(timer);
10323}
10324
10333
10335{
10338}
10339
10353
10355{
10356 uint32 transformId = GetTransformSpell();
10357 if (!transformId)
10358 return false;
10359
10360 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(transformId);
10361 if (!spellInfo)
10362 return false;
10363
10364 return spellInfo->GetSpellSpecific() == SPELL_SPECIFIC_MAGE_POLYMORPH;
10365}
10366
10368{
10369 if (!IsCreature())
10370 return;
10371
10373}
10374
10376{
10378 float scale = GetNativeObjectScale() + CalculatePct(1.0f, scaleAuras);
10379 float scaleMin = GetTypeId() == TYPEID_PLAYER ? 0.1 : 0.01;
10380 SetObjectScale(std::max(scale, scaleMin));
10381}
10382
10384{
10386 // Set Gender by modelId
10387 if (CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(modelId))
10388 SetGender(Gender(minfo->gender));
10389}
10390
10392{
10393 AuraEffect* handledAura = nullptr;
10394 // try to receive model from transform auras
10396 if (!transforms.empty())
10397 {
10398 // iterate over already applied transform auras - from newest to oldest
10399 for (auto i = transforms.rbegin(); i != transforms.rend(); ++i)
10400 {
10401 if (AuraApplication const* aurApp = (*i)->GetBase()->GetApplicationOfTarget(GetGUID()))
10402 {
10403 if (!handledAura)
10404 handledAura = (*i);
10405 // prefer negative auras
10406 if (!aurApp->IsPositive())
10407 {
10408 handledAura = (*i);
10409 break;
10410 }
10411 }
10412 }
10413 }
10414
10416
10417 // transform aura was found
10418 if (handledAura)
10419 {
10420 handledAura->HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true);
10421 return;
10422 }
10423 else if (!shapeshiftAura.empty()) // we've found shapeshift
10424 {
10425 // only one such aura possible at a time
10426 if (uint32 modelId = GetModelForForm(GetShapeshiftForm(), shapeshiftAura.front()->GetId()))
10427 {
10428 SetDisplayId(modelId);
10429 return;
10430 }
10431 }
10432
10433 // no auras found - set modelid to default
10435}
10436
10437void Unit::AddComboPoints(Unit* target, int8 count)
10438{
10439 if (!count)
10440 return;
10441
10442 if (target && target != m_comboTarget)
10443 {
10444 if (m_comboTarget)
10446 m_comboTarget = target;
10447 m_comboPoints = count;
10448 target->AddComboPointHolder(this);
10449 }
10450 else
10451 m_comboPoints = std::max<int8>(std::min<int8>(m_comboPoints + count, 5),0);
10452
10454}
10455
10457{
10458 if (!m_comboTarget)
10459 return;
10460
10461 // remove Premed-like effects
10462 // (NB: this Aura retains the CP while it's active - now that CP have reset, it shouldn't be there anymore)
10464
10465 m_comboPoints = 0;
10468 m_comboTarget = nullptr;
10469}
10470
10472{
10473 if (m_cleanupDone)
10474 return;
10475
10477 if (Player* playerMe = ToPlayer())
10478 {
10479 WorldPacket data;
10480 data.Initialize(SMSG_UPDATE_COMBO_POINTS, packGUID.size() + 1);
10481 data << packGUID;
10482 data << uint8(m_comboPoints);
10483 playerMe->SendDirectMessage(&data);
10484 }
10485 Player* movingMe = GetCharmerOrSelfPlayer();
10486 ObjectGuid ownerGuid = GetCharmerOrOwnerGUID();
10487 Player* owner = nullptr;
10488 if (ownerGuid.IsPlayer())
10489 owner = ObjectAccessor::GetPlayer(*this, ownerGuid);
10490 if (movingMe || owner)
10491 {
10492 WorldPacket data;
10493 data.Initialize(SMSG_PET_UPDATE_COMBO_POINTS, GetPackGUID().size() + packGUID.size() + 1);
10494 data << GetPackGUID();
10495 data << packGUID;
10496 data << uint8(m_comboPoints);
10497 if (movingMe)
10498 movingMe->SendDirectMessage(&data);
10499 if (owner && owner != movingMe)
10500 owner->SendDirectMessage(&data);
10501 }
10502}
10503
10505{
10506 while (!m_ComboPointHolders.empty())
10507 (*m_ComboPointHolders.begin())->ClearComboPoints(); // this also removes it from m_comboPointHolders
10508}
10509
10511{
10512 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
10513 m_reactiveTimer[i] = 0;
10514
10521 if (IsHunterPet())
10523}
10524
10526{
10527 for (uint8 i = 0; i < MAX_REACTIVE; ++i)
10528 {
10529 ReactiveType reactive = ReactiveType(i);
10530
10531 if (!m_reactiveTimer[reactive])
10532 continue;
10533
10534 if (m_reactiveTimer[reactive] <= p_time)
10535 {
10536 m_reactiveTimer[reactive] = 0;
10537
10538 switch (reactive)
10539 {
10540 case REACTIVE_DEFENSE:
10543 break;
10547 break;
10548 case REACTIVE_OVERPOWER:
10551 break;
10553 if (IsHunterPet())
10555 break;
10556 default:
10557 break;
10558 }
10559 }
10560 else
10561 {
10562 m_reactiveTimer[reactive] -= p_time;
10563 }
10564 }
10565}
10566
10567Unit* Unit::SelectNearbyTarget(Unit* exclude, float dist) const
10568{
10569 std::list<Unit*> targets;
10570 Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, dist);
10572 Cell::VisitAllObjects(this, searcher, dist);
10573
10574 // remove current target
10575 if (GetVictim())
10576 targets.remove(GetVictim());
10577
10578 if (exclude)
10579 targets.remove(exclude);
10580
10581 // remove not LoS targets
10582 for (std::list<Unit*>::iterator tIter = targets.begin(); tIter != targets.end();)
10583 {
10584 if (!IsWithinLOSInMap(*tIter) || (*tIter)->IsTotem() || (*tIter)->IsSpiritService() || (*tIter)->IsCritter())
10585 targets.erase(tIter++);
10586 else
10587 ++tIter;
10588 }
10589
10590 // no appropriate targets
10591 if (targets.empty())
10592 return nullptr;
10593
10594 // select random
10596}
10597
10599{
10601
10602 float remainingTimePct = (float)m_attackTimer[att] / (GetAttackTime(att) * m_modAttackSpeedPct[att]);
10603 if (val > 0.f)
10604 {
10606 ApplyPercentModFloatVar(amount, val, !apply);
10607 }
10608 else
10609 {
10611 ApplyPercentModFloatVar(amount, -val, apply);
10612 }
10613
10615 m_attackTimer[att] = uint32(GetAttackTime(att) * m_modAttackSpeedPct[att] * remainingTimePct);
10616}
10617
10618void Unit::ApplyCastTimePercentMod(float val, bool apply)
10619{
10620 float amount = GetFloatValue(UNIT_MOD_CAST_SPEED);
10621
10622 if (val > 0.f)
10623 ApplyPercentModFloatVar(amount, val, !apply);
10624 else
10625 ApplyPercentModFloatVar(amount, -val, apply);
10626
10627 SetModCastingSpeed(amount);
10628}
10629
10630uint32 Unit::GetCastingTimeForBonus(SpellInfo const* spellProto, DamageEffectType damagetype, uint32 CastingTime) const
10631{
10632 // Not apply this to creature cast spells with casttime == 0
10633 if (CastingTime == 0 && GetTypeId() == TYPEID_UNIT && !IsPet())
10634 return 3500;
10635
10636 if (CastingTime > 7000) CastingTime = 7000;
10637 if (CastingTime < 1500) CastingTime = 1500;
10638
10639 if (damagetype == DOT && !spellProto->IsChanneled())
10640 CastingTime = 3500;
10641
10642 int32 overTime = 0;
10643 uint8 effects = 0;
10644 bool DirectDamage = false;
10645 bool AreaEffect = false;
10646
10647 for (SpellEffectInfo const& spellEffectInfo : spellProto->GetEffects())
10648 {
10649 switch (spellEffectInfo.Effect)
10650 {
10656 case SPELL_EFFECT_HEAL:
10657 DirectDamage = true;
10658 break;
10660 switch (spellEffectInfo.ApplyAuraName)
10661 {
10665 if (spellProto->GetDuration())
10666 overTime = spellProto->GetDuration();
10667 break;
10668 default:
10669 // -5% per additional effect
10670 ++effects;
10671 break;
10672 }
10673 break;
10674 default:
10675 break;
10676 }
10677
10678 if (spellEffectInfo.IsTargetingArea())
10679 AreaEffect = true;
10680 }
10681
10682 // Combined Spells with Both Over Time and Direct Damage
10683 if (overTime > 0 && DirectDamage)
10684 {
10685 // mainly for DoTs which are 3500 here otherwise
10686 uint32 OriginalCastTime = spellProto->CalcCastTime();
10687 if (OriginalCastTime > 7000) OriginalCastTime = 7000;
10688 if (OriginalCastTime < 1500) OriginalCastTime = 1500;
10689 // Portion to Over Time
10690 float PtOT = (overTime / 15000.0f) / ((overTime / 15000.0f) + (OriginalCastTime / 3500.0f));
10691
10692 if (damagetype == DOT)
10693 CastingTime = uint32(CastingTime * PtOT);
10694 else if (PtOT < 1.0f)
10695 CastingTime = uint32(CastingTime * (1 - PtOT));
10696 else
10697 CastingTime = 0;
10698 }
10699
10700 // Area Effect Spells receive only half of bonus
10701 if (AreaEffect)
10702 CastingTime /= 2;
10703
10704 // 50% for damage and healing spells for leech spells from damage bonus and 0% from healing
10705 for (SpellEffectInfo const& spellEffectInfo : spellProto->GetEffects())
10706 {
10707 if (spellEffectInfo.IsEffect(SPELL_EFFECT_HEALTH_LEECH) ||
10708 (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA) && spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_LEECH))
10709 {
10710 CastingTime /= 2;
10711 break;
10712 }
10713 }
10714
10715 // -5% of total per any additional effect
10716 for (uint8 i = 0; i < effects; ++i)
10717 CastingTime *= 0.95f;
10718
10719 return CastingTime;
10720}
10721
10723{
10724 if (slot >= MAX_AURAS) // slot not found, return
10725 return;
10726 if (Player* player = ToPlayer())
10727 {
10728 if (player->GetGroup())
10729 {
10730 player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_AURAS);
10731 player->SetAuraUpdateMaskForRaid(slot);
10732 }
10733 }
10734 else if (GetTypeId() == TYPEID_UNIT && IsPet())
10735 {
10736 Pet* pet = ((Pet*)this);
10737 if (pet->isControlled())
10738 {
10739 Unit* owner = GetOwner();
10740 if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
10741 {
10743 pet->SetAuraUpdateMaskForRaid(slot);
10744 }
10745 }
10746 }
10747}
10748
10749void Unit::SetCantProc(bool apply)
10750{
10751 if (apply)
10752 ++m_procDeep;
10753 else
10754 {
10756 --m_procDeep;
10757 }
10758}
10759
10760float Unit::CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffectType damagetype) const
10761{
10762 // Damage over Time spells bonus calculation
10763 float DotFactor = 1.0f;
10764 if (damagetype == DOT)
10765 {
10766 int32 DotDuration = spellInfo->GetDuration();
10767 if (!spellInfo->IsChanneled() && DotDuration > 0)
10768 DotFactor = DotDuration / 15000.0f;
10769
10770 if (uint32 DotTicks = spellInfo->GetMaxTicks())
10771 DotFactor /= DotTicks;
10772 }
10773
10774 int32 CastingTime = spellInfo->IsChanneled() ? spellInfo->GetDuration() : spellInfo->CalcCastTime();
10775 // Distribute Damage over multiple effects, reduce by AoE
10776 CastingTime = GetCastingTimeForBonus(spellInfo, damagetype, CastingTime);
10777
10778 // As wowwiki says: C = (Cast Time / 3.5)
10779 return (CastingTime / 3500.0f) * DotFactor;
10780}
10781
10782float Unit::GetAPMultiplier(WeaponAttackType attType, bool normalized) const
10783{
10784 if (GetTypeId() != TYPEID_PLAYER || (IsInFeralForm() && !normalized))
10785 return GetAttackTime(attType) / 1000.0f;
10786
10787 Item* weapon = ToPlayer()->GetWeaponForAttack(attType, true);
10788 if (!weapon)
10789 return BASE_ATTACK_TIME / 1000.0f;
10790
10791 if (!normalized)
10792 return weapon->GetTemplate()->GetDelay() / 1000.0f;
10793
10794 switch (weapon->GetTemplate()->GetSubClass())
10795 {
10802 return 3.3f;
10807 return 2.8f;
10814 return 2.4f;
10816 return 1.7f;
10817 default:
10818 return weapon->GetTemplate()->GetDelay() / 1000.0f;
10819 }
10820}
10821
10823{
10825}
10826
10827Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget, uint32 spell_id)
10828{
10829 if (GetTypeId() != TYPEID_PLAYER)
10830 return nullptr;
10831
10832 Pet* pet = new Pet(ToPlayer(), HUNTER_PET);
10833
10834 if (!pet->CreateBaseAtCreature(creatureTarget))
10835 {
10836 delete pet;
10837 return nullptr;
10838 }
10839
10840 uint8 level = creatureTarget->GetLevel() + 5 < GetLevel() ? (GetLevel() - 5) : creatureTarget->GetLevel();
10841
10842 if (!InitTamedPet(pet, level, spell_id))
10843 {
10844 delete pet;
10845 return nullptr;
10846 }
10847
10848 return pet;
10849}
10850
10852{
10853 if (GetTypeId() != TYPEID_PLAYER)
10854 return nullptr;
10855
10856 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creatureEntry);
10857 if (!creatureInfo)
10858 return nullptr;
10859
10860 Pet* pet = new Pet(ToPlayer(), HUNTER_PET);
10861
10862 if (!pet->CreateBaseAtCreatureInfo(creatureInfo, this) || !InitTamedPet(pet, GetLevel(), spell_id))
10863 {
10864 delete pet;
10865 return nullptr;
10866 }
10867
10868 return pet;
10869}
10870
10871bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id)
10872{
10873 Player* player = ToPlayer();
10874 PetStable& petStable = player->GetOrInitPetStable();
10875 if (petStable.CurrentPet || petStable.GetUnslottedHunterPet())
10876 return false;
10877
10878 pet->SetCreatorGUID(GetGUID());
10879 pet->SetFaction(GetFaction());
10880 pet->SetCreatedBySpell(spell_id);
10881
10882 if (GetTypeId() == TYPEID_PLAYER)
10884
10885 if (!pet->InitStatsForLevel(level))
10886 {
10887 TC_LOG_ERROR("entities.unit", "Pet::InitStatsForLevel() failed for creature (Entry: {})!", pet->GetEntry());
10888 return false;
10889 }
10890
10891 pet->GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true);
10892 // this enables pet details window (Shift+P)
10893 pet->InitPetCreateSpells();
10894 //pet->InitLevelupSpellsForLevel();
10895 pet->SetFullHealth();
10896
10897 pet->FillPetInfo(&petStable.CurrentPet.emplace());
10898 return true;
10899}
10900
10901/*static*/ void Unit::Kill(Unit* attacker, Unit* victim, bool durabilityLoss /*= true*/)
10902{
10903 // Prevent killing unit twice (and giving reward from kill twice)
10904 if (!victim->GetHealth())
10905 return;
10906
10907 if (attacker && !attacker->IsInMap(victim))
10908 attacker = nullptr;
10909
10910 // find player: owner of controlled `this` or `this` itself maybe
10911 Player* player = nullptr;
10912 if (attacker)
10913 player = attacker->GetCharmerOrOwnerPlayerOrPlayerItself();
10914
10915 Creature* creature = victim->ToCreature();
10916
10917 bool isRewardAllowed = true;
10918 if (creature)
10919 {
10920 isRewardAllowed = creature->IsDamageEnoughForLootingAndReward();
10921 if (!isRewardAllowed)
10922 creature->SetLootRecipient(nullptr);
10923 }
10924
10925 if (isRewardAllowed && creature)
10926 {
10927 if (Player* lootRecipient = creature->GetLootRecipient())
10928 {
10929 // Loot recipient can be in a different map
10930 if (!creature->IsInMap(lootRecipient))
10931 {
10932 if (Group* group = creature->GetLootRecipientGroup())
10933 {
10934 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
10935 {
10936 Player* member = itr->GetSource();
10937 if (!member || !creature->IsInMap(member))
10938 continue;
10939
10940 player = member;
10941 break;
10942 }
10943 }
10944 }
10945 else
10946 player = creature->GetLootRecipient();
10947 }
10948 }
10949
10950 // Exploit fix
10951 if (creature && creature->IsPet() && creature->GetOwnerGUID().IsPlayer())
10952 isRewardAllowed = false;
10953
10954 // Reward player, his pets, and group/raid members
10955 // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
10956 if (isRewardAllowed && player && player != victim)
10957 {
10958 WorldPacket data(SMSG_PARTYKILLLOG, (8+8)); // send event PARTY_KILL
10959 data << player->GetGUID(); // player with killing blow
10960 data << victim->GetGUID(); // victim
10961
10962 Player* looter = player;
10963 Group* group = player->GetGroup();
10964 bool hasLooterGuid = false;
10965
10966 if (group)
10967 {
10968 group->BroadcastPacket(&data, group->GetMemberGroup(player->GetGUID()) != 0);
10969
10970 if (creature)
10971 {
10972 group->UpdateLooterGuid(creature, true);
10973 if (!group->GetLooterGuid().IsEmpty())
10974 {
10975 looter = ObjectAccessor::FindPlayer(group->GetLooterGuid());
10976 if (looter)
10977 {
10978 hasLooterGuid = true;
10979 creature->SetLootRecipient(looter); // update creature loot recipient to the allowed looter.
10980 }
10981 }
10982 }
10983 }
10984 else
10985 {
10986 player->SendDirectMessage(&data);
10987
10988 if (creature)
10989 {
10990 WorldPacket data2(SMSG_LOOT_LIST, 8 + 1 + 1);
10991 data2 << creature->GetGUID();
10992 data2 << uint8(0); // unk1
10993 data2 << uint8(0); // no group looter
10994 player->SendMessageToSet(&data2, true);
10995 }
10996 }
10997
10998 // Generate loot before updating looter
10999 if (creature)
11000 {
11001 Loot* loot = &creature->loot;
11002 loot->clear();
11003
11004 if (uint32 lootid = creature->GetCreatureTemplate()->lootid)
11005 loot->FillLoot(lootid, LootTemplates_Creature, looter, false, false, creature->GetLootMode());
11006
11007 if (creature->GetLootMode() > 0)
11009
11010 if (group)
11011 {
11012 if (hasLooterGuid)
11013 group->SendLooter(creature, looter);
11014 else
11015 group->SendLooter(creature, nullptr);
11016
11017 // Update round robin looter only if the creature had loot
11018 if (!loot->empty())
11019 group->UpdateLooterGuid(creature);
11020 }
11021 }
11022
11023 player->RewardPlayerAndGroupAtKill(victim, false);
11024 }
11025
11026 // 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
11027 if (attacker && (attacker->IsPet() || attacker->IsTotem()))
11028 {
11029 // proc only once for victim
11030 if (Unit* owner = attacker->GetOwner())
11032 }
11033
11034 if (!victim->IsCritter())
11036
11037 // Proc auras on death - must be before aura/combat remove
11039
11040 // update get killing blow achievements, must be done before setDeathState to be able to require auras on target
11041 // and before Spirit of Redemption as it also removes auras
11042 if (attacker)
11043 if (Player* killerPlayer = attacker->GetCharmerOrOwnerPlayerOrPlayerItself())
11044 killerPlayer->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, victim);
11045
11046 // Spirit of Redemption
11047 // if talent known but not triggered
11048 bool spiritOfRedemption = false;
11049 if (AuraEffect const* aurEff = victim->GetAuraEffect(SPELL_AURA_DUMMY, SPELLFAMILY_PRIEST, 0, 0, 0x200))
11050 {
11051 // save value before aura remove
11052 uint32 ressSpellId = victim->GetUInt32Value(PLAYER_SELF_RES_SPELL);
11053 if (!ressSpellId)
11054 ressSpellId = victim->ToPlayer()->GetResurrectionSpellId();
11055 // Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
11056 victim->RemoveAllAurasOnDeath();
11057 // restore for use at real death
11058 victim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId);
11059
11060 // FORM_SPIRITOFREDEMPTION and related auras
11061 victim->CastSpell(victim, 27827, aurEff);
11062 spiritOfRedemption = true;
11063 }
11064
11065 if (!spiritOfRedemption)
11066 {
11067 TC_LOG_DEBUG("entities.unit", "SET JUST_DIED");
11068 victim->setDeathState(JUST_DIED);
11069 }
11070
11071 // Inform pets (if any) when player kills target)
11072 // MUST come after victim->setDeathState(JUST_DIED); or pet next target
11073 // selection will get stuck on same target and break pet react state
11074 if (player)
11075 {
11076 Pet* pet = player->GetPet();
11077 if (pet && pet->IsAlive() && pet->isControlled())
11078 {
11079 if (pet->IsAIEnabled())
11080 pet->AI()->KilledUnit(victim);
11081 else
11082 TC_LOG_ERROR("entities.unit", "Pet doesn't have any AI in Unit::Kill(). {}", pet->GetDebugInfo());
11083 }
11084 }
11085
11086 // 10% durability loss on death
11087 if (Player* plrVictim = victim->ToPlayer())
11088 {
11089 // remember victim PvP death for corpse type and corpse reclaim delay
11090 // at original death (not at SpiritOfRedemtionTalent timeout)
11091 plrVictim->SetPvPDeath(player != nullptr);
11092
11093 // only if not player and not controlled by player pet. And not at BG
11094 if ((durabilityLoss && !player && !victim->ToPlayer()->InBattleground()) || (player && sWorld->getBoolConfig(CONFIG_DURABILITY_LOSS_IN_PVP)))
11095 {
11096 double baseLoss = sWorld->getRate(RATE_DURABILITY_LOSS_ON_DEATH);
11097 TC_LOG_DEBUG("entities.unit", "We are dead, losing {} percent durability", baseLoss);
11098 plrVictim->DurabilityLossAll(baseLoss, false);
11099 // durability lost message
11100 plrVictim->SendDurabilityLoss();
11101 }
11102 // Call KilledUnit for creatures
11103 if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())
11104 attacker->ToCreature()->AI()->KilledUnit(victim);
11105
11106 // last damage from non duel opponent or opponent controlled creature
11107 if (plrVictim->duel)
11108 {
11109 plrVictim->duel->Opponent->CombatStopWithPets(true);
11110 plrVictim->CombatStopWithPets(true);
11111 plrVictim->DuelComplete(DUEL_INTERRUPTED);
11112 }
11113 }
11114 else // creature died
11115 {
11116 TC_LOG_DEBUG("entities.unit", "DealDamageNotPlayer");
11117 ASSERT_NODEBUGINFO(creature);
11118
11119 if (!creature->IsPet())
11120 {
11121 // must be after setDeathState which resets dynamic flags
11122 if (!creature->loot.isLooted())
11124 else
11125 creature->AllLootRemovedFromCorpse();
11126 }
11127
11128 // Call KilledUnit for creatures, this needs to be called after the lootable flag is set
11129 if (attacker && attacker->GetTypeId() == TYPEID_UNIT && attacker->IsAIEnabled())
11130 attacker->ToCreature()->AI()->KilledUnit(victim);
11131
11132 // Call creature just died function
11133 if (CreatureAI* ai = creature->AI())
11134 ai->JustDied(attacker);
11135
11136 if (TempSummon * summon = creature->ToTempSummon())
11137 {
11138 if (WorldObject * summoner = summon->GetSummoner())
11139 {
11140 if (summoner->ToCreature() && summoner->ToCreature()->IsAIEnabled())
11141 summoner->ToCreature()->AI()->SummonedCreatureDies(creature, attacker);
11142 else if (summoner->ToGameObject() && summoner->ToGameObject()->AI())
11143 summoner->ToGameObject()->AI()->SummonedCreatureDies(creature, attacker);
11144 }
11145 }
11146
11147 // Dungeon specific stuff, only applies to players killing creatures
11148 if (creature->GetInstanceId())
11149 {
11150 Map* instanceMap = creature->GetMap();
11151
11153 if (instanceMap->IsDungeon() && ((attacker && attacker->GetCharmerOrOwnerPlayerOrPlayerItself()) || attacker == victim))
11154 {
11155 if (instanceMap->IsRaidOrHeroicDungeon())
11156 {
11158 instanceMap->ToInstanceMap()->PermBindAllPlayers();
11159 }
11160 else
11161 {
11162 // the reset time is set but not added to the scheduler
11163 // until the players leave the instance
11164 time_t resettime = GameTime::GetGameTime() + 2 * HOUR;
11165 if (InstanceSave* save = sInstanceSaveMgr->GetInstanceSave(creature->GetInstanceId()))
11166 if (save->GetResetTime() < resettime)
11167 save->SetResetTime(resettime);
11168 }
11169 }
11170 }
11171 }
11172
11173 // outdoor pvp things, do these after setting the death state, else the player activity notify won't work... doh...
11174 // handle player kill only if not suicide (spirit of redemption for example)
11175 if (player && attacker != victim)
11176 {
11177 if (OutdoorPvP* pvp = player->GetOutdoorPvP())
11178 pvp->HandleKill(player, victim);
11179
11180 if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetZoneId()))
11181 bf->HandleKill(player, victim);
11182 }
11183
11184 //if (victim->GetTypeId() == TYPEID_PLAYER)
11185 // if (OutdoorPvP* pvp = victim->ToPlayer()->GetOutdoorPvP())
11186 // pvp->HandlePlayerActivityChangedpVictim->ToPlayer();
11187
11188 // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
11189 if (player && player->InBattleground())
11190 {
11191 if (Battleground* bg = player->GetBattleground())
11192 {
11193 if (Player* playerVictim = victim->ToPlayer())
11194 bg->HandleKillPlayer(playerVictim, player);
11195 else
11196 bg->HandleKillUnit(victim->ToCreature(), player);
11197 }
11198 }
11199
11200 // achievement stuff
11201 if (attacker && victim->GetTypeId() == TYPEID_PLAYER)
11202 {
11203 if (attacker->GetTypeId() == TYPEID_UNIT)
11205 else if (attacker->GetTypeId() == TYPEID_PLAYER && victim != attacker)
11207 }
11208
11209 // Hook for OnPVPKill Event
11210 if (attacker)
11211 {
11212 if (Player* killerPlr = attacker->ToPlayer())
11213 {
11214 if (Player* killedPlr = victim->ToPlayer())
11215 sScriptMgr->OnPVPKill(killerPlr, killedPlr);
11216 else if (Creature* killedCre = victim->ToCreature())
11217 sScriptMgr->OnCreatureKill(killerPlr, killedCre);
11218 }
11219 else if (Creature* killerCre = attacker->ToCreature())
11220 {
11221 if (Player* killed = victim->ToPlayer())
11222 sScriptMgr->OnPlayerKilledByCreature(killerCre, killed);
11223 }
11224 }
11225}
11226
11227void Unit::SetControlled(bool apply, UnitState state)
11228{
11229 if (apply)
11230 {
11231 if (HasUnitState(state))
11232 return;
11233
11234 if (state & UNIT_STATE_CONTROLLED)
11235 CastStop();
11236
11237 AddUnitState(state);
11238 switch (state)
11239 {
11240 case UNIT_STATE_STUNNED:
11241 SetStunned(true);
11242 break;
11243 case UNIT_STATE_ROOT:
11245 SetRooted(true);
11246 break;
11249 {
11252 // SendAutoRepeatCancel ?
11253 SetConfused(true);
11254 }
11255 break;
11256 case UNIT_STATE_FLEEING:
11258 {
11261 // SendAutoRepeatCancel ?
11262 SetFeared(true);
11263 }
11264 break;
11265 default:
11266 break;
11267 }
11268 }
11269 else
11270 {
11271 switch (state)
11272 {
11273 case UNIT_STATE_STUNNED:
11275 return;
11276
11277 ClearUnitState(state);
11278 SetStunned(false);
11279 break;
11280 case UNIT_STATE_ROOT:
11281 if (HasAuraType(SPELL_AURA_MOD_ROOT) || GetVehicle() || (ToCreature() && ToCreature()->GetMovementTemplate().IsRooted()))
11282 return;
11283
11284 ClearUnitState(state);
11286 SetRooted(false);
11287 break;
11290 return;
11291
11292 ClearUnitState(state);
11293 SetConfused(false);
11294 break;
11295 case UNIT_STATE_FLEEING:
11297 return;
11298
11299 ClearUnitState(state);
11300 SetFeared(false);
11301 break;
11302 default:
11303 return;
11304 }
11305
11307 }
11308}
11309
11311{
11312 // Unit States might have been already cleared but auras still present. I need to check with HasAuraType
11314 SetStunned(true);
11315
11317 SetRooted(true);
11318
11320 SetConfused(true);
11321
11323 SetFeared(true);
11324}
11325
11326void Unit::SetStunned(bool apply)
11327{
11328 if (apply)
11329 {
11332
11333 StopMoving();
11334
11335 if (GetTypeId() == TYPEID_PLAYER)
11337
11338 SetRooted(true);
11339
11340 CastStop();
11341 }
11342 else
11343 {
11344 if (IsAlive() && GetVictim())
11346
11347 // don't remove UNIT_FLAG_STUNNED for pet when owner is mounted (disabled pet's interface)
11348 Unit* owner = GetCharmerOrOwner();
11349 if (!owner || owner->GetTypeId() != TYPEID_PLAYER || !owner->ToPlayer()->IsMounted())
11351
11352 if (!HasUnitState(UNIT_STATE_ROOT)) // prevent moving if it also has root effect
11353 SetRooted(false);
11354 }
11355}
11356
11357void Unit::SetRooted(bool apply)
11358{
11359 if (apply)
11360 {
11361 // MOVEMENTFLAG_ROOT cannot be used in conjunction with MOVEMENTFLAG_MASK_MOVING (tested 3.3.5a)
11362 // this will freeze clients. That's why we remove MOVEMENTFLAG_MASK_MOVING before
11363 // setting MOVEMENTFLAG_ROOT
11366 StopMoving();
11367 }
11368 else
11370
11371 static OpcodeServer const rootOpcodeTable[2][3] =
11372 {
11375 };
11376
11377 if (IsMovedByClient())
11378 {
11379 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
11380
11381 WorldPacket data(rootOpcodeTable[apply][1], 10);
11382 data << GetPackGUID();
11383 data << GetMovementCounterAndInc();
11384 playerMover->SendDirectMessage(&data);
11385
11386 data.Initialize(rootOpcodeTable[apply][2], 64);
11387 data << GetPackGUID();
11388 BuildMovementPacket(&data);
11389 SendMessageToSet(&data, playerMover);
11390 }
11391 else
11392 {
11393 WorldPacket data(rootOpcodeTable[apply][0], 9);
11394 data << GetPackGUID();
11395 SendMessageToSet(&data, true);
11396 }
11397}
11398
11399void Unit::SetFeared(bool apply)
11400{
11401 if (apply)
11402 {
11403 // block control to real player in control (eg charmer)
11406
11408
11409 Unit* caster = nullptr;
11411 if (!fearAuras.empty())
11412 caster = ObjectAccessor::GetUnit(*this, fearAuras.front()->GetCasterGUID());
11413 if (!caster)
11414 caster = getAttackerForHelper();
11415 GetMotionMaster()->MoveFleeing(caster, fearAuras.empty() ? sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY) : 0); // caster == NULL processed in MoveFleeing
11416 }
11417 else
11418 {
11419 if (IsAlive())
11420 {
11422 if (GetVictim())
11424 if (!IsPlayer() && !IsInCombat())
11426 }
11427
11428 // allow control to real player in control (eg charmer)
11431 }
11432}
11433
11434void Unit::SetConfused(bool apply)
11435{
11436 if (apply)
11437 {
11438 // block control to real player in control (eg charmer)
11441
11444 }
11445 else
11446 {
11447 if (IsAlive())
11448 {
11450 if (GetVictim())
11452 }
11453
11454 // allow control to real player in control (eg charmer)
11457 }
11458}
11459
11460bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* aurApp)
11461{
11462 if (!charmer)
11463 return false;
11464
11465 // dismount players when charmed
11466 if (GetTypeId() == TYPEID_PLAYER)
11468
11469 if (charmer->GetTypeId() == TYPEID_PLAYER)
11471
11472 ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
11473 ASSERT((type == CHARM_TYPE_VEHICLE) == (GetVehicleKit() && GetVehicleKit()->IsControllableVehicle()));
11474
11475 TC_LOG_DEBUG("entities.unit", "SetCharmedBy: charmer {}, charmed {}, type {}.", charmer->GetGUID().ToString(), GetGUID().ToString(), uint32(type));
11476
11477 if (this == charmer)
11478 {
11479 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: Unit {} is trying to charm itself!", GetGUID().ToString());
11480 return false;
11481 }
11482
11483 //if (HasUnitState(UNIT_STATE_UNATTACKABLE))
11484 // return false;
11485
11487 {
11488 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} is trying to charm Player {} on transport", charmer->GetGUID().ToString(), GetGUID().ToString());
11489 return false;
11490 }
11491
11492 // Already charmed
11493 if (!GetCharmerGUID().IsEmpty())
11494 {
11495 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} has already been charmed but {} is trying to charm it!", GetGUID().ToString(), charmer->GetGUID().ToString());
11496 return false;
11497 }
11498
11499 CastStop();
11500 AttackStop();
11501
11502 Player* playerCharmer = charmer->ToPlayer();
11503
11504 // Charmer stop charming
11505 if (playerCharmer)
11506 {
11507 playerCharmer->StopCastingCharm();
11508 playerCharmer->StopCastingBindSight();
11509 }
11510
11511 // Charmed stop charming
11512 if (GetTypeId() == TYPEID_PLAYER)
11513 {
11516 }
11517
11518 // StopCastingCharm may remove a possessed pet?
11519 if (!IsInWorld())
11520 {
11521 TC_LOG_FATAL("entities.unit", "Unit::SetCharmedBy: {} is not in world but {} is trying to charm it!", GetGUID().ToString(), charmer->GetGUID().ToString());
11522 return false;
11523 }
11524
11525 // charm is set by aura, and aura effect remove handler was called during apply handler execution
11526 // prevent undefined behaviour
11527 if (aurApp && aurApp->GetRemoveMode())
11528 return false;
11529
11531 SetFaction(charmer->GetFaction());
11532
11533 // Pause any Idle movement
11534 PauseMovement(0, 0, false);
11535
11536 // Remove any active voluntary movement
11538
11539 // Stop any remaining spline, if no involuntary movement is found
11540 auto criteria = [](MovementGenerator const* movement) -> bool
11541 {
11542 return movement->Priority == MOTION_PRIORITY_HIGHEST;
11543 };
11544 if (!GetMotionMaster()->HasMovementGenerator(criteria))
11545 StopMoving();
11546
11547 // Set charmed
11548 charmer->SetCharm(this, true);
11550
11551 if (Player* player = ToPlayer())
11552 {
11553 if (player->isAFK())
11554 player->ToggleAFK();
11555
11556 player->SetClientControl(this, false);
11557 }
11558
11559 // charm is set by aura, and aura effect remove handler was called during apply handler execution
11560 // prevent undefined behaviour
11561 if (aurApp && aurApp->GetRemoveMode())
11562 {
11563 // properly clean up charm changes up to this point to avoid leaving the unit in partially charmed state
11566 charmer->SetCharm(this, false);
11567 return false;
11568 }
11569
11570 // Pets already have a properly initialized CharmInfo, don't overwrite it.
11571 if (type != CHARM_TYPE_VEHICLE && !GetCharmInfo())
11572 {
11573 InitCharmInfo();
11574 if (type == CHARM_TYPE_POSSESS)
11576 else
11578 }
11579
11580 if (playerCharmer)
11581 {
11582 switch (type)
11583 {
11584 case CHARM_TYPE_VEHICLE:
11586 playerCharmer->SetClientControl(this, true);
11587 playerCharmer->VehicleSpellInitialize();
11588 break;
11589 case CHARM_TYPE_POSSESS:
11592 playerCharmer->SetClientControl(this, true);
11593 playerCharmer->PossessSpellInitialize();
11595 break;
11596 case CHARM_TYPE_CHARM:
11597 if (GetTypeId() == TYPEID_UNIT && charmer->GetClass() == CLASS_WARLOCK)
11598 {
11600 if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
11601 {
11602 // to prevent client crash
11604
11605 // just to enable stat window
11606 if (GetCharmInfo())
11607 GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true);
11608
11609 // if charmed two demons the same session, the 2nd gets the 1st one's name
11610 SetPetNameTimestamp(uint32(GameTime::GetGameTime())); // cast can't be helped
11611 }
11612 }
11613 playerCharmer->CharmSpellInitialize();
11614 break;
11615 default:
11616 case CHARM_TYPE_CONVERT:
11617 break;
11618 }
11619 }
11620
11622
11623 if (Creature* creature = ToCreature())
11624 creature->RefreshCanSwimFlag();
11625
11626 if ((GetTypeId() != TYPEID_PLAYER) || (charmer->GetTypeId() != TYPEID_PLAYER))
11627 {
11628 // AI will schedule its own change if appropriate
11629 if (UnitAI* ai = GetAI())
11630 ai->OnCharmed(false);
11631 else
11633 }
11634 return true;
11635}
11636
11638{
11639 if (!IsCharmed())
11640 return;
11641
11642 if (charmer)
11643 ASSERT(charmer == GetCharmer());
11644 else
11645 charmer = GetCharmer();
11646
11647 ASSERT(charmer);
11648
11649 CharmType type;
11651 type = CHARM_TYPE_POSSESS;
11652 else if (charmer->IsOnVehicle(this))
11653 type = CHARM_TYPE_VEHICLE;
11654 else
11655 type = CHARM_TYPE_CHARM;
11656
11657 CastStop();
11658 AttackStop();
11659
11660 if (_oldFactionId)
11661 {
11663 _oldFactionId = 0;
11664 }
11665 else
11667
11668 if (type != CHARM_TYPE_CHARM && !IsPlayer())
11669 {
11670 StopMoving(true);
11671
11672 // Purge flags left over by client control
11674 }
11675
11678
11679 // Vehicle should not attack its passenger after he exists the seat
11680 if (type != CHARM_TYPE_VEHICLE)
11681 LastCharmerGUID = charmer->GetGUID();
11682
11683 ASSERT(type != CHARM_TYPE_POSSESS || charmer->GetTypeId() == TYPEID_PLAYER);
11685
11686 charmer->SetCharm(this, false);
11688
11689 Player* playerCharmer = charmer->ToPlayer();
11690 if (playerCharmer)
11691 {
11692 switch (type)
11693 {
11694 case CHARM_TYPE_VEHICLE:
11695 playerCharmer->SetClientControl(this, false);
11696 playerCharmer->SetClientControl(charmer, true);
11698 break;
11699 case CHARM_TYPE_POSSESS:
11701 playerCharmer->SetClientControl(this, false);
11702 playerCharmer->SetClientControl(charmer, true);
11705 break;
11706 case CHARM_TYPE_CHARM:
11707 if (GetTypeId() == TYPEID_UNIT && charmer->GetClass() == CLASS_WARLOCK)
11708 {
11710 if (cinfo && cinfo->type == CREATURE_TYPE_DEMON)
11711 {
11712 SetClass(uint8(cinfo->unit_class));
11713 if (GetCharmInfo())
11714 GetCharmInfo()->SetPetNumber(0, true);
11715 else
11716 TC_LOG_ERROR("entities.unit", "Aura::HandleModCharm: {} has a charm aura but no charm info!", GetGUID().ToString());
11717 }
11718 }
11719 break;
11720 case CHARM_TYPE_CONVERT:
11721 break;
11722 }
11723 }
11724
11725 if (Player* player = ToPlayer())
11726 player->SetClientControl(this, true);
11727
11728 if (playerCharmer && this != charmer->GetFirstControlled())
11729 playerCharmer->SendRemoveControlBar();
11730
11731 // a guardian should always have charminfo
11732 if (!IsGuardian())
11734
11735 // reset confused movement for example
11737
11738 if (GetTypeId() != TYPEID_PLAYER || charmer->GetTypeId() == TYPEID_UNIT)
11739 {
11740 if (UnitAI* charmedAI = GetAI())
11741 charmedAI->OnCharmed(false); // AI will potentially schedule a charm ai update
11742 else
11744 }
11745}
11746
11748{
11749 if (GetTypeId() == TYPEID_PLAYER)
11751 else
11752 {
11754 {
11755 if (Unit* owner = GetOwner())
11756 {
11757 SetFaction(owner->GetFaction());
11758 return;
11759 }
11760 }
11761
11762 if (CreatureTemplate const* cinfo = ToCreature()->GetCreatureTemplate()) // normal creature
11763 SetFaction(cinfo->faction);
11764 }
11765}
11766
11767bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry)
11768{
11769 VehicleEntry const* vehInfo = sVehicleStore.LookupEntry(id);
11770 if (!vehInfo)
11771 return false;
11772
11773 m_vehicleKit = Trinity::make_unique_trackable<Vehicle>(this, vehInfo, creatureEntry);
11776 return true;
11777}
11778
11780{
11781 if (!m_vehicleKit)
11782 return;
11783
11785 m_vehicleKit = nullptr;
11786
11787 m_updateFlag &= ~UPDATEFLAG_VEHICLE;
11788 m_unitTypeMask &= ~UNIT_MASK_VEHICLE;
11790}
11791
11792bool Unit::IsOnVehicle(Unit const* vehicle) const
11793{
11794 return m_vehicle && m_vehicle == vehicle->GetVehicleKit();
11795}
11796
11798{
11799 return m_vehicle ? m_vehicle->GetBase() : nullptr;
11800}
11801
11803{
11804 Unit* vehicleRoot = GetVehicleBase();
11805
11806 if (!vehicleRoot)
11807 return nullptr;
11808
11809 for (;;)
11810 {
11811 if (!vehicleRoot->GetVehicleBase())
11812 return vehicleRoot;
11813
11814 vehicleRoot = vehicleRoot->GetVehicleBase();
11815 }
11816}
11817
11819{
11820 if (Unit* veh = GetVehicleBase())
11821 if (Creature* c = veh->ToCreature())
11822 return c;
11823
11824 return nullptr;
11825}
11826
11828{
11829 if (GetVehicle())
11830 return GetVehicleBase()->GetGUID();
11831 if (GetTransport())
11832 return GetTransport()->GetGUID();
11833
11834 return ObjectGuid::Empty;
11835}
11836
11838{
11839 if (Vehicle* veh = GetVehicle())
11840 return veh;
11841 return GetTransport();
11842}
11843
11844bool Unit::IsInPartyWith(Unit const* unit) const
11845{
11846 if (this == unit)
11847 return true;
11848
11849 Unit const* u1 = GetCharmerOrOwnerOrSelf();
11850 Unit const* u2 = unit->GetCharmerOrOwnerOrSelf();
11851 if (u1 == u2)
11852 return true;
11853
11854 if (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
11855 return u1->ToPlayer()->IsInSameGroupWith(u2->ToPlayer());
11858 return true;
11859
11860 return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
11861}
11862
11863bool Unit::IsInRaidWith(Unit const* unit) const
11864{
11865 if (this == unit)
11866 return true;
11867
11868 Unit const* u1 = GetCharmerOrOwnerOrSelf();
11869 Unit const* u2 = unit->GetCharmerOrOwnerOrSelf();
11870 if (u1 == u2)
11871 return true;
11872
11873 if (u1->GetTypeId() == TYPEID_PLAYER && u2->GetTypeId() == TYPEID_PLAYER)
11874 return u1->ToPlayer()->IsInSameRaidWith(u2->ToPlayer());
11877 return true;
11878
11879 return u1->GetTypeId() == TYPEID_UNIT && u2->GetTypeId() == TYPEID_UNIT && u1->GetFaction() == u2->GetFaction();
11880}
11881
11882void Unit::GetPartyMembers(std::list<Unit*> &TagUnitMap)
11883{
11884 Unit* owner = GetCharmerOrOwnerOrSelf();
11885 Group* group = nullptr;
11886 if (owner->GetTypeId() == TYPEID_PLAYER)
11887 group = owner->ToPlayer()->GetGroup();
11888
11889 if (group)
11890 {
11891 uint8 subgroup = owner->ToPlayer()->GetSubGroup();
11892
11893 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
11894 {
11895 Player* Target = itr->GetSource();
11896
11897 // IsHostileTo check duel and controlled by enemy
11898 if (Target && Target->IsInMap(owner) && Target->GetSubGroup() == subgroup && !IsHostileTo(Target))
11899 {
11900 if (Target->IsAlive())
11901 TagUnitMap.push_back(Target);
11902
11903 if (Guardian* pet = Target->GetGuardianPet())
11904 if (pet->IsAlive())
11905 TagUnitMap.push_back(pet);
11906 }
11907 }
11908 }
11909 else
11910 {
11911 if ((owner == this || IsInMap(owner)) && owner->IsAlive())
11912 TagUnitMap.push_back(owner);
11913 if (Guardian* pet = owner->GetGuardianPet())
11914 if ((pet == this || IsInMap(pet)) && pet->IsAlive())
11915 TagUnitMap.push_back(pet);
11916 }
11917}
11918
11920{
11921 if (FactionTemplateEntry const* entry = GetFactionTemplateEntry())
11922 return entry->IsContestedGuardFaction();
11923
11924 return false;
11925}
11926
11927void Unit::SetPvP(bool state)
11928{
11929 if (state)
11931 else
11933}
11934
11935Aura* Unit::AddAura(uint32 spellId, Unit* target)
11936{
11937 if (!target)
11938 return nullptr;
11939
11940 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
11941 if (!spellInfo)
11942 return nullptr;
11943
11944 return AddAura(spellInfo, MAX_EFFECT_MASK, target);
11945}
11946
11947Aura* Unit::AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target)
11948{
11949 if (!spellInfo)
11950 return nullptr;
11951
11952 if (!target->IsAlive() && !spellInfo->IsPassive() && !spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_DEAD))
11953 return nullptr;
11954
11955 if (target->IsImmunedToSpell(spellInfo, this))
11956 return nullptr;
11957
11958 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
11959 {
11960 if (!(effMask & (1 << spellEffectInfo.EffectIndex)))
11961 continue;
11962
11963 if (target->IsImmunedToSpellEffect(spellInfo, spellEffectInfo, this))
11964 effMask &= ~(1 << spellEffectInfo.EffectIndex);
11965 }
11966
11967 if (!effMask)
11968 return nullptr;
11969
11970 AuraCreateInfo createInfo(spellInfo, effMask, target);
11971 createInfo.SetCaster(this);
11972
11973 if (Aura* aura = Aura::TryRefreshStackOrCreate(createInfo))
11974 {
11975 aura->ApplyForTargets();
11976 return aura;
11977 }
11978 return nullptr;
11979}
11980
11981void Unit::SetAuraStack(uint32 spellId, Unit* target, uint32 stack)
11982{
11983 Aura* aura = target->GetAura(spellId, GetGUID());
11984 if (!aura)
11985 aura = AddAura(spellId, target);
11986 if (aura && stack)
11987 aura->SetStackAmount(stack);
11988}
11989
11991{
11992 WorldPackets::Spells::PlaySpellVisualKit playSpellVisualKit(type);
11993 playSpellVisualKit.Unit = GetGUID();
11994 playSpellVisualKit.KitRecID = id;
11995 SendMessageToSet(playSpellVisualKit.Write(), true);
11996}
11997
11999{
12000 return !IsVehicle() && GetOwnerGUID().IsPlayer();
12001}
12002
12003/*static*/ void Unit::ApplyResilience(Unit const* victim, float* crit, int32* damage, bool isCrit, CombatRating type)
12004{
12005 // player mounted on multi-passenger mount is also classified as vehicle
12006 if (victim->IsVehicle() && victim->GetTypeId() != TYPEID_PLAYER)
12007 return;
12008
12009 Unit const* target = nullptr;
12010 if (victim->GetTypeId() == TYPEID_PLAYER)
12011 target = victim;
12012 else // victim->GetTypeId() == TYPEID_UNIT
12013 {
12014 if (Unit* owner = victim->GetOwner())
12015 if (owner->GetTypeId() == TYPEID_PLAYER)
12016 target = owner;
12017 }
12018
12019 if (!target)
12020 return;
12021
12022 switch (type)
12023 {
12025 // Crit chance reduction works against nonpets
12026 if (crit)
12027 *crit -= target->GetMeleeCritChanceReduction();
12028 if (damage)
12029 {
12030 if (isCrit)
12031 *damage -= target->GetMeleeCritDamageReduction(*damage);
12032 *damage -= target->GetMeleeDamageReduction(*damage);
12033 }
12034 break;
12036 // Crit chance reduction works against nonpets
12037 if (crit)
12038 *crit -= target->GetRangedCritChanceReduction();
12039 if (damage)
12040 {
12041 if (isCrit)
12042 *damage -= target->GetRangedCritDamageReduction(*damage);
12043 *damage -= target->GetRangedDamageReduction(*damage);
12044 }
12045 break;
12047 // Crit chance reduction works against nonpets
12048 if (crit)
12049 *crit -= target->GetSpellCritChanceReduction();
12050 if (damage)
12051 {
12052 if (isCrit)
12053 *damage -= target->GetSpellCritDamageReduction(*damage);
12054 *damage -= target->GetSpellDamageReduction(*damage);
12055 }
12056 break;
12057 default:
12058 break;
12059 }
12060}
12061
12062int32 Unit::CalculateAOEAvoidance(int32 damage, uint32 schoolMask, ObjectGuid const& casterGuid) const
12063{
12064 damage = int32(float(damage) * GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, schoolMask));
12065 if (casterGuid.IsAnyTypeCreature())
12067
12068 return damage;
12069}
12070
12071// Melee based spells can be miss, parry or dodge on this step
12072// Crit or block - determined on damage calculation phase! (and can be both in some time)
12073float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const
12074{
12075 SpellInfo const* spellInfo = spellId ? sSpellMgr->GetSpellInfo(spellId) : nullptr;
12076 if (spellInfo && spellInfo->HasAttribute(SPELL_ATTR7_CANT_MISS))
12077 return 0.f;
12078
12079 //calculate miss chance
12080 float missChance = victim->GetUnitMissChance();
12081
12082 // Check if dual wielding, add additional miss penalty - when mainhand has on next swing spell, offhand doesnt suffer penalty
12083 if (!spellId && haveOffhandWeapon() && attType != RANGED_ATTACK && !m_currentSpells[CURRENT_MELEE_SPELL])
12084 missChance += 19.0f;
12085
12086 // bonus from skills is 0.04%
12087 //miss_chance -= skillDiff * 0.04f;
12088 int32 diff = -skillDiff;
12089 if (victim->GetTypeId() == TYPEID_PLAYER)
12090 missChance += diff > 0 ? diff * 0.04f : diff * 0.02f;
12091 else
12092 {
12093 missChance += diff > 10 ? 1 + (diff - 10) * 0.4f : diff * 0.1f;
12094 float levelFactor = victim->GetLevelForTarget(this);
12095 if (levelFactor < 10.f)
12096 missChance *= (levelFactor / 10.f);
12097 }
12098
12099 // Spellmod from SPELLMOD_RESIST_MISS_CHANCE
12100 float resistMissChance = 100.0f;
12101 if (spellId)
12102 {
12103 if (Player* modOwner = GetSpellModOwner())
12104 modOwner->ApplySpellMod(spellId, SPELLMOD_RESIST_MISS_CHANCE, resistMissChance);
12105 }
12106 missChance -= resistMissChance - 100.0f;
12107
12108 if (attType == RANGED_ATTACK)
12109 missChance -= m_modRangedHitChance;
12110 else
12111 missChance -= m_modMeleeHitChance;
12112
12113 // miss chance from auras after calculating skill based miss
12115 if (attType == RANGED_ATTACK)
12117 else
12119
12120 return std::max(missChance, 0.f);
12121}
12122
12123void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
12124{
12125 if (newPhaseMask == GetPhaseMask())
12126 return;
12127
12128 // Phase player, dont update
12129 WorldObject::SetPhaseMask(newPhaseMask, false);
12130
12131 // Phase pets and summons
12132 if (IsInWorld())
12133 {
12134 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
12135 if ((*itr)->GetTypeId() == TYPEID_UNIT)
12136 (*itr)->SetPhaseMask(newPhaseMask, true);
12137
12138 for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
12139 if (!m_SummonSlot[i].IsEmpty())
12140 if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
12141 summon->SetPhaseMask(newPhaseMask, true);
12142
12143 RemoveNotOwnSingleTargetAuras(newPhaseMask); // we can lost access to caster or target
12144 }
12145
12146 // Update visibility after phasing pets and summons so they wont despawn
12147 if (update)
12149}
12150
12152{
12153 if (!forced)
12155 else
12156 {
12158 // call MoveInLineOfSight for nearby creatures
12159 Trinity::AIRelocationNotifier notifier(*this);
12160 Cell::VisitAllObjects(this, notifier, GetVisibilityRange());
12161 }
12162}
12163
12164void Unit::SendMoveKnockBack(Player* player, float speedXY, float speedZ, float vcos, float vsin)
12165{
12166 WorldPacket data(SMSG_MOVE_KNOCK_BACK, (8 + 4 + 4 + 4 + 4 + 4));
12167 data << GetPackGUID();
12168 data << uint32(0); // counter
12169 data << TaggedPosition<Position::XY>(vcos, vsin);
12170 data << float(speedXY); // Horizontal speed
12171 data << float(speedZ); // Z Movement speed (vertical)
12172 player->SendDirectMessage(&data);
12173}
12174
12175void Unit::KnockbackFrom(float x, float y, float speedXY, float speedZ)
12176{
12177 if (IsMovedByServer())
12178 {
12179 GetMotionMaster()->MoveKnockbackFrom(x, y, speedXY, speedZ);
12180 }
12181 else
12182 {
12183 float vcos, vsin;
12184 GetSinCos(x, y, vsin, vcos);
12185 SendMoveKnockBack(GetGameClientMovingMe()->GetBasePlayer(), speedXY, -speedZ, vcos, vsin);
12186
12188 SetCanFly(true, true);
12189 }
12190}
12191
12193{
12194 if (Player const* player = ToPlayer())
12195 return player->GetRatingBonusValue(cr);
12196 // Player's pet get resilience from owner
12197 else if (IsPet() && GetOwner())
12198 if (Player* owner = GetOwner()->ToPlayer())
12199 return owner->GetRatingBonusValue(cr);
12200
12201 return 0.0f;
12202}
12203
12204uint32 Unit::GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const
12205{
12206 float percent = std::min(GetCombatRatingReduction(cr) * rate, cap);
12207 return CalculatePct(damage, percent);
12208}
12209
12211{
12212 // Hardcoded cases
12213 switch (spellId)
12214 {
12215 case 7090: // Bear Form
12216 return 29414;
12217 case 35200: // Roc Form
12218 return 4877;
12219 default:
12220 break;
12221 }
12222
12223 if (Player const* player = ToPlayer())
12224 {
12225 switch (form)
12226 {
12227 case FORM_CAT:
12228 // Based on Hair color
12229 if (GetRace() == RACE_NIGHTELF)
12230 {
12231 switch (player->GetHairColorId())
12232 {
12233 case 7: // Violet
12234 case 8:
12235 return 29405;
12236 case 3: // Light Blue
12237 return 29406;
12238 case 0: // Green
12239 case 1: // Light Green
12240 case 2: // Dark Green
12241 return 29407;
12242 case 4: // White
12243 return 29408;
12244 default: // original - Dark Blue
12245 return 892;
12246 }
12247 }
12248 // Based on Skin color
12249 else if (GetRace() == RACE_TAUREN)
12250 {
12251 uint8 skinColor = player->GetSkinId();
12252 // Male
12254 {
12255 switch (skinColor)
12256 {
12257 case 12: // White
12258 case 13:
12259 case 14:
12260 case 18: // Completly White
12261 return 29409;
12262 case 9: // Light Brown
12263 case 10:
12264 case 11:
12265 return 29410;
12266 case 6: // Brown
12267 case 7:
12268 case 8:
12269 return 29411;
12270 case 0: // Dark
12271 case 1:
12272 case 2:
12273 case 3: // Dark Grey
12274 case 4:
12275 case 5:
12276 return 29412;
12277 default: // original - Grey
12278 return 8571;
12279 }
12280 }
12281 // Female
12282 else
12283 {
12284 switch (skinColor)
12285 {
12286 case 10: // White
12287 return 29409;
12288 case 6: // Light Brown
12289 case 7:
12290 return 29410;
12291 case 4: // Brown
12292 case 5:
12293 return 29411;
12294 case 0: // Dark
12295 case 1:
12296 case 2:
12297 case 3:
12298 return 29412;
12299 default: // original - Grey
12300 return 8571;
12301 }
12302 }
12303 }
12304 else if (Player::TeamForRace(GetRace()) == ALLIANCE)
12305 return 892;
12306 else
12307 return 8571;
12308 case FORM_DIREBEAR:
12309 case FORM_BEAR:
12310 // Based on Hair color
12311 if (GetRace() == RACE_NIGHTELF)
12312 {
12313 switch (player->GetHairColorId())
12314 {
12315 case 0: // Green
12316 case 1: // Light Green
12317 case 2: // Dark Green
12318 return 29413; // 29415?
12319 case 6: // Dark Blue
12320 return 29414;
12321 case 4: // White
12322 return 29416;
12323 case 3: // Light Blue
12324 return 29417;
12325 default: // original - Violet
12326 return 2281;
12327 }
12328 }
12329 // Based on Skin color
12330 else if (GetRace() == RACE_TAUREN)
12331 {
12332 uint8 skinColor = player->GetSkinId();
12333 // Male
12335 {
12336 switch (skinColor)
12337 {
12338 case 0: // Dark (Black)
12339 case 1:
12340 case 2:
12341 return 29418;
12342 case 3: // White
12343 case 4:
12344 case 5:
12345 case 12:
12346 case 13:
12347 case 14:
12348 return 29419;
12349 case 9: // Light Brown/Grey
12350 case 10:
12351 case 11:
12352 case 15:
12353 case 16:
12354 case 17:
12355 return 29420;
12356 case 18: // Completly White
12357 return 29421;
12358 default: // original - Brown
12359 return 2289;
12360 }
12361 }
12362 // Female
12363 else
12364 {
12365 switch (skinColor)
12366 {
12367 case 0: // Dark (Black)
12368 case 1:
12369 return 29418;
12370 case 2: // White
12371 case 3:
12372 return 29419;
12373 case 6: // Light Brown/Grey
12374 case 7:
12375 case 8:
12376 case 9:
12377 return 29420;
12378 case 10: // Completly White
12379 return 29421;
12380 default: // original - Brown
12381 return 2289;
12382 }
12383 }
12384 }
12385 else if (Player::TeamForRace(GetRace()) == ALLIANCE)
12386 return 2281;
12387 else
12388 return 2289;
12389 case FORM_FLIGHT:
12391 return 20857;
12392 return 20872;
12393 case FORM_FLIGHT_EPIC:
12395 return 21243;
12396 return 21244;
12397 default:
12398 break;
12399 }
12400 }
12401
12402 uint32 modelid = 0;
12403 SpellShapeshiftFormEntry const* formEntry = sSpellShapeshiftFormStore.LookupEntry(form);
12404 if (formEntry && formEntry->CreatureDisplayID[0])
12405 {
12406 // Take the alliance modelid as default
12407 if (GetTypeId() != TYPEID_PLAYER)
12408 return formEntry->CreatureDisplayID[0];
12409 else
12410 {
12412 modelid = formEntry->CreatureDisplayID[0];
12413 else
12414 modelid = formEntry->CreatureDisplayID[1];
12415
12416 // If the player is horde but there are no values for the horde modelid - take the alliance modelid
12417 if (!modelid && Player::TeamForRace(GetRace()) == HORDE)
12418 modelid = formEntry->CreatureDisplayID[0];
12419 }
12420 }
12421
12422 return modelid;
12423}
12424
12425void Unit::JumpTo(float speedXY, float speedZ, bool forward, Optional<Position> dest)
12426{
12427 float angle = forward ? 0 : float(M_PI);
12428 if (dest)
12429 angle += GetRelativeAngle(*dest);
12430
12431 if (GetTypeId() == TYPEID_UNIT)
12432 GetMotionMaster()->MoveJumpTo(angle, speedXY, speedZ);
12433 else
12434 {
12435 float vcos = std::cos(angle+GetOrientation());
12436 float vsin = std::sin(angle+GetOrientation());
12437 SendMoveKnockBack(ToPlayer(), speedXY, -speedZ, vcos, vsin);
12438 }
12439}
12440
12441void Unit::JumpTo(WorldObject* obj, float speedZ, bool withOrientation)
12442{
12443 float x, y, z;
12444 obj->GetContactPoint(this, x, y, z);
12445 float speedXY = GetExactDist2d(x, y) * 10.0f / speedZ;
12446 GetMotionMaster()->MoveJump(x, y, z, GetAbsoluteAngle(obj), speedXY, speedZ, EVENT_JUMP, withOrientation);
12447}
12448
12449void Unit::HandleSpellClick(Unit* clicker, int8 seatId /*= -1*/)
12450{
12451 bool spellClickHandled = false;
12452 uint32 spellClickEntry = GetVehicleKit() ? GetVehicleKit()->GetCreatureEntry() : GetEntry();
12454
12455 auto clickBounds = sObjectMgr->GetSpellClickInfoMapBounds(spellClickEntry);
12456 for (auto const& clickPair : clickBounds)
12457 {
12459 if (!clickPair.second.IsFitToRequirements(clicker, this))
12460 continue;
12461
12463 if (!sConditionMgr->IsObjectMeetingSpellClickConditions(spellClickEntry, clickPair.second.spellId, clicker, this))
12464 continue;
12465
12466 Unit* caster = (clickPair.second.castFlags & NPC_CLICK_CAST_CASTER_CLICKER) ? clicker : this;
12467 Unit* target = (clickPair.second.castFlags & NPC_CLICK_CAST_TARGET_CLICKER) ? clicker : this;
12468 ObjectGuid origCasterGUID = (clickPair.second.castFlags & NPC_CLICK_CAST_ORIG_CASTER_OWNER) ? GetOwnerGUID() : clicker->GetGUID();
12469
12470 SpellInfo const* spellEntry = sSpellMgr->AssertSpellInfo(clickPair.second.spellId);
12471 // if (!spellEntry) should be checked at npc_spellclick load
12472
12473 if (seatId > -1)
12474 {
12475 uint8 i = 0;
12476 bool valid = false;
12477 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
12478 {
12479 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_CONTROL_VEHICLE)
12480 {
12481 valid = true;
12482 break;
12483 }
12484 ++i;
12485 }
12486
12487 if (!valid)
12488 {
12489 TC_LOG_ERROR("sql.sql", "Spell {} specified in npc_spellclick_spells is not a valid vehicle enter aura!", clickPair.second.spellId);
12490 continue;
12491 }
12492
12493 if (IsInMap(caster))
12494 {
12496 args.OriginalCaster = origCasterGUID;
12497 args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + i), seatId + 1);
12498 caster->CastSpell(target, clickPair.second.spellId, args);
12499 }
12500 else // This can happen during Player::_LoadAuras
12501 {
12502 int32 bp[MAX_SPELL_EFFECTS] = { };
12503 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
12504 bp[spellEffectInfo.EffectIndex] = spellEffectInfo.BasePoints;
12505
12506 bp[i] = seatId;
12507
12508 AuraCreateInfo createInfo(spellEntry, MAX_EFFECT_MASK, this);
12509 createInfo
12510 .SetCaster(clicker)
12511 .SetBaseAmount(bp)
12512 .SetCasterGUID(origCasterGUID);
12513
12515 }
12516 }
12517 else
12518 {
12519 if (IsInMap(caster))
12520 caster->CastSpell(target, spellEntry->Id, CastSpellExtraArgs().SetOriginalCaster(origCasterGUID));
12521 else
12522 {
12523 AuraCreateInfo createInfo(spellEntry, MAX_EFFECT_MASK, this);
12524 createInfo
12525 .SetCaster(clicker)
12526 .SetCasterGUID(origCasterGUID);
12527
12529 }
12530 }
12531
12532 spellClickHandled = true;
12533 }
12534
12535 Creature* creature = ToCreature();
12536 if (creature && creature->IsAIEnabled())
12537 creature->AI()->OnSpellClick(clicker, spellClickHandled);
12538}
12539
12540void Unit::EnterVehicle(Unit* base, int8 seatId /*= -1*/)
12541{
12543 args.AddSpellBP0(seatId + 1);
12545}
12546
12547void Unit::_EnterVehicle(Vehicle* vehicle, int8 seatId, AuraApplication const* aurApp)
12548{
12549 // Must be called only from aura handler
12550 ASSERT(aurApp);
12551
12552 if (!IsAlive() || GetVehicleKit() == vehicle || vehicle->GetBase()->IsOnVehicle(this))
12553 return;
12554
12555 if (m_vehicle)
12556 {
12557 if (m_vehicle != vehicle)
12558 {
12559 TC_LOG_DEBUG("entities.vehicle", "EnterVehicle: {} exit {} and enter {}.", GetEntry(), m_vehicle->GetBase()->GetEntry(), vehicle->GetBase()->GetEntry());
12560 ExitVehicle();
12561 }
12562 else if (seatId >= 0 && seatId == GetTransSeat())
12563 return;
12564 else
12565 {
12566 //Exit the current vehicle because unit will reenter in a new seat.
12568 }
12569 }
12570
12571 if (aurApp->GetRemoveMode())
12572 return;
12573
12574 if (Player* player = ToPlayer())
12575 {
12576 if (vehicle->GetBase()->GetTypeId() == TYPEID_PLAYER && player->IsInCombat())
12577 {
12578 vehicle->GetBase()->RemoveAura(const_cast<AuraApplication*>(aurApp));
12579 return;
12580 }
12581
12582 if (Creature* vehicleBaseCreature = vehicle->GetBase()->ToCreature())
12583 {
12584 // If a player entered a vehicle that is part of a formation, remove it from said formation
12585 if (CreatureGroup* creatureGroup = vehicleBaseCreature->GetFormation())
12586 sFormationMgr->RemoveCreatureFromGroup(creatureGroup, vehicleBaseCreature);
12587 }
12588 }
12589
12590 // If vehicle flag for fixed position set (cannons), or if the following hardcoded units, then set state rooted
12591 // 30236 | Argent Cannon
12592 // 39759 | Tankbuster Cannon
12593 if ((vehicle->GetVehicleInfo()->Flags & VEHICLE_FLAG_FIXED_POSITION) || vehicle->GetBase()->GetEntry() == 30236 || vehicle->GetBase()->GetEntry() == 39759)
12595
12596 ASSERT(!m_vehicle);
12597 (void)vehicle->AddPassenger(this, seatId);
12598}
12599
12600void Unit::ChangeSeat(int8 seatId, bool next)
12601{
12602 if (!m_vehicle)
12603 return;
12604
12605 // Don't change if current and new seat are identical
12606 if (seatId == GetTransSeat())
12607 return;
12608
12609 SeatMap::const_iterator seat = (seatId < 0 ? m_vehicle->GetNextEmptySeat(GetTransSeat(), next) : m_vehicle->Seats.find(seatId));
12610 // The second part of the check will only return true if seatId >= 0. @Vehicle::GetNextEmptySeat makes sure of that.
12611 if (seat == m_vehicle->Seats.end() || !seat->second.IsEmpty())
12612 return;
12613
12614 AuraEffect* rideVehicleEffect = nullptr;
12616 for (AuraEffectList::const_iterator itr = vehicleAuras.begin(); itr != vehicleAuras.end(); ++itr)
12617 {
12618 if ((*itr)->GetCasterGUID() != GetGUID())
12619 continue;
12620
12621 // Make sure there is only one ride vehicle aura on target cast by the unit changing seat
12622 ASSERT(!rideVehicleEffect);
12623 rideVehicleEffect = *itr;
12624 }
12625
12626 // Unit riding a vehicle must always have control vehicle aura on target
12627 ASSERT(rideVehicleEffect);
12628
12629 rideVehicleEffect->ChangeAmount(seat->first + 1);
12630}
12631
12632void Unit::ExitVehicle(Position const* /*exitPosition*/)
12633{
12635 if (!m_vehicle)
12636 return;
12637
12642 /*_ExitVehicle(exitPosition);*/
12649}
12650
12651void Unit::_ExitVehicle(Position const* exitPosition)
12652{
12656 if (!m_vehicle)
12657 return;
12658
12659 // This should be done before dismiss, because there may be some aura removal
12661 Vehicle* vehicle = m_vehicle->RemovePassenger(this);
12662
12663 if (!vehicle)
12664 {
12665 TC_LOG_ERROR("entities.vehicle", "RemovePassenger() couldn't remove current unit from vehicle. Debug info: {}", GetDebugInfo());
12666 return;
12667 }
12668
12669 Player* player = ToPlayer();
12670
12671 // If the player is on mounted duel and exits the mount, he should immediatly lose the duel
12672 if (player && player->duel && player->duel->IsMounted)
12673 player->DuelComplete(DUEL_FLED);
12674
12675 SetControlled(false, UNIT_STATE_ROOT); // SMSG_MOVE_FORCE_UNROOT, ~MOVEMENTFLAG_ROOT
12676
12678
12679 if (player)
12680 player->SetFallInformation(0, GetPositionZ());
12682 {
12684 data << GetPackGUID();
12685 SendMessageToSet(&data, false);
12686 }
12687
12688 Position pos;
12689 // If we ask for a specific exit position, use that one. Otherwise allow scripts to modify it
12690 if (exitPosition)
12691 pos = *exitPosition;
12692 else
12693 {
12694 // Set exit position to vehicle position and use the current orientation
12695 pos = vehicle->GetBase()->GetPosition();
12697
12698 // Change exit position based on seat entry addon data
12699 if (seatAddon)
12700 {
12702 pos.RelocateOffset({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
12704 pos.Relocate({ seatAddon->ExitParameterX, seatAddon->ExitParameterY, seatAddon->ExitParameterZ, seatAddon->ExitParameterO });
12705 }
12706 }
12707
12708 std::function<void(Movement::MoveSplineInit&)> initializer = [=, this, vehicleCollisionHeight = vehicle->GetBase()->GetCollisionHeight()](Movement::MoveSplineInit& init)
12709 {
12710 float height = pos.GetPositionZ() + vehicleCollisionHeight;
12711
12712 // Creatures without inhabit type air should begin falling after exiting the vehicle
12713 if (GetTypeId() == TYPEID_UNIT && !CanFly() && height > GetMap()->GetWaterOrGroundLevel(GetPhaseMask(), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() + vehicleCollisionHeight, &height))
12714 init.SetFall();
12715
12716 init.MoveTo(pos.GetPositionX(), pos.GetPositionY(), height, false);
12717 init.SetFacing(pos.GetOrientation());
12718 init.SetTransportExit();
12719 };
12721
12722 if (player)
12724
12725 if (vehicle->GetBase()->HasUnitTypeMask(UNIT_MASK_MINION) && vehicle->GetBase()->GetTypeId() == TYPEID_UNIT)
12726 if (((Minion*)vehicle->GetBase())->GetOwner() == this)
12727 vehicle->GetBase()->ToCreature()->DespawnOrUnsummon(vehicle->GetDespawnDelay());
12728
12730 {
12731 // Vehicle just died, we die too
12732 if (vehicle->GetBase()->getDeathState() == JUST_DIED)
12734 // If for other reason we as minion are exiting the vehicle (ejected, master dismounted) - unsummon
12735 else
12736 ToTempSummon()->UnSummon(2000); // Approximation
12737 }
12738}
12739
12744
12745void Unit::BuildMovementPacket(Position const& pos, Position const& transportPos, MovementInfo const& movementInfo, ByteBuffer* data)
12746{
12747 *data << uint32(movementInfo.GetMovementFlags());
12748 *data << uint16(movementInfo.GetExtraMovementFlags());
12749 *data << uint32(GameTime::GetGameTimeMS()); // time / counter
12750 *data << TaggedPosition<Position::XYZO>(pos);
12751
12752 // 0x00000200
12753 if (movementInfo.HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT))
12754 {
12755 *data << movementInfo.transport.guid.WriteAsPacked();
12756 *data << TaggedPosition<Position::XYZO>(transportPos);
12757 *data << uint32(movementInfo.transport.time);
12758 *data << int8(movementInfo.transport.seat);
12759
12761 *data << uint32(movementInfo.transport.time2);
12762 }
12763
12764 // 0x02200000
12766 *data << float(movementInfo.pitch);
12767
12768 *data << uint32(movementInfo.fallTime);
12769
12770 // 0x00001000
12771 if (movementInfo.HasMovementFlag(MOVEMENTFLAG_FALLING))
12772 {
12773 *data << float(movementInfo.jump.zspeed);
12774 *data << float(movementInfo.jump.sinAngle);
12775 *data << float(movementInfo.jump.cosAngle);
12776 *data << float(movementInfo.jump.xyspeed);
12777 }
12778
12779 // 0x04000000
12781 *data << float(movementInfo.splineElevation);
12782}
12783
12788
12789bool Unit::CanSwim() const
12790{
12791 // 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
12793 return false;
12794 if (HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) // is player
12795 return true;
12797 return false;
12799 return true;
12801}
12802
12803void Unit::NearTeleportTo(Position const& pos, bool casting /*= false*/)
12804{
12805 if (Player* player = ToPlayer())
12806 {
12807 WorldLocation target(GetMapId(), pos);
12808 player->TeleportTo(target, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | (casting ? TELE_TO_SPELL : 0));
12809 }
12810 else
12811 {
12812 DisableSpline();
12814 SendTeleportPacket(pos);
12815 UpdatePosition(pos, true);
12817 }
12818}
12819
12820void Unit::SendTeleportPacket(Position const& pos, bool teleportingTransport /*= false*/)
12821{
12822 // MSG_MOVE_TELEPORT is sent to nearby players to signal the teleport
12823 // MSG_MOVE_TELEPORT_ACK is sent to self in order to trigger ACK and update the position server side
12824
12825 MovementInfo teleportMovementInfo = m_movementInfo;
12826 teleportMovementInfo.pos.Relocate(pos);
12827 if (TransportBase* transportBase = GetDirectTransport())
12828 {
12829 // if its the transport that is teleported then we have old transport position here and cannot use it to calculate offsets
12830 // assume that both transport teleport and teleport within transport cannot happen at the same time
12831 if (!teleportingTransport)
12832 {
12833 float x, y, z, o;
12834 pos.GetPosition(x, y, z, o);
12835 transportBase->CalculatePassengerOffset(x, y, z, &o);
12836 teleportMovementInfo.transport.pos.Relocate(x, y, z, o);
12837 }
12838 }
12839
12841 moveUpdateTeleport.Status = &teleportMovementInfo;
12842
12843 if (IsMovedByClient())
12844 {
12845 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
12846
12848 moveTeleport.Status = &teleportMovementInfo;
12849 moveTeleport.SequenceIndex = GetMovementCounterAndInc();
12850 playerMover->SendDirectMessage(moveTeleport.Write());
12851
12852 // Broadcast the packet to everyone except self.
12853 SendMessageToSet(moveUpdateTeleport.Write(), playerMover);
12854 }
12855 else
12856 {
12857 // This is the only packet sent for creatures which contains MovementInfo structure
12858 // we do not update m_movementInfo for creatures so it needs to be done manually here
12859 moveUpdateTeleport.Status->guid = GetGUID();
12860 moveUpdateTeleport.Status->time = GameTime::GetGameTimeMS();
12861
12862 SendMessageToSet(moveUpdateTeleport.Write(), true);
12863 }
12864}
12865
12866bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool teleport)
12867{
12868 // prevent crash when a bad coord is sent by the client
12869 if (!Trinity::IsValidMapCoord(x, y, z, orientation))
12870 {
12871 TC_LOG_DEBUG("entities.unit", "Unit::UpdatePosition({}, {}, {}) .. bad coordinates!", x, y, z);
12872 return false;
12873 }
12874
12875 // Check if angular distance changed
12876 bool const turn = G3D::fuzzyGt(M_PI - fabs(fabs(GetOrientation() - orientation) - M_PI), 0.0f);
12877
12878 // G3D::fuzzyEq won't help here, in some cases magnitudes differ by a little more than G3D::eps, but should be considered equal
12879 bool const relocated = (teleport ||
12880 std::fabs(GetPositionX() - x) > 0.001f ||
12881 std::fabs(GetPositionY() - y) > 0.001f ||
12882 std::fabs(GetPositionZ() - z) > 0.001f);
12883
12884 if (relocated)
12885 {
12886 // move and update visible state if need
12887 if (GetTypeId() == TYPEID_PLAYER)
12888 GetMap()->PlayerRelocation(ToPlayer(), x, y, z, orientation);
12889 else
12890 GetMap()->CreatureRelocation(ToCreature(), x, y, z, orientation);
12891 }
12892 else if (turn)
12893 UpdateOrientation(orientation);
12894
12896
12897 _positionUpdateInfo.Relocated = relocated;
12899
12900 return (relocated || turn);
12901}
12902
12903bool Unit::UpdatePosition(Position const& pos, bool teleport)
12904{
12905 return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport);
12906}
12907
12909void Unit::UpdateOrientation(float orientation)
12910{
12911 SetOrientation(orientation);
12912 if (IsVehicle())
12914}
12915
12917void Unit::UpdateHeight(float newZ)
12918{
12920 if (IsVehicle())
12922}
12923
12928
12935
12937{
12938 m_pendingMovementChanges.emplace_back(std::move(newChange));
12939}
12940
12942{
12943 return std::find_if(m_pendingMovementChanges.begin(), m_pendingMovementChanges.end(),
12944 [changeType](PlayerMovementPendingChange const& pendingChange)
12945 {
12946 return pendingChange.movementChangeType == changeType;
12947 }) != m_pendingMovementChanges.end();
12948}
12949
12951{
12952 if (sWorld->getIntConfig(CONFIG_PENDING_MOVE_CHANGES_TIMEOUT) == 0)
12953 return;
12954
12956 return;
12957
12958 PlayerMovementPendingChange const& oldestChangeToAck = m_pendingMovementChanges.front();
12959 if (GameTime::GetGameTimeMS() > oldestChangeToAck.time + sWorld->getIntConfig(CONFIG_PENDING_MOVE_CHANGES_TIMEOUT))
12960 {
12961 /*
12962 when players are teleported from one corner of a map to an other (example: from Dragonblight to the entrance of Naxxramas, both in the same map: Northend),
12963 is it done through what is called a 'near' teleport. A near teleport always involve teleporting a player from one point to an other in the same map, even if
12964 the distance is huge. When that distance is big enough, a loading screen appears on the client side. During that time, the client loads the surrounding zone
12965 of the new location (and everything it contains). The problem is that, as long as the client hasn't finished loading the new zone, it will NOT ack the near
12966 teleport. So if the server sends a near teleport order at a certain time and the client takes 20s to load the new zone (let's imagine a very slow computer),
12967 even with zero latency, the server will receive an ack from the client only after 20s.
12968
12969 For this reason and because the current implementation is simple (you dear reader, feel free to improve it if you can), we will just ignore checking for
12970 near teleport acks (for now. @todo).
12971 */
12972 if (oldestChangeToAck.movementChangeType == MovementChangeType::TELEPORT)
12973 return;
12974
12975 GameClient* controller = GetGameClientMovingMe();
12976 controller->GetWorldSession()->KickPlayer("Took too long to ack a movement change");
12977 TC_LOG_INFO("cheat", "Unit::CheckPendingMovementAcks: Player GUID: {} took too long to acknowledge a movement change. He was therefore kicked.", controller->GetBasePlayer()->GetGUID().ToString());
12978 }
12979}
12980
12981void Unit::PurgeAndApplyPendingMovementChanges(bool informObservers /* = true */)
12982{
12983 for (auto pendingChange = m_pendingMovementChanges.cbegin(); pendingChange != m_pendingMovementChanges.cend(); ++pendingChange)
12984 {
12985 float speedFlat = pendingChange->newValue;
12986 MovementChangeType changeType = pendingChange->movementChangeType;
12987 UnitMoveType moveType;
12988 switch (changeType)
12989 {
12990 case MovementChangeType::SPEED_CHANGE_WALK: moveType = MOVE_WALK; break;
12991 case MovementChangeType::SPEED_CHANGE_RUN: moveType = MOVE_RUN; break;
12993 case MovementChangeType::SPEED_CHANGE_SWIM: moveType = MOVE_SWIM; break;
12999 default:
13000 ASSERT(false);
13001 return;
13002 }
13003
13004 float newSpeedRate = speedFlat / (IsControlledByPlayer() ? playerBaseMoveSpeed[moveType] : baseMoveSpeed[moveType]);
13005 SetSpeedRateReal(moveType, newSpeedRate);
13006
13007 if (informObservers)
13008 MovementPacketSender::SendSpeedChangeToObservers(this, moveType, speedFlat);
13009 }
13010
13012}
13013
13018
13019void Unit::RewardRage(uint32 damage, uint32 weaponSpeedHitFactor, bool attacker)
13020{
13021 float addRage;
13022
13023 float rageconversion = ((0.0091107836f * GetLevel() * GetLevel()) + 3.225598133f * GetLevel()) + 4.2652911f;
13024
13025 // Unknown if correct, but lineary adjust rage conversion above level 70
13026 if (GetLevel() > 70)
13027 rageconversion += 13.27f * (GetLevel() - 70);
13028
13029 if (attacker)
13030 {
13031 addRage = (damage / rageconversion * 7.5f + weaponSpeedHitFactor) / 2;
13032
13033 // talent who gave more rage on attack
13035 }
13036 else
13037 {
13038 addRage = damage / rageconversion * 2.5f;
13039
13040 // Berserker Rage effect
13041 if (HasAura(18499))
13042 addRage *= 2.0f;
13043 }
13044
13045 addRage *= sWorld->getRate(RATE_POWER_RAGE_INCOME);
13046
13047 ModifyPower(POWER_RAGE, uint32(addRage * 10));
13048}
13049
13051{
13052 if (Unit* victim = GetVictim())
13053 {
13054 if (victim->GetFactionTemplateEntry()->Faction == faction_id)
13055 {
13056 AttackStop();
13057 if (IsNonMeleeSpellCast(false))
13059
13060 // melee and ranged forced attack cancel
13061 if (GetTypeId() == TYPEID_PLAYER)
13063 }
13064 }
13065
13066 AttackerSet const& attackers = getAttackers();
13067 for (AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end();)
13068 {
13069 if ((*itr)->GetFactionTemplateEntry()->Faction == faction_id)
13070 {
13071 (*itr)->AttackStop();
13072 itr = attackers.begin();
13073 }
13074 else
13075 ++itr;
13076 }
13077
13078 std::vector<CombatReference*> refsToEnd;
13079 for (auto const& pair : m_combatManager.GetPvECombatRefs())
13080 if (pair.second->GetOther(this)->GetFactionTemplateEntry()->Faction == faction_id)
13081 refsToEnd.push_back(pair.second);
13082 for (CombatReference* ref : refsToEnd)
13083 ref->EndCombat();
13084
13085 for (Unit* minion : m_Controlled)
13086 minion->StopAttackFaction(faction_id);
13087}
13088
13090{
13091 TC_LOG_ERROR("entities.unit", "Unit::OutDebugInfo");
13092 TC_LOG_DEBUG("entities.unit", "{} name {}", GetGUID().ToString(), GetName());
13093 TC_LOG_DEBUG("entities.unit", "Owner {}, Minion {}, Charmer {}, Charmed {}", GetOwnerGUID().ToString(), GetMinionGUID().ToString(), GetCharmerGUID().ToString(), GetCharmedGUID().ToString());
13094 TC_LOG_DEBUG("entities.unit", "In world {}, unit type mask {}", (uint32)(IsInWorld() ? 1 : 0), m_unitTypeMask);
13095 if (IsInWorld())
13096 TC_LOG_DEBUG("entities.unit", "Mapid {}", GetMapId());
13097
13098 std::ostringstream o;
13099 o << "Summon Slot: ";
13100 for (uint32 i = 0; i < MAX_SUMMON_SLOT; ++i)
13101 o << m_SummonSlot[i].ToString() << ", ";
13102
13103 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13104 o.str("");
13105
13106 o << "Controlled List: ";
13107 for (ControlList::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
13108 o << (*itr)->GetGUID().ToString() << ", ";
13109 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13110 o.str("");
13111
13112 o << "Aura List: ";
13113 for (AuraApplicationMap::const_iterator itr = m_appliedAuras.begin(); itr != m_appliedAuras.end(); ++itr)
13114 o << itr->first << ", ";
13115 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13116 o.str("");
13117
13118 if (IsVehicle())
13119 {
13120 o << "Passenger List: ";
13121 for (SeatMap::iterator itr = GetVehicleKit()->Seats.begin(); itr != GetVehicleKit()->Seats.end(); ++itr)
13122 if (Unit* passenger = ObjectAccessor::GetUnit(*GetVehicleBase(), itr->second.Passenger.Guid))
13123 o << passenger->GetGUID().ToString() << ", ";
13124 TC_LOG_DEBUG("entities.unit", "{}", o.str());
13125 }
13126
13127 if (GetVehicle())
13128 TC_LOG_DEBUG("entities.unit", "On vehicle {}.", GetVehicleBase()->GetEntry());
13129}
13130
13132{
13134 data << GetPackGUID();
13135 SendMessageToSet(&data, false);
13136}
13137
13139{
13140 int32 resist = -1;
13141 for (int32 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
13142 if (mask & (1 << i) && (resist < 0 || resist > int32(GetResistance(SpellSchools(i)))))
13143 resist = int32(GetResistance(SpellSchools(i)));
13144
13145 // resist value will never be negative here
13146 return resist;
13147}
13148
13150{
13151 _isCommandAttack = val;
13152}
13153
13155{
13156 return _isCommandAttack;
13157}
13158
13160{
13161 _isCommandFollow = val;
13162}
13163
13165{
13166 return _isCommandFollow;
13167}
13168
13170{
13172 G3D::Vector3 stayPos = _unit->movespline->FinalDestination();
13173
13175 if (TransportBase* transport = _unit->GetDirectTransport())
13176 transport->CalculatePassengerPosition(stayPos.x, stayPos.y, stayPos.z);
13177
13178 _stayX = stayPos.x;
13179 _stayY = stayPos.y;
13180 _stayZ = stayPos.z;
13181}
13182
13183void CharmInfo::GetStayPosition(float &x, float &y, float &z)
13184{
13185 x = _stayX;
13186 y = _stayY;
13187 z = _stayZ;
13188}
13189
13191{
13192 _isAtStay = val;
13193}
13194
13196{
13197 return _isAtStay;
13198}
13199
13201{
13202 _isFollowing = val;
13203}
13204
13206{
13207 return _isFollowing;
13208}
13209
13211{
13212 _isReturning = val;
13213}
13214
13216{
13217 return _isReturning;
13218}
13219
13221{
13224}
13225
13226void Unit::SetFacingTo(float ori, bool force /*= true*/, uint32 movementId /*= EVENT_FACE*/)
13227{
13228 // do not face when already moving
13229 if (!force && (!IsStopped() || !movespline->Finalized()))
13230 return;
13231
13232 GetMotionMaster()->MoveFace(ori, movementId);
13233}
13234
13235void Unit::SetFacingToObject(WorldObject const* object, bool force /*= true*/, uint32 movementId /*= EVENT_FACE*/)
13236{
13237 // do not face when already moving
13238 if (!force && (!IsStopped() || !movespline->Finalized()))
13239 return;
13240
13241 GetMotionMaster()->MoveFace(object, movementId);
13242}
13243
13244bool Unit::SetWalk(bool enable)
13245{
13246 if (enable == IsWalking())
13247 return false;
13248
13249 if (enable)
13251 else
13253
13255
13256 WorldPackets::Movement::MoveSplineSetFlag packet(walkModeTable[enable]);
13257 packet.MoverGUID = GetGUID();
13258 SendMessageToSet(packet.Write(), true);
13259 return true;
13260}
13261
13262bool Unit::SetDisableGravity(bool disable, bool updateAnimTier /*= true*/)
13263{
13264 if (disable == IsGravityDisabled())
13265 return false;
13266
13267 if (disable)
13268 {
13271 }
13272 else
13274
13275 static OpcodeServer const gravityOpcodeTable[2][2] =
13276 {
13279 };
13280
13281 if (IsMovedByClient())
13282 {
13283 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
13284
13285 WorldPackets::Movement::MoveSetFlag packet(gravityOpcodeTable[disable][1]);
13286 packet.MoverGUID = GetGUID();
13288 playerMover->SendDirectMessage(packet.Write());
13289
13291 moveUpdate.Status = &m_movementInfo;
13292 SendMessageToSet(moveUpdate.Write(), playerMover);
13293 }
13294 else
13295 {
13296 WorldPackets::Movement::MoveSplineSetFlag packet(gravityOpcodeTable[disable][0]);
13297 packet.MoverGUID = GetGUID();
13298 SendMessageToSet(packet.Write(), true);
13299 }
13300
13301 if (IsCreature() && updateAnimTier && !HasUnitState(UNIT_STATE_ROOT) && !ToCreature()->GetMovementTemplate().IsRooted())
13302 {
13303 if (IsGravityDisabled())
13305 else if (IsHovering())
13307 else
13309 }
13310
13311 return true;
13312}
13313
13314bool Unit::SetFall(bool enable)
13315{
13317 return false;
13318
13319 if (enable)
13320 {
13323 }
13324 else
13326
13327 return true;
13328}
13329
13330bool Unit::SetSwim(bool enable)
13331{
13333 return false;
13334
13335 if (enable)
13337 else
13339
13340 static OpcodeServer const swimOpcodeTable[2] = { SMSG_SPLINE_MOVE_STOP_SWIM, SMSG_SPLINE_MOVE_START_SWIM };
13341
13342 WorldPackets::Movement::MoveSplineSetFlag packet(swimOpcodeTable[enable]);
13343 packet.MoverGUID = GetGUID();
13344 SendMessageToSet(packet.Write(), true);
13345
13346 return true;
13347}
13348
13349bool Unit::SetCanFly(bool enable, bool packetOnly /*= false */)
13350{
13351 if (!packetOnly)
13352 {
13354 return false;
13355
13356 if (enable)
13357 {
13360 }
13361 else
13363 }
13364
13365 static OpcodeServer const flyOpcodeTable[2][2] =
13366 {
13369 };
13370
13371 if (!enable && GetTypeId() == TYPEID_PLAYER)
13373
13374 if (IsMovedByClient())
13375 {
13376 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
13377
13378 WorldPackets::Movement::MoveSetFlag packet(flyOpcodeTable[enable][1]);
13379 packet.MoverGUID = GetGUID();
13381 playerMover->SendDirectMessage(packet.Write());
13382
13384 moveUpdate.Status = &m_movementInfo;
13385 SendMessageToSet(moveUpdate.Write(), playerMover);
13386 }
13387 else
13388 {
13389 WorldPackets::Movement::MoveSplineSetFlag packet(flyOpcodeTable[enable][0]);
13390 packet.MoverGUID = GetGUID();
13391 SendMessageToSet(packet.Write(), true);
13392 }
13393
13394 return true;
13395}
13396
13397bool Unit::SetWaterWalking(bool enable)
13398{
13400 return false;
13401
13402 if (enable)
13404 else
13406
13407 static OpcodeServer const waterWalkingOpcodeTable[2][2] =
13408 {
13411 };
13412
13413 if (IsMovedByClient())
13414 {
13415 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
13416
13417 WorldPackets::Movement::MoveSetFlag packet(waterWalkingOpcodeTable[enable][1]);
13418 packet.MoverGUID = GetGUID();
13420 playerMover->SendDirectMessage(packet.Write());
13421
13423 moveUpdate.Status = &m_movementInfo;
13424 SendMessageToSet(moveUpdate.Write(), playerMover);
13425 }
13426 else
13427 {
13428 WorldPackets::Movement::MoveSplineSetFlag packet(waterWalkingOpcodeTable[enable][0]);
13429 packet.MoverGUID = GetGUID();
13430 SendMessageToSet(packet.Write(), true);
13431 }
13432
13433 return true;
13434}
13435
13436bool Unit::SetFeatherFall(bool enable)
13437{
13439 return false;
13440
13441 if (enable)
13443 else
13445
13446 static OpcodeServer const featherFallOpcodeTable[2][2] =
13447 {
13450 };
13451
13452 if (IsMovedByClient())
13453 {
13454 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
13455
13456 WorldPackets::Movement::MoveSetFlag packet(featherFallOpcodeTable[enable][1]);
13457 packet.MoverGUID = GetGUID();
13459 playerMover->SendDirectMessage(packet.Write());
13460
13462 moveUpdate.Status = &m_movementInfo;
13463 SendMessageToSet(moveUpdate.Write(), playerMover);
13464 }
13465 else
13466 {
13467 WorldPackets::Movement::MoveSplineSetFlag packet(featherFallOpcodeTable[enable][0]);
13468 packet.MoverGUID = GetGUID();
13469 SendMessageToSet(packet.Write(), true);
13470 }
13471
13472 return true;
13473}
13474
13475bool Unit::SetHover(bool enable, bool updateAnimTier /*= true*/)
13476{
13478 return false;
13479
13480 float hoverHeight = GetFloatValue(UNIT_FIELD_HOVERHEIGHT);
13481
13482 if (enable)
13483 {
13486 if (hoverHeight && GetPositionZ() - GetFloorZ() < hoverHeight)
13487 UpdateHeight(std::max(GetFloorZ() + hoverHeight, GetPositionZ()));
13488 }
13489 else
13490 {
13493 if (hoverHeight && (!isDying() || GetTypeId() != TYPEID_UNIT))
13494 {
13495 float newZ = std::max<float>(GetFloorZ(), GetPositionZ() - hoverHeight);
13497 UpdateHeight(newZ);
13498 }
13499 }
13500
13501 static OpcodeServer const hoverOpcodeTable[2][2] =
13502 {
13505 };
13506
13507 if (IsMovedByClient())
13508 {
13509 Player* playerMover = GetGameClientMovingMe()->GetBasePlayer();
13510
13511 WorldPackets::Movement::MoveSetFlag packet(hoverOpcodeTable[enable][1]);
13512 packet.MoverGUID = GetGUID();
13514 playerMover->SendDirectMessage(packet.Write());
13515
13517 moveUpdate.Status = &m_movementInfo;
13518 SendMessageToSet(moveUpdate.Write(), playerMover);
13519 }
13520 else
13521 {
13522 WorldPackets::Movement::MoveSplineSetFlag packet(hoverOpcodeTable[enable][0]);
13523 packet.MoverGUID = GetGUID();
13524 SendMessageToSet(packet.Write(), true);
13525 }
13526
13527 if (IsCreature() && updateAnimTier && !HasUnitState(UNIT_STATE_ROOT) && !ToCreature()->GetMovementTemplate().IsRooted())
13528 {
13529 if (IsGravityDisabled())
13531 else if (IsHovering())
13533 else
13535 }
13536
13537 return true;
13538}
13539
13541{
13542 return movespline->Initialized() && !movespline->Finalized();
13543}
13544
13545void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player const* target) const
13546{
13547 if (!target)
13548 return;
13549
13550 ByteBuffer fieldBuffer;
13551
13553
13555 uint32 visibleFlag = UF_FLAG_PUBLIC;
13556
13557 if (target == this)
13558 visibleFlag |= UF_FLAG_PRIVATE;
13559
13561 if (GetOwnerGUID() == target->GetGUID())
13562 visibleFlag |= UF_FLAG_OWNER;
13563
13566 visibleFlag |= UF_FLAG_SPECIAL_INFO;
13567
13568 if (plr && plr->IsInSameRaidWith(target))
13569 visibleFlag |= UF_FLAG_PARTY_MEMBER;
13570
13571 Creature const* creature = ToCreature();
13572 for (uint16 index = 0; index < m_valuesCount; ++index)
13573 {
13574 if (_fieldNotifyFlags & flags[index] ||
13575 ((flags[index] & visibleFlag) & UF_FLAG_SPECIAL_INFO) ||
13576 ((updateType == UPDATETYPE_VALUES ? _changesMask.GetBit(index) : m_uint32Values[index]) && (flags[index] & visibleFlag)) ||
13578 {
13579 updateMask.SetBit(index);
13580
13581 if (index == UNIT_NPC_FLAGS)
13582 {
13583 uint32 appendValue = m_uint32Values[UNIT_NPC_FLAGS];
13584
13585 if (creature)
13586 if (!target->CanSeeSpellClickOn(creature))
13587 appendValue &= ~UNIT_NPC_FLAG_SPELLCLICK;
13588
13589 fieldBuffer << uint32(appendValue);
13590 }
13591 else if (index == UNIT_FIELD_AURASTATE)
13592 {
13593 // Check per caster aura states to not enable using a spell in client if specified aura is not by target
13594 fieldBuffer << BuildAuraStateUpdateForTarget(target);
13595 }
13596 // FIXME: Some values at server stored in float format but must be sent to client in uint32 format
13597 else if (index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME)
13598 {
13599 // convert from float to uint32 and send
13600 fieldBuffer << uint32(m_floatValues[index] < 0 ? 0 : m_floatValues[index]);
13601 }
13602 // there are some float values which may be negative or can't get negative due to other checks
13603 else if ((index >= UNIT_FIELD_NEGSTAT0 && index <= UNIT_FIELD_NEGSTAT4) ||
13606 (index >= UNIT_FIELD_POSSTAT0 && index <= UNIT_FIELD_POSSTAT4))
13607 {
13608 fieldBuffer << uint32(m_floatValues[index]);
13609 }
13610 // Gamemasters should be always able to interact with units - remove uninteractible flag
13611 else if (index == UNIT_FIELD_FLAGS)
13612 {
13613 uint32 appendValue = m_uint32Values[UNIT_FIELD_FLAGS];
13614 if (target->IsGameMaster())
13615 appendValue &= ~UNIT_FLAG_UNINTERACTIBLE;
13616
13617 fieldBuffer << uint32(appendValue);
13618 }
13619 // use modelid_a if not gm, _h if gm for CREATURE_FLAG_EXTRA_TRIGGER creatures
13620 else if (index == UNIT_FIELD_DISPLAYID)
13621 {
13623 if (creature)
13624 {
13625 CreatureTemplate const* cinfo = creature->GetCreatureTemplate();
13626
13627 // this also applies for transform auras
13628 if (SpellInfo const* transform = sSpellMgr->GetSpellInfo(GetTransformSpell()))
13629 {
13630 for (SpellEffectInfo const& spellEffectInfo : transform->GetEffects())
13631 {
13632 if (spellEffectInfo.IsAura(SPELL_AURA_TRANSFORM))
13633 {
13634 if (CreatureTemplate const* transformInfo = sObjectMgr->GetCreatureTemplate(spellEffectInfo.MiscValue))
13635 {
13636 cinfo = transformInfo;
13637 break;
13638 }
13639 }
13640 }
13641 }
13642
13644 if (target->IsGameMaster())
13645 displayId = cinfo->GetFirstVisibleModel();
13646 }
13647
13648 fieldBuffer << uint32(displayId);
13649 }
13650 // hide lootable animation for unallowed players
13651 else if (index == UNIT_DYNAMIC_FLAGS)
13652 {
13654
13655 if (creature)
13656 {
13657 if (creature->hasLootRecipient())
13658 {
13659 dynamicFlags |= UNIT_DYNFLAG_TAPPED;
13660 if (creature->isTappedBy(target))
13661 dynamicFlags |= UNIT_DYNFLAG_TAPPED_BY_PLAYER;
13662 }
13663
13664 if (!target->isAllowedToLoot(creature))
13665 dynamicFlags &= ~UNIT_DYNFLAG_LOOTABLE;
13666 }
13667
13668 // unit UNIT_DYNFLAG_TRACK_UNIT should only be sent to caster of SPELL_AURA_MOD_STALKED auras
13669 if (dynamicFlags & UNIT_DYNFLAG_TRACK_UNIT)
13671 dynamicFlags &= ~UNIT_DYNFLAG_TRACK_UNIT;
13672
13673 fieldBuffer << dynamicFlags;
13674 }
13675 // FG: pretend that OTHER players in own group are friendly ("blue")
13676 else if (index == UNIT_FIELD_BYTES_2 || index == UNIT_FIELD_FACTIONTEMPLATE)
13677 {
13678 if (IsControlledByPlayer() && target != this && sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && IsInRaidWith(target))
13679 {
13681 FactionTemplateEntry const* ft2 = target->GetFactionTemplateEntry();
13682 if (!ft1->IsFriendlyTo(*ft2))
13683 {
13684 if (index == UNIT_FIELD_BYTES_2)
13685 // Allow targetting opposite faction in party when enabled in config
13686 fieldBuffer << (m_uint32Values[UNIT_FIELD_BYTES_2] & ((UNIT_BYTE2_FLAG_SANCTUARY /*| UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5*/) << 8)); // this flag is at uint8 offset 1 !!
13687 else
13688 // pretend that all other HOSTILE players have own faction, to allow follow, heal, rezz (trade wont work)
13689 fieldBuffer << uint32(target->GetFaction());
13690 }
13691 else
13692 fieldBuffer << m_uint32Values[index];
13693 }
13694 else
13695 fieldBuffer << m_uint32Values[index];
13696 }
13697 else
13698 {
13699 // send in current format (float as float, uint32 as uint32)
13700 fieldBuffer << m_uint32Values[index];
13701 }
13702 }
13703 }
13704
13705 updateMask.AppendToPacket(data);
13706 data->append(fieldBuffer);
13707}
13708
13709void Unit::DestroyForPlayer(Player* target, bool onDeath) const
13710{
13711 if (Battleground* bg = target->GetBattleground())
13712 {
13713 if (bg->isArena())
13714 {
13716 destroyArenaUnit.Guid = GetGUID();
13717 target->GetSession()->SendPacket(destroyArenaUnit.Write());
13718 }
13719 }
13720
13721 WorldObject::DestroyForPlayer(target, onDeath);
13722}
13723
13724int32 Unit::GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const* aurEff, AuraType auraType, bool checkMiscValue /*= false*/, int32 miscValue /*= 0*/) const
13725{
13726 int32 val = 0;
13727 SpellSpellGroupMapBounds spellGroup = sSpellMgr->GetSpellSpellGroupMapBounds(aurEff->GetSpellInfo()->GetFirstRankSpell()->Id);
13728 for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second ; ++itr)
13729 {
13730 if (sSpellMgr->GetSpellGroupStackRule(itr->second) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT)
13731 {
13732 AuraEffectList const& auraEffList = GetAuraEffectsByType(auraType);
13733 for (AuraEffectList::const_iterator auraItr = auraEffList.begin(); auraItr != auraEffList.end(); ++auraItr)
13734 {
13735 if (aurEff != (*auraItr) && (!checkMiscValue || (*auraItr)->GetMiscValue() == miscValue) &&
13736 sSpellMgr->IsSpellMemberOfSpellGroup((*auraItr)->GetSpellInfo()->Id, itr->second))
13737 {
13738 // absolute value only
13739 if (abs(val) < abs((*auraItr)->GetAmount()))
13740 val = (*auraItr)->GetAmount();
13741 }
13742 }
13743 }
13744 }
13745 return val;
13746}
13747
13748bool Unit::IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications /*= false*/)
13749{
13750 for (uint32 i = 0 ; i < MAX_SPELL_EFFECTS; ++i)
13751 if (AuraEffect const* aurEff = aura->GetEffect(i))
13752 if (!IsHighestExclusiveAuraEffect(aura->GetSpellInfo(), aurEff->GetAuraType(), aurEff->GetAmount(), aura->GetEffectMask(), removeOtherAuraApplications))
13753 return false;
13754
13755 return true;
13756}
13757
13758bool Unit::IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType auraType, int32 effectAmount, uint8 auraEffectMask, bool removeOtherAuraApplications /*= false*/)
13759{
13760 AuraEffectList const& auras = GetAuraEffectsByType(auraType);
13761 for (Unit::AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end();)
13762 {
13763 AuraEffect const* existingAurEff = (*itr);
13764 ++itr;
13765
13766 if (sSpellMgr->CheckSpellGroupStackRules(spellInfo, existingAurEff->GetSpellInfo()) == SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST)
13767 {
13768 int32 diff = abs(effectAmount) - abs(existingAurEff->GetAmount());
13769 if (!diff)
13770 for (int32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
13771 diff += int32((auraEffectMask & (1 << i)) >> i) - int32((existingAurEff->GetBase()->GetEffectMask() & (1 << i)) >> i);
13772
13773 if (diff > 0)
13774 {
13775 Aura const* base = existingAurEff->GetBase();
13776 // no removing of area auras from the original owner, as that completely cancels them
13777 if (removeOtherAuraApplications && (!base->IsArea() || base->GetOwner() != this))
13778 {
13779 if (AuraApplication* aurApp = existingAurEff->GetBase()->GetApplicationOfTarget(GetGUID()))
13780 {
13781 bool hasMoreThanOneEffect = base->HasMoreThanOneEffectForType(auraType);
13782 uint32 removedAuras = m_removedAurasCount;
13783 RemoveAura(aurApp);
13784 if (hasMoreThanOneEffect || m_removedAurasCount > removedAuras + 1)
13785 itr = auras.begin();
13786 }
13787 }
13788 }
13789 else if (diff < 0)
13790 return false;
13791 }
13792 }
13793
13794 return true;
13795}
13796
13797void Unit::Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const* target)
13798{
13799 Trinity::CustomChatTextBuilder builder(this, msgType, text, language, target);
13802 Cell::VisitWorldObjects(this, worker, textRange);
13803}
13804
13805void Unit::Say(std::string_view text, Language language, WorldObject const* target /*= nullptr*/)
13806{
13807 Talk(text, CHAT_MSG_MONSTER_SAY, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
13808}
13809
13810void Unit::Yell(std::string_view text, Language language, WorldObject const* target /*= nullptr*/)
13811{
13812 Talk(text, CHAT_MSG_MONSTER_YELL, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target);
13813}
13814
13815void Unit::TextEmote(std::string_view text, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/)
13816{
13818}
13819
13820void Unit::Whisper(std::string_view text, Language language, Player* target, bool isBossWhisper /*= false*/)
13821{
13822 if (!target)
13823 return;
13824
13827 packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, language, this, target, text, 0, "", locale);
13828 target->SendDirectMessage(packet.Write());
13829}
13830
13832{
13833 if (slot >= MAX_EQUIPMENT_ITEMS)
13834 return 0;
13835
13837}
13838
13840{
13841 if (slot >= MAX_EQUIPMENT_ITEMS)
13842 return;
13843
13845}
13846
13847void Unit::Talk(uint32 textId, ChatMsg msgType, float textRange, WorldObject const* target)
13848{
13849 if (!sObjectMgr->GetBroadcastText(textId))
13850 {
13851 TC_LOG_ERROR("entities.unit", "WorldObject::MonsterText: `broadcast_text` (ID: {}) was not found", textId);
13852 return;
13853 }
13854
13855 Trinity::BroadcastTextBuilder builder(this, msgType, textId, GetGender(), target);
13858 Cell::VisitWorldObjects(this, worker, textRange);
13859}
13860
13861void Unit::Say(uint32 textId, WorldObject const* target /*= nullptr*/)
13862{
13863 Talk(textId, CHAT_MSG_MONSTER_SAY, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
13864}
13865
13866void Unit::Yell(uint32 textId, WorldObject const* target /*= nullptr*/)
13867{
13868 Talk(textId, CHAT_MSG_MONSTER_YELL, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target);
13869}
13870
13871void Unit::TextEmote(uint32 textId, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/)
13872{
13873 Talk(textId, isBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), target);
13874}
13875
13876void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/)
13877{
13878 if (!target)
13879 return;
13880
13881 BroadcastTextEntry const* bct = sObjectMgr->GetBroadcastText(textId);
13882 if (!bct)
13883 {
13884 TC_LOG_ERROR("entities.unit", "WorldObject::MonsterWhisper: `broadcast_text` was not {} found", textId);
13885 return;
13886 }
13887
13890 packet.Initialize(isBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER, LANG_UNIVERSAL, this, target, bct->GetText(locale, GetGender()), 0, "", locale);
13891 target->SendDirectMessage(packet.Write());
13892}
13893
13894// Returns collisionheight of the unit. If it is 0, it returns DEFAULT_COLLISION_HEIGHT.
13896{
13897 float scaleMod = GetObjectScale(); // 99% sure about this
13898
13899 if (IsMounted())
13900 {
13901 if (CreatureDisplayInfoEntry const* mountDisplayInfo = sCreatureDisplayInfoStore.LookupEntry(GetMountDisplayId()))
13902 {
13903 if (CreatureModelDataEntry const* mountModelData = sCreatureModelDataStore.LookupEntry(mountDisplayInfo->ModelID))
13904 {
13905 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId());
13906 CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelID);
13907 float const collisionHeight = scaleMod * (mountModelData->MountHeight + modelData->CollisionHeight * modelData->ModelScale * displayInfo->CreatureModelScale * 0.5f);
13908 return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
13909 }
13910 }
13911 }
13912
13914 CreatureDisplayInfoEntry const* displayInfo = sCreatureDisplayInfoStore.AssertEntry(GetNativeDisplayId());
13915 CreatureModelDataEntry const* modelData = sCreatureModelDataStore.AssertEntry(displayInfo->ModelID);
13916
13917 float const collisionHeight = scaleMod * modelData->CollisionHeight * modelData->ModelScale * displayInfo->CreatureModelScale;
13918 return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
13919}
13920
13921std::string Unit::GetDebugInfo() const
13922{
13923 std::stringstream sstr;
13924 sstr << WorldObject::GetDebugInfo() << "\n"
13925 << std::boolalpha
13926 << "IsAIEnabled: " << IsAIEnabled() << " DeathState: " << std::to_string(getDeathState())
13927 << " UnitMovementFlags: " << GetUnitMovementFlags() << " ExtraUnitMovementFlags: " << GetExtraUnitMovementFlags()
13928 << " Class: " << std::to_string(GetClass()) << "\n"
13929 << "" << (movespline ? movespline->ToString() : "Movespline: <none>\n")
13930 << "GetCharmedGUID(): " << GetCharmedGUID().ToString() << "\n"
13931 << "GetCharmerGUID(): " << GetCharmerGUID().ToString() << "\n"
13932 << "" << (GetVehicleKit() ? GetVehicleKit()->GetDebugInfo() : "No vehicle kit") << "\n"
13933 << "GetGameClientMovingMe(): " << (GetGameClientMovingMe() ? GetGameClientMovingMe()->GetDebugInfo() : "NULL") << "\n"
13934 << "m_Controlled size: " << m_Controlled.size();
13935
13936 size_t controlledCount = 0;
13937 for (Unit* controlled : m_Controlled)
13938 {
13939 ++controlledCount;
13940 sstr << "\n" << "m_Controlled " << controlledCount << " : " << controlled->GetGUID().ToString();
13941 }
13942
13943 return sstr.str();
13944}
#define sBattlefieldMgr
@ SCORE_DAMAGE_DONE
@ SCORE_HEALING_DONE
#define sCharacterCache
LocaleConstant
Definition Common.h:48
@ IN_MILLISECONDS
Definition Common.h:35
@ MINUTE
Definition Common.h:29
@ HOUR
Definition Common.h:30
@ SEC_PLAYER
Definition Common.h:40
@ SEC_GAMEMASTER
Definition Common.h:42
#define M_PI
Definition Common.h:71
#define sConditionMgr
@ CREATURE_FLAG_EXTRA_NO_BLOCK
@ CREATURE_FLAG_EXTRA_NO_CRUSHING_BLOWS
@ CREATURE_FLAG_EXTRA_NO_CRIT
@ CREATURE_FLAG_EXTRA_TRIGGER
@ CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN
@ CREATURE_FLAG_EXTRA_INSTANCE_BIND
@ CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS
@ CREATURE_FLAG_EXTRA_NO_PARRY
static const uint32 MAX_CREATURE_SPELLS
#define sFormationMgr
#define MAX_EFFECT_MASK
Definition DBCEnums.h:387
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED
Definition DBCEnums.h:222
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST
Definition DBCEnums.h:224
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED
Definition DBCEnums.h:226
@ ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE
Definition DBCEnums.h:181
@ ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED
Definition DBCEnums.h:225
@ ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER
Definition DBCEnums.h:150
@ ACHIEVEMENT_CRITERIA_TYPE_GAIN_AURA
Definition DBCEnums.h:193
@ ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE
Definition DBCEnums.h:142
@ ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED
Definition DBCEnums.h:223
@ ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE
Definition DBCEnums.h:149
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT
Definition DBCEnums.h:221
@ ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS
Definition DBCEnums.h:182
#define MAX_SPELL_EFFECTS
Definition DBCEnums.h:386
DBCStorage< SpellShapeshiftFormEntry > sSpellShapeshiftFormStore(SpellShapeshiftFormfmt)
DBCStorage< VehicleEntry > sVehicleStore(VehicleEntryfmt)
DBCStorage< PowerDisplayEntry > sPowerDisplayStore(PowerDisplayfmt)
DBCStorage< CreatureDisplayInfoEntry > sCreatureDisplayInfoStore(CreatureDisplayInfofmt)
DBCStorage< ChrRacesEntry > sChrRacesStore(ChrRacesEntryfmt)
DBCStorage< CreatureDisplayInfoExtraEntry > sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt)
DBCStorage< CreatureModelDataEntry > sCreatureModelDataStore(CreatureModelDatafmt)
DBCStorage< ChrClassesEntry > sChrClassesStore(ChrClassesEntryfmt)
DBCStorage< LiquidTypeEntry > sLiquidTypeStore(LiquidTypefmt)
@ CHRRACES_FLAGS_CAN_MOUNT
@ CREATURE_MODEL_DATA_FLAGS_CAN_MOUNT
uint8_t uint8
Definition Define.h:135
int16_t int16
Definition Define.h:130
int8_t int8
Definition Define.h:131
int32_t int32
Definition Define.h:129
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
uint16 flags
std::chrono::steady_clock::time_point TimePoint
time_point shorthand typedefs
Definition Duration.h:36
#define ABORT_MSG
Definition Errors.h:75
#define ASSERT_WITH_SIDE_EFFECTS
Definition Errors.h:72
#define ABORT
Definition Errors.h:74
#define ASSERT_NODEBUGINFO
Definition Errors.h:69
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:84
#define ASSERT
Definition Errors.h:68
@ GROUP_UPDATE_FLAG_CUR_HP
Definition Group.h:102
@ GROUP_UPDATE_FLAG_PET_CUR_HP
Definition Group.h:114
@ GROUP_UPDATE_FLAG_POWER_TYPE
Definition Group.h:104
@ GROUP_UPDATE_FLAG_PET_CUR_POWER
Definition Group.h:117
@ GROUP_UPDATE_FLAG_PET_MAX_POWER
Definition Group.h:118
@ GROUP_UPDATE_FLAG_MAX_HP
Definition Group.h:103
@ GROUP_UPDATE_FLAG_PET_POWER_TYPE
Definition Group.h:116
@ GROUP_UPDATE_FLAG_MAX_POWER
Definition Group.h:106
@ GROUP_UPDATE_FLAG_PET_AURAS
Definition Group.h:119
@ GROUP_UPDATE_FLAG_AURAS
Definition Group.h:110
@ GROUP_UPDATE_FLAG_LEVEL
Definition Group.h:107
@ GROUP_UPDATE_FLAG_PET_MAX_HP
Definition Group.h:115
@ GROUP_UPDATE_FLAG_CUR_POWER
Definition Group.h:105
#define sInstanceSaveMgr
@ ITEM_SUBCLASS_WEAPON_CROSSBOW
@ ITEM_SUBCLASS_WEAPON_GUN
@ ITEM_SUBCLASS_WEAPON_AXE2
@ ITEM_SUBCLASS_WEAPON_STAFF
@ ITEM_SUBCLASS_WEAPON_MACE
@ ITEM_SUBCLASS_WEAPON_EXOTIC2
@ ITEM_SUBCLASS_WEAPON_FISHING_POLE
@ ITEM_SUBCLASS_WEAPON_MACE2
@ ITEM_SUBCLASS_WEAPON_DAGGER
@ ITEM_SUBCLASS_WEAPON_BOW
@ ITEM_SUBCLASS_WEAPON_SWORD
@ ITEM_SUBCLASS_WEAPON_AXE
@ ITEM_SUBCLASS_WEAPON_FIST_WEAPON
@ ITEM_SUBCLASS_WEAPON_EXOTIC
@ ITEM_SUBCLASS_WEAPON_THROWN
@ ITEM_SUBCLASS_WEAPON_SWORD2
@ ITEM_SUBCLASS_WEAPON_POLEARM
#define MAX_ITEM_PROTO_DAMAGES
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition Log.h:159
#define TC_LOG_FATAL(filterType__,...)
Definition Log.h:168
LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true)
ZLiquidStatus
Definition MapDefines.h:74
@ LIQUID_MAP_UNDER_WATER
Definition MapDefines.h:79
@ LIQUID_MAP_IN_WATER
Definition MapDefines.h:78
bool IsInvalidMovementSlot(uint8 const slot)
@ MOTION_PRIORITY_HIGHEST
@ MOTION_PRIORITY_NORMAL
MovementSlot
MovementGeneratorType
@ DISTRACT_MOTION_TYPE
@ IDLE_MOTION_TYPE
@ FLEEING_MOTION_TYPE
@ CONFUSED_MOTION_TYPE
@ POINT_MOTION_TYPE
@ FOLLOW_MOTION_TYPE
#define NOMINAL_MELEE_RANGE
@ NOTIFY_VISIBILITY_CHANGED
@ TYPEID_GAMEOBJECT
Definition ObjectGuid.h:40
@ TYPEID_UNIT
Definition ObjectGuid.h:38
@ TYPEID_PLAYER
Definition ObjectGuid.h:39
@ TYPEMASK_UNIT
Definition ObjectGuid.h:52
#define sObjectMgr
Definition ObjectMgr.h:1721
float const DEFAULT_COLLISION_HEIGHT
Definition Object.h:65
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
@ PETSPELL_REMOVED
Definition PetDefines.h:60
@ PET_SAVE_NOT_IN_SLOT
Definition PetDefines.h:45
PetActionFeedback
Definition PetDefines.h:71
#define PET_FOLLOW_DIST
Definition PetDefines.h:85
PetAction
Definition PetDefines.h:80
@ HUNTER_PET
Definition PetDefines.h:32
EquipmentSlots
Definition Player.h:558
@ EQUIPMENT_SLOT_END
Definition Player.h:579
@ EQUIPMENT_SLOT_OFFHAND
Definition Player.h:576
@ TELE_TO_SPELL
Definition Player.h:671
@ TELE_TO_NOT_LEAVE_COMBAT
Definition Player.h:669
@ TELE_TO_NOT_LEAVE_TRANSPORT
Definition Player.h:668
std::unordered_map< uint32, PlayerSpell > PlayerSpellMap
Definition Player.h:180
@ CHEAT_GOD
Definition Player.h:815
#define SPELL_DK_RAISE_ALLY
Definition Player.h:871
@ PLAYERSPELL_REMOVED
Definition Player.h:153
#define INVENTORY_SLOT_BAG_0
Definition Player.h:555
int32 irand(int32 min, int32 max)
Definition Random.cpp:35
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
double rand_norm()
Definition Random.cpp:75
bool roll_chance_f(float chance)
Definition Random.h:53
bool roll_chance_i(int chance)
Definition Random.h:59
#define sScriptMgr
Definition ScriptMgr.h:1168
@ SERVERSIDE_VISIBILITY_GM
@ SERVERSIDE_VISIBILITY_GHOST
@ EFFECT_0
SpellSchools
@ SPELL_SCHOOL_SHADOW
@ SPELL_SCHOOL_NORMAL
@ SPELL_SCHOOL_NATURE
@ SPELL_SCHOOL_FROST
@ SPELL_SCHOOL_ARCANE
@ SPELL_SCHOOL_FIRE
@ SPELL_SCHOOL_HOLY
@ MAX_SPELL_SCHOOL
@ SPELL_ATTR7_CANT_MISS
@ SPELL_ATTR7_DISPEL_CHARGES
@ SPELL_ATTR7_CANT_PARRY
@ SPELL_ATTR7_CANT_DODGE
@ SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE
@ SPELL_EFFECT_POWER_BURN
@ SPELL_EFFECT_HEALTH_LEECH
@ SPELL_EFFECT_HEAL
@ SPELL_EFFECT_NORMALIZED_WEAPON_DMG
@ SPELL_EFFECT_ENVIRONMENTAL_DAMAGE
@ SPELL_EFFECT_SUMMON
@ SPELL_EFFECT_POWER_DRAIN
@ SPELL_EFFECT_SCHOOL_DAMAGE
@ SPELL_EFFECT_APPLY_AURA
Language
@ LANG_UNIVERSAL
Gender
@ GENDER_MALE
@ SPELL_ATTR5_REMOVE_ON_ARENA_ENTER
@ NPC_CLICK_CAST_TARGET_CLICKER
@ NPC_CLICK_CAST_ORIG_CASTER_OWNER
@ NPC_CLICK_CAST_CASTER_CLICKER
@ EMOTE_ONESHOT_NONE
SpellSchoolMask
@ SPELL_SCHOOL_MASK_NORMAL
@ SPELL_SCHOOL_MASK_MAGIC
@ SPELL_SCHOOL_MASK_NONE
@ SPELL_SCHOOL_MASK_HOLY
@ EVENT_JUMP
@ EVENT_VEHICLE_EXIT
@ SPELL_ATTR2_CAN_TARGET_DEAD
@ SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS
@ SPELL_ATTR2_UNAFFECTED_BY_AURA_SCHOOL_IMMUNE
@ CREATURE_TYPE_DEMON
@ SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY
@ SPELL_ATTR1_UNAFFECTED_BY_SCHOOL_IMMUNE
SpellSchools GetFirstSchoolInMask(SpellSchoolMask mask)
uint32 const CREATURE_TYPEMASK_DEMON_OR_UNDEAD
@ UNIT_DYNFLAG_SPECIALINFO
@ UNIT_DYNFLAG_TAPPED_BY_PLAYER
@ UNIT_DYNFLAG_TAPPED
@ UNIT_DYNFLAG_LOOTABLE
@ UNIT_DYNFLAG_TRACK_UNIT
@ SPELL_ATTR3_TREAT_AS_PERIODIC
@ SPELL_ATTR3_DEATH_PERSISTENT
@ SPELL_ATTR3_NO_DONE_BONUS
@ SPELL_ATTR3_DISABLE_PROC
@ SPELL_ATTR3_IGNORE_HIT_RESULT
@ SPELL_DAMAGE_CLASS_RANGED
@ SPELL_DAMAGE_CLASS_MAGIC
@ SPELL_DAMAGE_CLASS_NONE
@ SPELL_DAMAGE_CLASS_MELEE
@ AI_REACTION_HOSTILE
@ SUMMON_TYPE_MINIPET
WeaponAttackType
@ OFF_ATTACK
@ MAX_ATTACK
@ BASE_ATTACK
@ RANGED_ATTACK
@ CLASS_HUNTER
@ CLASS_WARRIOR
@ CLASS_WARLOCK
@ CLASS_MAGE
@ CLASS_ROGUE
#define PER_CASTER_AURA_STATE_MASK
@ MECHANIC_SLOW_ATTACK
@ MECHANIC_KNOCKOUT
@ MECHANIC_STUN
@ MECHANIC_ROOT
@ MECHANIC_BLEED
@ MECHANIC_DAZE
@ MECHANIC_SNARE
@ IMMUNITY_STATE
@ IMMUNITY_EFFECT
@ IMMUNITY_ID
@ IMMUNITY_DAMAGE
@ IMMUNITY_MECHANIC
@ IMMUNITY_SCHOOL
@ IMMUNITY_DISPEL
SpellFamilyNames
@ SPELLFAMILY_PRIEST
@ SPELLFAMILY_WARLOCK
@ SPELLFAMILY_MAGE
@ SPELLFAMILY_WARRIOR
@ SPELLFAMILY_PALADIN
@ SPELLFAMILY_HUNTER
@ SPELLFAMILY_POTION
@ SPELLFAMILY_ROGUE
@ SPELLFAMILY_SHAMAN
@ SPELLFAMILY_DRUID
@ SPELLFAMILY_DEATHKNIGHT
@ ALLIANCE
@ HORDE
Powers
@ MAX_POWERS
@ POWER_RAGE
@ POWER_HEALTH
@ POWER_RUNIC_POWER
@ POWER_HAPPINESS
@ POWER_ENERGY
@ POWER_MANA
@ POWER_RUNE
@ POWER_FOCUS
SpellAttr0
@ SPELL_ATTR0_IMPOSSIBLE_DODGE_PARRY_BLOCK
@ SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY
@ SPELL_ATTR0_CASTABLE_WHILE_MOUNTED
ChatMsg
@ CHAT_MSG_MONSTER_WHISPER
@ CHAT_MSG_RAID_BOSS_WHISPER
@ CHAT_MSG_RAID_BOSS_EMOTE
@ CHAT_MSG_MONSTER_EMOTE
@ CHAT_MSG_MONSTER_SAY
@ CHAT_MSG_MONSTER_YELL
DiminishingLevels
@ DIMINISHING_LEVEL_3
@ DIMINISHING_LEVEL_1
@ DIMINISHING_LEVEL_4
@ DIMINISHING_LEVEL_IMMUNE
@ DIMINISHING_LEVEL_TAUNT_IMMUNE
@ DIMINISHING_LEVEL_2
@ DUEL_FLED
@ DUEL_WON
@ DUEL_INTERRUPTED
DiminishingGroup
@ DIMINISHING_NONE
@ DIMINISHING_TAUNT
@ MAX_SUMMON_SLOT
@ GHOST_VISIBILITY_ALIVE
@ SPELL_HIT_TYPE_CRIT
@ SPELL_HIT_TYPE_SPLIT
@ RACE_NIGHTELF
@ RACE_TAUREN
SpellMissInfo
@ SPELL_MISS_PARRY
@ SPELL_MISS_IMMUNE
@ SPELL_MISS_ABSORB
@ SPELL_MISS_DODGE
@ SPELL_MISS_IMMUNE2
@ SPELL_MISS_NONE
@ SPELL_MISS_RESIST
@ SPELL_MISS_MISS
@ SPELL_MISS_EVADE
@ SPELL_MISS_REFLECT
@ SPELL_MISS_BLOCK
@ SPELL_MISS_DEFLECT
AuraStateType
@ AURA_STATE_DEFENSE
@ AURA_STATE_FROZEN
@ AURA_STATE_BLEEDING
@ AURA_STATE_FAERIE_FIRE
@ AURA_STATE_ENRAGE
@ AURA_STATE_HEALTHLESS_35_PERCENT
@ AURA_STATE_HEALTH_ABOVE_75_PERCENT
@ AURA_STATE_HEALTHLESS_20_PERCENT
@ AURA_STATE_CONFLAGRATE
@ AURA_STATE_HUNTER_PARRY
@ DRTYPE_PLAYER
@ DRTYPE_ALL
Stats
@ STAT_SPIRIT
@ STAT_INTELLECT
@ MAX_STATS
@ STAT_AGILITY
@ STAT_STRENGTH
@ STAT_STAMINA
@ DISPEL_DISEASE
#define MAX_GAMEOBJECT_SLOT
SpellCastResult
@ SPELL_CAST_OK
@ SPELL_ATTR4_DONT_REMOVE_IN_ARENA
@ SPELL_ATTR4_IGNORE_RESISTANCES
@ SPELL_ATTR4_FIXED_DAMAGE
@ SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS
@ CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT
@ SKILL_DEFENSE
@ SKILL_UNARMED
@ SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS
@ SPELL_ATTR6_LIMIT_PCT_HEALING_MODS
#define MAX_AURAS
AuraRemoveMode
@ AURA_REMOVE_BY_CANCEL
@ AURA_REMOVE_NONE
@ AURA_REMOVE_BY_DEFAULT
@ AURA_REMOVE_BY_DEATH
@ AURA_REMOVE_BY_EXPIRE
@ AURA_REMOVE_BY_ENEMY_SPELL
@ AURA_EFFECT_HANDLE_STAT
@ AURA_EFFECT_HANDLE_SEND_FOR_CLIENT
@ SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS
@ SPELL_AURA_MANA_SHIELD
@ SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
@ SPELL_AURA_CLONE_CASTER
@ SPELL_AURA_RETAIN_COMBO_POINTS
@ SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE
@ SPELL_AURA_MOD_TARGET_ABSORB_SCHOOL
@ SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE
@ SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
@ SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
@ SPELL_AURA_PERIODIC_DAMAGE
@ SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
@ SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS
@ SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER
@ SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE
@ SPELL_AURA_MOD_PARRY_PERCENT
@ SPELL_AURA_ABILITY_IGNORE_AURASTATE
@ SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE
@ SPELL_AURA_MOD_IGNORE_TARGET_RESIST
@ SPELL_AURA_MOD_SHAPESHIFT
@ SPELL_AURA_MOD_DAMAGE_DONE_VERSUS
@ SPELL_AURA_MOD_CRITICAL_HEALING_AMOUNT
@ SPELL_AURA_DAMAGE_SHIELD
@ SPELL_AURA_OBS_MOD_HEALTH
@ SPELL_AURA_PERIODIC_HEALTH_FUNNEL
@ SPELL_AURA_PERIODIC_MANA_LEECH
@ SPELL_AURA_MOD_POSSESS_PET
@ SPELL_AURA_MOD_INCREASE_SPEED
@ SPELL_AURA_MOD_RESISTANCE
@ SPELL_AURA_MOD_EXPERTISE
@ SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
@ SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN
@ SPELL_AURA_MOD_CRIT_CHANCE_FOR_CASTER
@ SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE
@ SPELL_AURA_MOD_FEAR
@ SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
@ SPELL_AURA_MOD_HEALING_DONE_PERCENT
@ SPELL_AURA_LINKED
@ SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS
@ SPELL_AURA_SHARE_DAMAGE_PCT
@ SPELL_AURA_OBS_MOD_POWER
@ SPELL_AURA_ADD_CASTER_HIT_TRIGGER
@ SPELL_AURA_SPLIT_DAMAGE_FLAT
@ SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
@ SPELL_AURA_CONTROL_VEHICLE
@ SPELL_AURA_IGNORE_HIT_DIRECTION
@ SPELL_AURA_IGNORE_COMBAT_RESULT
@ SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS
@ SPELL_AURA_EMPATHY
@ SPELL_AURA_MOD_SPEED_NOT_STACK
@ SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE
@ SPELL_AURA_MOD_STALKED
@ SPELL_AURA_SCHOOL_HEAL_ABSORB
@ SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED
@ SPELL_AURA_MOD_HIT_CHANCE
@ SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT
@ SPELL_AURA_PERIODIC_HEAL
@ SPELL_AURA_MOD_ENEMY_DODGE
@ SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE
@ SPELL_AURA_PERIODIC_DAMAGE_PERCENT
@ SPELL_AURA_DUMMY
@ SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
@ SPELL_AURA_MOD_TARGET_ABILITY_ABSORB_SCHOOL
@ SPELL_AURA_MOD_DODGE_PERCENT
@ SPELL_AURA_MOD_INCREASE_SWIM_SPEED
@ SPELL_AURA_FLY
@ SPELL_AURA_SPLIT_DAMAGE_PCT
@ SPELL_AURA_DEFLECT_SPELLS
@ SPELL_AURA_MOD_STAT
@ SPELL_AURA_MOD_CRIT_DAMAGE_BONUS
@ SPELL_AURA_MOD_HEALING_DONE
@ SPELL_AURA_MOD_HEALING_RECEIVED
@ SPELL_AURA_MOD_HEALING_PCT
@ SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
@ SPELL_AURA_MOD_CHARM
@ SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT
@ SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE
@ SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT
@ SPELL_AURA_MOD_ARMOR_PENETRATION_PCT
@ SPELL_AURA_MOD_ROOT
@ SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT
@ SPELL_AURA_MOUNTED
@ SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
@ SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE
@ SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN
@ SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT
@ SPELL_AURA_MOD_DAMAGE_TAKEN
@ SPELL_AURA_MOD_DAMAGE_DONE_VERSUS_AURASTATE
@ SPELL_AURA_MOD_VEHICLE_SPEED_ALWAYS
@ SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE
@ SPELL_AURA_MOD_CRIT_PCT
@ SPELL_AURA_MOD_MINIMUM_SPEED
@ SPELL_AURA_MOD_BLOCK_CRIT_CHANCE
@ SPELL_AURA_MOD_HOT_PCT
@ SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER
@ SPELL_AURA_MOD_SCALE_2
@ SPELL_AURA_AOE_CHARM
@ SPELL_AURA_MOD_TARGET_RESISTANCE
@ SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS
@ SPELL_AURA_MOD_SPEED_ALWAYS
@ SPELL_AURA_MOD_DECREASE_SPEED
@ SPELL_AURA_TRANSFORM
@ SPELL_AURA_SCHOOL_ABSORB
@ SPELL_AURA_MOD_RESISTANCE_PCT
@ SPELL_AURA_MOD_DAMAGE_DONE_FOR_MECHANIC
@ SPELL_AURA_MOD_COMBAT_RESULT_CHANCE
@ SPELL_AURA_PERIODIC_ENERGIZE
@ SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
@ SPELL_AURA_MOD_WEAPON_CRIT_PERCENT
@ SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
@ SPELL_AURA_MOD_SCALE
@ SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL
@ SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER
@ SPELL_AURA_PERIODIC_LEECH
@ SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT
@ SPELL_AURA_MOD_PERCENT_STAT
@ SPELL_AURA_MOD_HEALING
@ SPELL_AURA_MOD_DAMAGE_DONE
@ SPELL_AURA_MOD_ABILITY_IGNORE_TARGET_RESIST
@ SPELL_AURA_MOD_CONFUSE
@ SPELL_AURA_MOD_POSSESS
@ SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT
@ SPELL_AURA_MOD_MECHANIC_RESISTANCE
@ SPELL_AURA_MOD_UNATTACKABLE
@ SPELL_AURA_NONE
@ SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
@ SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
@ SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
@ SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
@ SPELL_AURA_MOD_BLOCK_PERCENT
@ SPELL_AURA_MOD_STUN
@ SPELL_AURA_BIND_SIGHT
ShapeshiftForm
@ FORM_DIREBEAR
@ FORM_TRAVEL
@ FORM_FLIGHT_EPIC
@ FORM_CAT
@ FORM_FLIGHT
@ FORM_GHOSTWOLF
@ FORM_GHOUL
@ FORM_BEAR
@ UNIT_AURA_TYPE
@ SPELL_INTERRUPT_FLAG_ABORT_ON_DMG
@ SPELL_INTERRUPT_FLAG_MOVEMENT
@ SPELLMOD_DAMAGE
@ SPELLMOD_CRIT_DAMAGE_BONUS
@ SPELLMOD_DOT
@ SPELLMOD_CRITICAL_CHANCE
@ SPELLMOD_BONUS_MULTIPLIER
@ SPELLMOD_PROC_PER_MINUTE
@ SPELLMOD_IGNORE_ARMOR
@ SPELLMOD_RESIST_MISS_CHANCE
TriggerCastFlags
@ TRIGGERED_FULL_MASK
Will return SPELL_FAILED_DONT_REPORT in CheckCast functions.
@ TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE
Disallows proc events from triggered spell (default)
@ TRIGGERED_NONE
SpellValueMod
@ SPELLVALUE_BASE_POINT0
@ AURA_INTERRUPT_FLAG_TAKE_DAMAGE
@ AURA_INTERRUPT_FLAG_DIRECT_DAMAGE
@ AURA_INTERRUPT_FLAG_MOVE
@ AURA_INTERRUPT_FLAG_TURNING
@ AURA_INTERRUPT_FLAG_NOT_ABOVEWATER
@ AURA_INTERRUPT_FLAG_NOT_SEATED
@ AURA_INTERRUPT_FLAG_NOT_UNDERWATER
@ AURA_INTERRUPT_FLAG_MELEE_ATTACK
@ AURA_INTERRUPT_FLAG_LEAVE_COMBAT
@ AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT
@ AURA_INTERRUPT_FLAG_MOUNT
@ AURA_INTERRUPT_FLAG_NOT_MOUNTED
@ SPELL_ATTR0_CU_IGNORE_ARMOR
Definition SpellInfo.h:156
@ SPELL_ATTR0_CU_ENCHANT_PROC
Definition SpellInfo.h:141
@ SPELL_ATTR0_CU_CAN_CRIT
Definition SpellInfo.h:148
@ SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET
Definition SpellInfo.h:158
@ SPELL_ATTR0_CU_AURA_CC
Definition SpellInfo.h:146
@ SPELL_ATTR0_CU_BINARY_SPELL
Definition SpellInfo.h:161
@ SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC
Definition SpellInfo.h:162
@ SPELL_SPECIFIC_MAGE_POLYMORPH
Definition SpellInfo.h:124
@ PROC_HIT_BLOCK
Definition SpellMgr.h:226
@ PROC_HIT_FULL_RESIST
Definition SpellMgr.h:223
@ PROC_HIT_FULL_BLOCK
Definition SpellMgr.h:233
@ PROC_HIT_MISS
Definition SpellMgr.h:222
@ PROC_HIT_NONE
Definition SpellMgr.h:219
@ PROC_HIT_DEFLECT
Definition SpellMgr.h:229
@ PROC_HIT_EVADE
Definition SpellMgr.h:227
@ PROC_HIT_DODGE
Definition SpellMgr.h:224
@ PROC_HIT_IMMUNE
Definition SpellMgr.h:228
@ PROC_HIT_ABSORB
Definition SpellMgr.h:230
@ PROC_HIT_PARRY
Definition SpellMgr.h:225
@ PROC_HIT_CRITICAL
Definition SpellMgr.h:221
@ PROC_HIT_NORMAL
Definition SpellMgr.h:220
@ PROC_HIT_REFLECT
Definition SpellMgr.h:231
#define MELEE_BASED_TRIGGER_MASK
Definition SpellMgr.h:190
std::pair< SpellSpellGroupMap::const_iterator, SpellSpellGroupMap::const_iterator > SpellSpellGroupMapBounds
Definition SpellMgr.h:318
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT
Definition SpellMgr.h:329
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST
Definition SpellMgr.h:330
#define sSpellMgr
Definition SpellMgr.h:738
@ PROC_SPELL_TYPE_NONE
Definition SpellMgr.h:201
@ PROC_SPELL_TYPE_MASK_ALL
Definition SpellMgr.h:205
@ PROC_SPELL_TYPE_DAMAGE
Definition SpellMgr.h:202
@ PROC_SPELL_PHASE_NONE
Definition SpellMgr.h:210
@ PROC_SPELL_PHASE_HIT
Definition SpellMgr.h:212
@ PROC_FLAG_DONE_MELEE_AUTO_ATTACK
Definition SpellMgr.h:118
@ PROC_FLAG_KILLED
Definition SpellMgr.h:115
@ PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG
Definition SpellMgr.h:140
@ PROC_FLAG_DEATH
Definition SpellMgr.h:151
@ PROC_FLAG_KILL
Definition SpellMgr.h:116
@ PROC_FLAG_DONE_MAINHAND_ATTACK
Definition SpellMgr.h:148
@ PROC_FLAG_TAKEN_DAMAGE
Definition SpellMgr.h:145
@ PROC_FLAG_TAKEN_MELEE_AUTO_ATTACK
Definition SpellMgr.h:119
@ PROC_FLAG_DONE_OFFHAND_ATTACK
Definition SpellMgr.h:149
@ PROC_FLAG_NONE
Definition SpellMgr.h:113
@ SPELL_STATE_DELAYED
Definition Spell.h:136
@ SPELL_STATE_FINISHED
Definition Spell.h:134
@ SPELL_STATE_PREPARING
Definition Spell.h:132
@ SPELL_STATE_CASTING
Definition Spell.h:133
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
Definition Timer.h:40
@ TOTEM_PASSIVE
Definition Totem.h:25
@ UNIT_BYTES_2_OFFSET_SHAPESHIFT_FORM
Definition UnitDefines.h:80
@ UNIT_BYTES_0_OFFSET_POWER_TYPE
Definition UnitDefines.h:64
@ UNIT_FLAG2_UNUSED_6
@ UNIT_FLAG2_DISARM_OFFHAND
@ UNIT_FLAG2_DISARM_RANGED
HitInfo
@ HITINFO_PARTIAL_ABSORB
@ HITINFO_FULL_RESIST
@ HITINFO_NORMALSWING
@ HITINFO_BLOCK
@ HITINFO_CRUSHING
@ HITINFO_SWINGNOHITSOUND
@ HITINFO_MISS
@ HITINFO_FULL_ABSORB
@ HITINFO_OFFHAND
@ HITINFO_GLANCING
@ HITINFO_CRITICALHIT
@ HITINFO_PARTIAL_RESIST
@ HITINFO_AFFECTS_VICTIM
@ REACT_PASSIVE
UnitStandStateType
Definition UnitDefines.h:33
@ UNIT_STAND_STATE_SLEEP
Definition UnitDefines.h:37
@ UNIT_STAND_STATE_SIT_HIGH_CHAIR
Definition UnitDefines.h:40
@ UNIT_STAND_STATE_SIT_MEDIUM_CHAIR
Definition UnitDefines.h:39
@ UNIT_STAND_STATE_SIT_LOW_CHAIR
Definition UnitDefines.h:38
@ UNIT_STAND_STATE_KNEEL
Definition UnitDefines.h:42
@ UNIT_STAND_STATE_SIT_CHAIR
Definition UnitDefines.h:36
@ UNIT_STAND_STATE_STAND
Definition UnitDefines.h:34
@ UNIT_STAND_STATE_SIT
Definition UnitDefines.h:35
#define BASE_ATTACK_TIME
Definition UnitDefines.h:27
MovementFlags
@ MOVEMENTFLAG_SPLINE_ENABLED
@ MOVEMENTFLAG_FORWARD
@ MOVEMENTFLAG_ONTRANSPORT
@ MOVEMENTFLAG_WATERWALKING
@ MOVEMENTFLAG_MASK_MOVING
@ MOVEMENTFLAG_DISABLE_GRAVITY
@ MOVEMENTFLAG_FLYING
@ MOVEMENTFLAG_FALLING_SLOW
@ MOVEMENTFLAG_CAN_FLY
@ MOVEMENTFLAG_ROOT
@ MOVEMENTFLAG_MASK_TURNING
@ MOVEMENTFLAG_FALLING
@ MOVEMENTFLAG_MASK_MOVING_FLY
@ MOVEMENTFLAG_FALLING_FAR
@ MOVEMENTFLAG_SWIMMING
@ MOVEMENTFLAG_HOVER
@ MOVEMENTFLAG_SPLINE_ELEVATION
@ MOVEMENTFLAG_WALKING
#define MAX_MOVE_TYPE
@ MOVEMENTFLAG2_ALWAYS_ALLOW_PITCHING
@ MOVEMENTFLAG2_INTERPOLATED_MOVEMENT
@ UNIT_BYTES_1_OFFSET_ANIM_TIER
Definition UnitDefines.h:72
@ UNIT_BYTES_1_OFFSET_STAND_STATE
Definition UnitDefines.h:69
ActiveStates
@ ACT_REACTION
@ ACT_DECIDE
@ ACT_COMMAND
@ ACT_ENABLED
@ ACT_PASSIVE
@ ACT_DISABLED
@ UNIT_NPC_FLAG_TABARDDESIGNER
@ UNIT_NPC_FLAG_BANKER
@ UNIT_NPC_FLAG_AUCTIONEER
@ UNIT_NPC_FLAG_VENDOR
@ UNIT_NPC_FLAG_BATTLEMASTER
@ UNIT_NPC_FLAG_INNKEEPER
@ UNIT_NPC_FLAG_SPELLCLICK
@ UNIT_NPC_FLAG_PLAYER_VEHICLE
@ UNIT_NPC_FLAG_FLIGHTMASTER
@ UNIT_NPC_FLAG_TRAINER
@ UNIT_NPC_FLAG_PETITIONER
@ UNIT_NPC_FLAG_SPIRITGUIDE
@ UNIT_NPC_FLAG_SPIRITHEALER
#define BASE_MAXDAMAGE
Definition UnitDefines.h:26
#define MAX_EQUIPMENT_ITEMS
Definition UnitDefines.h:29
@ UNIT_BYTE2_FLAG_PVP
@ UNIT_BYTE2_FLAG_NONE
@ UNIT_BYTE2_FLAG_SANCTUARY
AnimTier
Definition UnitDefines.h:85
@ COMMAND_ATTACK
@ COMMAND_FOLLOW
#define BASE_MINDAMAGE
Definition UnitDefines.h:25
UnitMoveType
@ MOVE_FLIGHT
@ MOVE_SWIM
@ MOVE_TURN_RATE
@ MOVE_FLIGHT_BACK
@ MOVE_SWIM_BACK
@ MOVE_RUN
@ MOVE_PITCH_RATE
@ MOVE_RUN_BACK
@ MOVE_WALK
@ UNIT_FLAG_EVADING_HOME
@ UNIT_FLAG_STUNNED
@ UNIT_FLAG_CANNOT_SWIM
@ UNIT_FLAG_NON_ATTACKABLE
@ UNIT_FLAG_IMMUNE_TO_NPC
@ UNIT_FLAG_POSSESSED
@ UNIT_FLAG_DISARMED
@ UNIT_FLAG_PACIFIED
@ UNIT_FLAG_CAN_SWIM
@ UNIT_FLAG_REMOVE_CLIENT_CONTROL
@ UNIT_FLAG_UNINTERACTIBLE
@ UNIT_FLAG_IMMUNE_TO_PC
@ UNIT_FLAG_PLAYER_CONTROLLED
@ UNIT_FLAG_SKINNABLE
@ UNIT_FLAG_MOUNT
@ UNIT_FLAG_PET_IN_COMBAT
float baseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:88
uint32 createProcHitMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
Definition Unit.cpp:9978
void ApplyPercentModFloatVar(float &var, float val, bool apply)
Definition Unit.cpp:8958
float playerBaseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:101
UnitModifierFlatType
Definition Unit.h:138
@ BASE_VALUE
Definition Unit.h:139
@ MODIFIER_TYPE_FLAT_END
Definition Unit.h:141
@ TOTAL_VALUE
Definition Unit.h:140
#define MAX_SPELL_CHARM
Definition Unit.h:36
std::unordered_multimap< uint32, uint32 > SpellImmuneContainer
Definition Unit.h:135
@ UNIT_MASK_NONE
Definition Unit.h:377
@ UNIT_MASK_CONTROLABLE_GUARDIAN
Definition Unit.h:386
@ UNIT_MASK_ACCESSORY
Definition Unit.h:387
@ UNIT_MASK_VEHICLE
Definition Unit.h:383
@ UNIT_MASK_GUARDIAN
Definition Unit.h:380
@ UNIT_MASK_MINION
Definition Unit.h:379
#define MAX_UNIT_ACTION_BAR_INDEX
Definition Unit.h:684
MovementChangeType
Definition Unit.h:289
VictimState
Definition Unit.h:45
@ VICTIMSTATE_INTACT
Definition Unit.h:46
@ VICTIMSTATE_HIT
Definition Unit.h:47
@ VICTIMSTATE_DODGE
Definition Unit.h:48
@ VICTIMSTATE_IS_IMMUNE
Definition Unit.h:53
@ VICTIMSTATE_PARRY
Definition Unit.h:49
@ VICTIMSTATE_BLOCKS
Definition Unit.h:51
@ VICTIMSTATE_EVADES
Definition Unit.h:52
AttackPowerModType
Definition Unit.h:216
WeaponDamageRange
Definition Unit.h:152
@ MINDAMAGE
Definition Unit.h:153
@ MAXDAMAGE
Definition Unit.h:154
UnitMods
Definition Unit.h:158
@ UNIT_MOD_DAMAGE_OFFHAND
Definition Unit.h:180
@ UNIT_MOD_RUNE
Definition Unit.h:170
@ UNIT_MOD_STAT_INTELLECT
Definition Unit.h:162
@ UNIT_MOD_STAT_SPIRIT
Definition Unit.h:163
@ UNIT_MOD_ARMOR
Definition Unit.h:172
@ UNIT_MOD_RESISTANCE_SHADOW
Definition Unit.h:177
@ UNIT_MOD_RESISTANCE_FROST
Definition Unit.h:176
@ UNIT_MOD_END
Definition Unit.h:182
@ UNIT_MOD_RESISTANCE_HOLY
Definition Unit.h:173
@ UNIT_MOD_RESISTANCE_ARCANE
Definition Unit.h:178
@ UNIT_MOD_ENERGY
Definition Unit.h:168
@ UNIT_MOD_HEALTH
Definition Unit.h:164
@ UNIT_MOD_DAMAGE_RANGED
Definition Unit.h:181
@ UNIT_MOD_RESISTANCE_FIRE
Definition Unit.h:174
@ UNIT_MOD_STAT_STRENGTH
Definition Unit.h:159
@ UNIT_MOD_RESISTANCE_NATURE
Definition Unit.h:175
@ UNIT_MOD_STAT_AGILITY
Definition Unit.h:160
@ UNIT_MOD_FOCUS
Definition Unit.h:167
@ UNIT_MOD_DAMAGE_MAINHAND
Definition Unit.h:179
@ UNIT_MOD_HAPPINESS
Definition Unit.h:169
@ UNIT_MOD_MANA
Definition Unit.h:165
@ UNIT_MOD_STAT_START
Definition Unit.h:184
@ UNIT_MOD_RAGE
Definition Unit.h:166
@ UNIT_MOD_STAT_STAMINA
Definition Unit.h:161
@ UNIT_MOD_RUNIC_POWER
Definition Unit.h:171
TC_GAME_API float playerBaseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:101
@ ACTION_BAR_INDEX_PET_SPELL_START
Definition Unit.h:679
@ ACTION_BAR_INDEX_PET_SPELL_END
Definition Unit.h:680
@ ACTION_BAR_INDEX_END
Definition Unit.h:681
@ ACTION_BAR_INDEX_START
Definition Unit.h:678
DeathState
Definition Unit.h:224
@ CORPSE
Definition Unit.h:227
@ DEAD
Definition Unit.h:228
@ ALIVE
Definition Unit.h:225
@ JUST_RESPAWNED
Definition Unit.h:229
@ JUST_DIED
Definition Unit.h:226
#define CURRENT_FIRST_NON_MELEE_SPELL
Definition Unit.h:626
CurrentSpellTypes
Definition Unit.h:619
@ CURRENT_CHANNELED_SPELL
Definition Unit.h:622
@ CURRENT_GENERIC_SPELL
Definition Unit.h:621
@ CURRENT_MELEE_SPELL
Definition Unit.h:620
@ CURRENT_AUTOREPEAT_SPELL
Definition Unit.h:623
UnitState
Definition Unit.h:233
@ UNIT_STATE_DISTRACTED
Definition Unit.h:246
@ UNIT_STATE_DIED
Definition Unit.h:234
@ UNIT_STATE_ATTACK_PLAYER
Definition Unit.h:248
@ UNIT_STATE_POSSESSED
Definition Unit.h:250
@ UNIT_STATE_UNATTACKABLE
Definition Unit.h:272
@ UNIT_STATE_CANNOT_AUTOATTACK
Definition Unit.h:276
@ UNIT_STATE_CONFUSED
Definition Unit.h:245
@ UNIT_STATE_ROOT
Definition Unit.h:244
@ UNIT_STATE_CONTROLLED
Definition Unit.h:274
@ UNIT_STATE_FLEEING
Definition Unit.h:241
@ UNIT_STATE_CANNOT_TURN
Definition Unit.h:278
@ UNIT_STATE_MOVING
Definition Unit.h:273
@ UNIT_STATE_MOVE
Definition Unit.h:254
@ UNIT_STATE_MELEE_ATTACKING
Definition Unit.h:235
@ UNIT_STATE_IN_FLIGHT
Definition Unit.h:242
@ UNIT_STATE_CASTING
Definition Unit.h:249
@ UNIT_STATE_STUNNED
Definition Unit.h:237
@ UNIT_STATE_CHARMED
Definition Unit.h:236
MeleeHitOutcome
Definition Unit.h:407
@ MELEE_HIT_CRUSHING
Definition Unit.h:409
@ MELEE_HIT_BLOCK
Definition Unit.h:408
@ MELEE_HIT_CRIT
Definition Unit.h:409
@ MELEE_HIT_NORMAL
Definition Unit.h:409
@ MELEE_HIT_EVADE
Definition Unit.h:408
@ MELEE_HIT_DODGE
Definition Unit.h:408
@ MELEE_HIT_MISS
Definition Unit.h:408
@ MELEE_HIT_PARRY
Definition Unit.h:408
@ MELEE_HIT_GLANCING
Definition Unit.h:409
#define MAX_AGGRO_RESET_TIME
Definition Unit.h:41
AttackPowerModIndex
Definition Unit.h:209
std::vector< DispelableAura > DispelChargesList
Definition Unit.h:133
#define CURRENT_MAX_SPELL
Definition Unit.h:627
CombatRating
Definition Unit.h:335
@ CR_WEAPON_SKILL_RANGED
Definition Unit.h:358
@ CR_CRIT_TAKEN_RANGED
Definition Unit.h:351
@ CR_CRIT_TAKEN_SPELL
Definition Unit.h:352
@ CR_ARMOR_PENETRATION
Definition Unit.h:360
@ CR_WEAPON_SKILL
Definition Unit.h:336
@ CR_WEAPON_SKILL_OFFHAND
Definition Unit.h:357
@ CR_DEFENSE_SKILL
Definition Unit.h:337
@ CR_WEAPON_SKILL_MAINHAND
Definition Unit.h:356
@ CR_CRIT_TAKEN_MELEE
Definition Unit.h:350
DamageEffectType
Definition Unit.h:366
@ DIRECT_DAMAGE
Definition Unit.h:367
@ NODAMAGE
Definition Unit.h:371
@ DOT
Definition Unit.h:369
@ SPELL_DIRECT_DAMAGE
Definition Unit.h:368
CharmType
Definition Unit.h:667
@ CHARM_TYPE_CHARM
Definition Unit.h:668
@ CHARM_TYPE_POSSESS
Definition Unit.h:669
@ CHARM_TYPE_CONVERT
Definition Unit.h:671
@ CHARM_TYPE_VEHICLE
Definition Unit.h:670
ReactiveType
Definition Unit.h:758
@ MAX_REACTIVE
Definition Unit.h:763
@ REACTIVE_OVERPOWER
Definition Unit.h:761
@ REACTIVE_DEFENSE
Definition Unit.h:759
@ REACTIVE_HUNTER_PARRY
Definition Unit.h:760
@ REACTIVE_WOLVERINE_BITE
Definition Unit.h:762
TC_GAME_API float baseMoveSpeed[MAX_MOVE_TYPE]
Definition Unit.cpp:88
UnitModifierPctType
Definition Unit.h:145
@ MODIFIER_TYPE_PCT_END
Definition Unit.h:148
@ TOTAL_PCT
Definition Unit.h:147
@ BASE_PCT
Definition Unit.h:146
@ UPDATETYPE_VALUES
Definition UpdateData.h:30
@ UPDATEFLAG_LIVING
Definition UpdateData.h:46
@ UPDATEFLAG_VEHICLE
Definition UpdateData.h:48
@ UPDATEFLAG_STATIONARY_POSITION
Definition UpdateData.h:47
uint32 UnitUpdateFieldFlags[PLAYER_END]
@ UF_FLAG_SPECIAL_INFO
@ UF_FLAG_PUBLIC
@ UF_FLAG_OWNER
@ UF_FLAG_PRIVATE
@ UF_FLAG_PARTY_MEMBER
@ UNIT_FIELD_MINDAMAGE
@ PLAYER_RANGED_CRIT_PERCENTAGE
@ UNIT_NPC_FLAGS
@ PLAYER_CRIT_PERCENTAGE
@ PLAYER_SPELL_CRIT_PERCENTAGE1
@ UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE
@ UNIT_FIELD_POSSTAT0
@ UNIT_FIELD_RANGEDATTACKTIME
@ UNIT_FIELD_HEALTH
@ UNIT_FIELD_ATTACK_POWER_MODS
@ PLAYER_PARRY_PERCENTAGE
@ UNIT_FIELD_SUMMONEDBY
@ PLAYER_OFFHAND_CRIT_PERCENTAGE
@ UNIT_FIELD_MAXDAMAGE
@ UNIT_FIELD_DISPLAYID
@ PLAYER_BLOCK_PERCENTAGE
@ UNIT_FIELD_BYTES_0
@ UNIT_FIELD_LEVEL
@ UNIT_FIELD_FACTIONTEMPLATE
@ UNIT_FIELD_RANGED_ATTACK_POWER
@ UNIT_FIELD_MAXPOWER1
@ UNIT_MOD_CAST_SPEED
@ UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER
@ UNIT_FIELD_POSSTAT4
@ UNIT_FIELD_MAXOFFHANDDAMAGE
@ UNIT_FIELD_SUMMON
@ UNIT_FIELD_NEGSTAT4
@ UNIT_FIELD_AURASTATE
@ UNIT_FIELD_MAXRANGEDDAMAGE
@ PLAYER_DODGE_PERCENTAGE
@ UNIT_FIELD_ATTACK_POWER_MULTIPLIER
@ UNIT_FIELD_ATTACK_POWER
@ UNIT_FIELD_POWER1
@ UNIT_FIELD_CHARMEDBY
@ UNIT_FIELD_CHARM
@ UNIT_VIRTUAL_ITEM_SLOT_ID
@ UNIT_FIELD_MINRANGEDDAMAGE
@ UNIT_FIELD_FLAGS
@ UNIT_FIELD_RANGED_ATTACK_POWER_MODS
@ UNIT_FIELD_HOVERHEIGHT
@ PLAYER_SELF_RES_SPELL
@ UNIT_FIELD_NEGSTAT0
@ UNIT_FIELD_MAXHEALTH
@ PLAYER_FIELD_MOD_DAMAGE_DONE_PCT
@ UNIT_FIELD_BYTES_1
@ UNIT_FIELD_BYTES_2
@ UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE
@ UNIT_FIELD_MINOFFHANDDAMAGE
@ UNIT_CREATED_BY_SPELL
@ UNIT_FIELD_BASEATTACKTIME
@ UNIT_DYNAMIC_FLAGS
T AddPct(T &base, U pct)
Definition Util.h:77
T RoundToInterval(T &num, T floor, T ceil)
Definition Util.h:89
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:554
T ApplyPct(T &base, U pct)
Definition Util.h:83
T CalculatePct(T base, U pct)
Definition Util.h:71
@ VEHICLE_SPELL_RIDE_HARDCODED
@ VEHICLE_FLAG_FIXED_POSITION
Unit * GetTarget() const
Definition SpellAuras.h:74
void SetRemoveMode(AuraRemoveMode mode)
Definition SpellAuras.h:87
bool IsPositive() const
Definition SpellAuras.h:81
uint8 GetEffectMask() const
Definition SpellAuras.h:79
void _HandleEffect(uint8 effIndex, bool apply)
Aura * GetBase() const
Definition SpellAuras.h:75
AuraRemoveMode GetRemoveMode() const
Definition SpellAuras.h:88
bool HasEffect(uint8 effect) const
Definition SpellAuras.h:80
void ChangeAmount(int32 newAmount, bool mark=true, bool onStackOrReapply=false)
SpellInfo const * GetSpellInfo() const
AuraType GetAuraType() const
bool CanBeRecalculated() const
SpellEffectInfo const & GetSpellEffectInfo() const
uint32 GetId() const
void HandleEffect(AuraApplication *aurApp, uint8 mode, bool apply)
bool IsAffectingSpell(SpellInfo const *spell) const
void SetAmount(int32 amount)
Unit * GetCaster() const
int32 GetMiscValue() const
Aura * GetBase() const
int32 const m_baseAmount
int32 GetBaseAmount() const
ObjectGuid GetCasterGUID() const
int32 GetAmount() const
bool HasMoreThanOneEffectForType(AuraType auraType) const
virtual void _UnapplyForTarget(Unit *target, Unit *caster, AuraApplication *auraApp)
bool IsArea() const
int32 GetMaxDuration() const
Definition SpellAuras.h: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)
ApplicationMap const & GetApplicationMap()
Definition SpellAuras.h:232
void SetStackAmount(uint8 num)
Unit * GetUnitOwner() const
Definition SpellAuras.h:147
AuraApplication const * GetApplicationOfTarget(ObjectGuid guid) const
Definition SpellAuras.h:234
ObjectGuid GetCasterGUID() const
Definition SpellAuras.h:144
bool HasEffect(uint8 effIndex) const
Definition SpellAuras.h:224
bool IsRemoved() const
Definition SpellAuras.h:209
float GetCritChance() const
Definition SpellAuras.h:196
void TriggerProcOnEvent(uint8 procEffectMask, AuraApplication *aurApp, ProcEventInfo &eventInfo)
WorldObject * GetOwner() const
Definition SpellAuras.h:146
bool IsSingleTargetWith(Aura const *aura) const
bool ModCharges(int32 num, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
bool CanStackWith(Aura const *existingAura) const
uint32 GetId() const
Definition SpellAuras.h:141
int32 CalcDispelChance(Unit const *auraTarget, bool offensive) const
bool IsAppliedOnTarget(ObjectGuid guid) const
Definition SpellAuras.h:236
int32 GetDuration() const
Definition SpellAuras.h:173
void UpdateOwner(uint32 diff, WorldObject *owner)
void UnregisterSingleTarget()
bool IsDeathPersistent() const
AuraEffect * GetEffect(uint8 effIndex) const
Definition SpellAuras.h:226
Unit * GetCaster() const
bool CanApplyResilience() const
Definition SpellAuras.h:193
void SetNeedClientUpdateForTargets() const
bool ModStackAmount(int32 num, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, bool resetPeriodicTimer=true)
uint8 GetEffectMask() const
Definition SpellAuras.h:227
void SetDuration(int32 duration, bool withMods=false)
void CallScriptEffectAfterAbsorbHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount)
void CallScriptEffectManaShieldHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount, bool &defaultPrevented)
AuraObjectType GetType() const
uint8 GetStackAmount() const
Definition SpellAuras.h:189
uint8 GetCharges() const
Definition SpellAuras.h:180
SpellInfo const * GetSpellInfo() const
Definition SpellAuras.h:140
ObjectGuid GetCastItemGUID() const
Definition SpellAuras.h:143
void HandleAuraSpecificMods(AuraApplication const *aurApp, Unit *caster, bool apply, bool onReapply)
void SetIsSingleTarget(bool val)
Definition SpellAuras.h:214
virtual void _ApplyForTarget(Unit *target, Unit *caster, AuraApplication *auraApp)
bool IsPassive() const
std::unordered_map< ObjectGuid, AuraApplication * > ApplicationMap
Definition SpellAuras.h:129
void CallScriptEffectAfterManaShieldHandlers(AuraEffect *aurEff, AuraApplication const *aurApp, DamageInfo &dmgInfo, uint32 &absorbAmount)
virtual void Remove(AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)=0
void CallScriptAfterDispel(DispelInfo *dispelInfo)
void _Remove(AuraRemoveMode removeMode)
bool IsSingleTarget() const
Definition SpellAuras.h:212
bool isArena() const
void append(T value)
Definition ByteBuffer.h:133
std::unordered_map< ObjectGuid, PvPCombatReference * > const & GetPvPCombatRefs() const
void Update(uint32 tdiff)
bool HasPvECombat() const
std::unordered_map< ObjectGuid, CombatReference * > const & GetPvECombatRefs() const
bool HasPvPCombat() const
virtual void OnSpellClick(Unit *, bool)
Definition CreatureAI.h:240
virtual void OnSpellFailed(SpellInfo const *)
Definition CreatureAI.h:152
virtual void KilledUnit(Unit *)
Definition CreatureAI.h:133
float GetSpellDamageMod(int32 Rank) const
Loot loot
Definition Creature.h:218
bool isWorldBoss() const
uint16 GetLootMode() const
Definition Creature.h:231
uint32 m_spells[MAX_CREATURE_SPELLS]
Definition Creature.h:238
void SetLootRecipient(Unit *unit, bool withGroup=true)
bool CanWalk() const
Definition Creature.h:114
bool CanFly() const override
Definition Creature.h:117
void SetLastDamagedTime(time_t val)
Definition Creature.h:359
bool IsEvadingAttacks() const
Definition Creature.h:156
void AllLootRemovedFromCorpse()
bool hasLootRecipient() const
Definition Creature.h:225
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
Player * GetLootRecipient() const
CreatureTemplate const * GetCreatureTemplate() const
Definition Creature.h:195
bool IsDamageEnoughForLootingAndReward() const
Definition Creature.h:330
bool isTappedBy(Player const *player) const
bool CanEnterWater() const override
Group * GetLootRecipientGroup() const
void SendAIReaction(AiReaction reactionType)
void CallAssistance()
bool IsInEvadeMode() const
Definition Creature.h:155
CreatureAI * AI() const
Definition Creature.h:163
void LowerPlayerDamageReq(uint32 unDamage)
void ResistDamage(uint32 amount)
Definition Unit.cpp:208
void AbsorbDamage(uint32 amount)
Definition Unit.cpp:200
uint32 m_resist
Definition Unit.h:454
void ModifyDamage(int32 amount)
Definition Unit.cpp:194
Unit * GetVictim() const
Definition Unit.h:473
Unit * GetAttacker() const
Definition Unit.h:472
uint32 m_block
Definition Unit.h:455
SpellInfo const * GetSpellInfo() const
Definition Unit.h:474
uint32 GetHitMask() const
Definition Unit.cpp:233
void BlockDamage(uint32 amount)
Definition Unit.cpp:220
DamageEffectType GetDamageType() const
Definition Unit.h:476
WeaponAttackType GetAttackType() const
Definition Unit.h:477
uint32 GetResist() const
Definition Unit.h:480
SpellSchoolMask GetSchoolMask() const
Definition Unit.h:475
uint32 m_absorb
Definition Unit.h:453
uint32 m_damage
Definition Unit.h:448
uint32 GetBlock() const
Definition Unit.h:481
uint32 m_hitMask
Definition Unit.h:456
DamageInfo(DamageInfo const &dmg1, DamageInfo const &dmg2)
Definition Unit.cpp:120
uint32 GetDamage() const
Definition Unit.h:478
uint32 GetAbsorb() const
Definition Unit.h:479
uint8 GetRemovedCharges() const
Definition Unit.h:420
bool RollDispel() const
Definition Unit.cpp:298
int32 _chance
Definition Unit.h:130
DispelableAura(Aura *aura, int32 dispelChance, uint8 dispelCharges)
Definition Unit.cpp:291
uint32 GetSpellId() const
void KillAllEvents(bool force)
T_VALUES GetValue(FLAG_TYPE flag) const
Definition Object.h:292
void SetValue(FLAG_TYPE flag, T_VALUES value)
Definition Object.h:293
WorldSession * GetWorldSession() const
Definition GameClient.h:41
Player * GetBasePlayer() const
Definition GameClient.h:40
std::string GetDebugInfo() const
ObjectGuid GetOwnerGUID() const override
Definition GameObject.h:141
uint32 GetSpellId() const
Definition GameObject.h:148
void Delete()
void SetOwnerGUID(ObjectGuid owner)
Definition GameObject.h:131
void SetRespawnTime(int32 respawn)
Definition Group.h:165
uint8 GetMemberGroup(ObjectGuid guid) const
Definition Group.cpp:2506
uint32 GetMembersCount() const
Definition Group.h:249
ObjectGuid GetLooterGuid() const
Definition Group.cpp:2442
void BroadcastPacket(WorldPacket const *packet, bool ignorePlayersInBGRaid, int group=-1, ObjectGuid ignoredPlayer=ObjectGuid::Empty)
Definition Group.cpp:1788
void UpdateLooterGuid(WorldObject *pLootedObject, bool ifneed=false)
Definition Group.cpp:1926
GroupReference * GetFirstMember()
Definition Group.h:247
void SendLooter(Creature *creature, Player *pLooter)
Definition Group.cpp:1008
bool InitStatsForLevel(uint8 level)
Definition Pet.cpp:861
uint32 _heal
Definition Unit.h:491
Unit * GetHealer() const
Definition Unit.h:504
uint32 _effectiveHeal
Definition Unit.h:492
uint32 GetAbsorb() const
Definition Unit.h:508
uint32 GetEffectiveHeal() const
Definition Unit.h:507
SpellInfo const * GetSpellInfo() const
Definition Unit.h:509
uint32 _absorb
Definition Unit.h:493
uint32 GetHitMask() const
Definition Unit.cpp:253
void SetEffectiveHeal(uint32 amount)
Definition Unit.h:502
SpellSchoolMask GetSchoolMask() const
Definition Unit.h:510
void AbsorbHeal(uint32 amount)
Definition Unit.cpp:243
Unit * GetTarget() const
Definition Unit.h:505
HealInfo(Unit *healer, Unit *target, uint32 heal, SpellInfo const *spellInfo, SpellSchoolMask schoolMask)
Definition Unit.cpp:238
uint32 GetHeal() const
Definition Unit.h:506
uint32 _hitMask
Definition Unit.h:496
void PermBindAllPlayers()
Definition Map.cpp:4129
Definition Item.h:62
ItemTemplate const * GetTemplate() const
Definition Item.cpp:541
bool IsBroken() const
Definition Item.h:120
uint32 GetSkill()
Definition Item.cpp:552
Definition Map.h:302
bool IsDungeon() const
Definition Map.cpp:4231
void CreatureRelocation(Creature *creature, float x, float y, float z, float ang, bool respawnRelocationOnFail=true)
Definition Map.cpp:1108
bool IsRaidOrHeroicDungeon() const
Definition Map.cpp:4246
float GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float *ground=nullptr, bool swim=false, float collisionHeight=2.03128f) const
Definition Map.cpp:2458
InstanceMap * ToInstanceMap()
Definition Map.h:540
void PlayerRelocation(Player *, float x, float y, float z, float orientation)
Definition Map.cpp:1081
Creature * GetCreature(ObjectGuid const &guid)
Definition Map.cpp:4392
void setDeathState(DeathState s) override
Unit * GetOwner() const
bool IsGuardianPet() const
bool HasMovementGenerator(std::function< bool(MovementGenerator const *)> const &filter, MovementSlot slot=MOTION_SLOT_ACTIVE) const
void LaunchMoveSpline(std::function< void(Movement::MoveSplineInit &init)> &&initializer, uint32 id=0, MovementGeneratorPriority priority=MOTION_PRIORITY_NORMAL, MovementGeneratorType type=EFFECT_MOTION_TYPE)
MovementGeneratorType GetCurrentMovementGeneratorType() const
void MoveJump(Position const &pos, float speedXY, float speedZ, uint32 id=EVENT_JUMP, bool hasOrientation=false)
void PropagateSpeedChange()
void MoveKnockbackFrom(float srcX, float srcY, float speedXY, float speedZ)
void InterruptOnTeleport()
void Update(uint32 diff)
void MoveTargetedHome()
void MoveJumpTo(float angle, float speedXY, float speedZ)
void Remove(MovementGenerator *movement, MovementSlot slot=MOTION_SLOT_ACTIVE)
void InitializeDefault()
void MoveFace(float orientation, uint32 id=EVENT_FACE)
void MoveFleeing(Unit *enemy, uint32 time=0)
static void SendSpeedChangeToMover(Unit *unit, UnitMoveType mtype, float newRate)
static MovementChangeType GetChangeTypeByMoveType(UnitMoveType moveType)
static void SendSpeedChangeToObservers(Unit *unit, UnitMoveType mtype, float newRate)
static void SendSpeedChangeToAll(Unit *unit, UnitMoveType mtype, float newRate)
void Stop(bool force=false)
bool isCyclic() const
Definition MoveSpline.h:134
std::string ToString() const
Location ComputePosition() const
bool isFalling() const
Definition MoveSpline.h:135
bool Finalized() const
Definition MoveSpline.h:133
int32 timePassed() const
Definition MoveSpline.h:100
Vector3 const & FinalDestination() const
Definition MoveSpline.h:136
int32 Duration() const
Definition MoveSpline.h:101
AnimTier GetAnimTier() const
Definition MoveSpline.h:141
bool Initialized() const
Definition MoveSpline.h:110
void updateState(int32 difftime, UpdateHandler &handler)
Definition MoveSpline.h:115
bool HasAnimation() const
Definition MoveSpline.h:140
bool HasStarted() const
Definition MoveSpline.h:145
static ObjectGuid const Empty
Definition ObjectGuid.h:140
bool IsEmpty() const
Definition ObjectGuid.h:172
bool IsPlayer() const
Definition ObjectGuid.h:179
PackedGuidWriter WriteAsPacked() const
Definition ObjectGuid.h:152
std::string ToString() const
bool IsGameObject() const
Definition ObjectGuid.h:182
bool IsAnyTypeCreature() const
Definition ObjectGuid.h:178
void Clear()
Definition ObjectGuid.h:150
void SetByteValue(uint16 index, uint8 offset, uint8 value)
Definition Object.cpp:660
void BuildValuesUpdateBlockForPlayer(UpdateData *data, Player const *target) const
Definition Object.cpp:206
uint16 m_objectType
Definition Object.h:234
static Creature * ToCreature(Object *o)
Definition Object.h:189
int32 GetInt32Value(uint16 index) const
Definition Object.cpp:235
bool IsPlayer() const
Definition Object.h:182
float GetObjectScale() const
Definition Object.h:84
PackedGuid const & GetPackGUID() const
Definition Object.h:80
static Unit * ToUnit(Object *o)
Definition Object.h:195
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:241
Player * ToPlayer()
Definition Object.h:185
bool IsInWorld() const
Definition Object.h:73
uint16 GetUInt16Value(uint16 index, uint8 offset) const
Definition Object.cpp:266
virtual void DestroyForPlayer(Player *target, bool onDeath=false) const
Definition Object.cpp:223
uint16 _fieldNotifyFlags
Definition Object.h:250
bool HasDynamicFlag(uint32 flag) const
Definition Object.h:88
bool AddGuidValue(uint16 index, ObjectGuid value)
Definition Object.cpp:612
void RemoveFieldNotifyFlag(uint16 flag)
Definition Object.h:165
UpdateMask _changesMask
Definition Object.h:246
TypeID GetTypeId() const
Definition Object.h:93
uint32 * m_uint32Values
Definition Object.h:242
uint16 m_valuesCount
Definition Object.h:248
void SetFlag(uint16 index, uint32 newFlag)
Definition Object.cpp:761
void RemoveFlag(uint16 index, uint32 oldFlag)
Definition Object.cpp:776
virtual void SetDynamicFlag(uint32 flag)
Definition Object.h:89
float GetFloatValue(uint16 index) const
Definition Object.cpp:253
void SetGuidValue(uint16 index, ObjectGuid value)
Definition Object.cpp:691
uint32 GetEntry() const
Definition Object.h:81
bool IsCreature() const
Definition Object.h:188
Creature * ToCreature()
Definition Object.h:191
void SetFloatValue(uint16 index, float value)
Definition Object.cpp:647
bool RemoveGuidValue(uint16 index, ObjectGuid value)
Definition Object.cpp:629
bool HasFlag(uint16 index, uint32 flag) const
Definition Object.cpp:800
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
float * m_floatValues
Definition Object.h:243
virtual void SetObjectScale(float scale)
Definition Object.h:85
void SetFieldNotifyFlag(uint16 flag)
Definition Object.h:164
void SetUInt32Value(uint16 index, uint32 value)
Definition Object.cpp:577
uint16 m_updateFlag
Definition Object.h:237
ObjectGuid GetGUID() const
Definition Object.h:79
TypeID m_objectTypeId
Definition Object.h:236
void SetStatInt32Value(uint16 index, int32 value)
Definition Object.cpp:712
static Player * ToPlayer(Object *o)
Definition Object.h:183
void ForceValuesUpdateAtIndex(uint32)
Definition Object.cpp:1778
std::size_t size() const
Definition ObjectGuid.h:278
Definition PetAI.h:30
PetInfo const * GetUnslottedHunterPet() const
Definition PetDefines.h:117
Optional< PetInfo > CurrentPet
Definition PetDefines.h:112
Definition Pet.h:40
void FillPetInfo(PetStable::PetInfo *petInfo) const
Definition Pet.cpp:536
std::string GetDebugInfo() const override
Definition Pet.cpp:2045
bool CreateBaseAtCreatureInfo(CreatureTemplate const *cinfo, Unit *owner)
Definition Pet.cpp:823
bool CreateBaseAtCreature(Creature *creature)
Definition Pet.cpp:790
bool isControlled() const
Definition Pet.h:53
void InitPetCreateSpells()
Definition Pet.cpp:1629
void SetAuraUpdateMaskForRaid(uint8 slot)
Definition Pet.h:144
void StopCastingBindSight() const
Definition Player.cpp:24084
bool HaveAtClient(Object const *u) const
Definition Player.cpp:22065
uint32 GetTeam() const
Definition Player.h:1818
void SetClientControl(Unit *target, bool allowMove)
Definition Player.cpp:23718
bool IsInSameRaidWith(Player const *p) const
Definition Player.cpp:2329
void SendAttackSwingCancelAttack() const
Definition Player.cpp:20067
void SetGroupUpdateFlag(uint32 flag)
Definition Player.h:2165
void DuelComplete(DuelCompleteType type)
Definition Player.cpp:6938
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6163
uint16 GetSkillValue(uint32 skill) const
Definition Player.cpp:5906
void SendAutoRepeatCancel(Unit *target)
Definition Player.cpp:20087
PetStable & GetOrInitPetStable()
Definition Player.cpp:25938
float GetRatingBonusValue(CombatRating cr) const
Definition Player.cpp:5218
void CharmSpellInitialize()
Definition Player.cpp:20722
bool isAllowedToLoot(Creature const *creature) const
Definition Player.cpp:17609
void UpdatePvPState(bool onlyFFA=false)
Definition Player.cpp:21641
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1=0, uint32 miscValue2=0, WorldObject *ref=nullptr)
Definition Player.cpp:24914
bool InBattleground() const
Definition Player.h:1969
void DurabilityPointLossForEquipSlot(EquipmentSlots slot)
Definition Player.cpp:4673
void PetSpellInitialize()
Definition Player.cpp:20594
uint32 GetBaseSpellPowerBonus() const
Returns base spellpower bonus from spellpower stat on items.
Definition Player.h:1671
void SetFallInformation(uint32 time, float z)
Definition Player.cpp:24827
Pet * GetPet() const
Definition Player.cpp:20284
uint32 GetResurrectionSpellId()
Definition Player.cpp:23505
void SendRemoveControlBar() const
Definition Player.cpp:20777
WorldSession * GetSession() const
Definition Player.h:1705
OutdoorPvP * GetOutdoorPvP() const
Definition Player.cpp:23397
void CastItemCombatSpell(DamageInfo const &damageInfo)
Definition Player.cpp:7661
static uint32 TeamForRace(uint8 race)
Definition Player.cpp:6271
uint16 GetMaxSkillValue(uint32 skill) const
Definition Player.cpp:5921
void RewardPlayerAndGroupAtKill(Unit *victim, bool isBattleGround)
Definition Player.cpp:23606
PlayerSpellMap const & GetSpellMap() const
Definition Player.h:1518
void StopCastingCharm()
Definition Player.cpp:20412
Battleground * GetBattleground() const
Definition Player.cpp:23024
float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const
Definition Player.cpp:5223
Group * GetGroup()
Definition Player.h:2159
bool IsGameMaster() const
Definition Player.h:976
void PossessSpellInitialize()
Definition Player.cpp:20643
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition Player.cpp:9605
std::unique_ptr< DuelInfo > duel
Definition Player.h:1587
uint8 GetSubGroup() const
Definition Player.h:2163
void VehicleSpellInitialize()
Definition Player.cpp:20671
void SendMessageToSet(WorldPacket const *data, bool self) const override
Definition Player.h:1733
void SetFactionForRace(uint8 race)
Definition Player.cpp:6297
void SetContestedPvP(Player *attackedPlayer=nullptr)
Definition Player.cpp:20210
void ResummonPetTemporaryUnSummonedIfAny()
Definition Player.cpp:25183
void UpdateCombatSkills(Unit *victim, WeaponAttackType attType, bool defense)
Definition Player.cpp:5659
bool CanSeeSpellClickOn(Creature const *creature) const
Definition Player.cpp:25207
void UpdatePvP(bool state, bool override=false)
Definition Player.cpp:21684
bool IsInSameGroupWith(Player const *p) const
Definition Player.cpp:2322
DamageInfo * _damageInfo
Definition Unit.h:546
SpellSchoolMask GetSchoolMask() const
Definition Unit.cpp:280
HealInfo * _healInfo
Definition Unit.h:547
ProcEventInfo(Unit *actor, Unit *actionTarget, uint32 typeMask, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition Unit.cpp:258
Spell const * GetProcSpell() const
Definition Unit.h:536
SpellInfo const * GetSpellInfo() const
Definition Unit.cpp:269
Spell * _spell
Definition Unit.h:545
Mechanics Mechanic
Definition SpellInfo.h:222
AuraType ApplyAuraName
Definition SpellInfo.h:211
float CalcValueMultiplier(WorldObject *caster, Spell *spell=nullptr) const
SpellEffects Effect
Definition SpellInfo.h:210
bool IsEffect() const
float BonusCoefficient
Definition SpellInfo.h:219
SpellEffIndex EffectIndex
Definition SpellInfo.h:209
void SendCooldownEvent(SpellInfo const *spellInfo, uint32 itemId=0, Spell *spell=nullptr, bool startCooldown=true)
void StartCooldown(SpellInfo const *spellInfo, uint32 itemId, Spell *spell=nullptr, bool onHold=false)
uint32 MaxLevel
Definition SpellInfo.h:327
uint32 GetMaxTicks() const
Mechanics GetEffectMechanic(SpellEffIndex effIndex) const
SpellInfo const * GetFirstRankSpell() const
bool IsAutocastable() const
uint32 GetCategory() const
bool IsRequiringDeadTarget() const
flag96 SpellFamilyFlags
Definition SpellInfo.h:357
DiminishingLevels GetDiminishingReturnsMaxLevel(bool triggered) const
bool IsGroupBuff() const
bool IsDeathPersistent() const
bool IsCooldownStartedOnEvent() const
bool IsPassive() const
uint32 Mechanic
Definition SpellInfo.h:292
uint32 Id
Definition SpellInfo.h:289
bool IsStackableOnOneSlotWithDifferentCasters() const
uint32 GetDispelMask() const
uint32 CalcCastTime(Spell *spell=nullptr) const
SpellSpecificType GetSpellSpecific() const
uint32 Dispel
Definition SpellInfo.h:291
bool IsMultiSlotAura() const
int32 GetMaxDuration() const
uint32 SchoolMask
Definition SpellInfo.h:361
uint32 CasterAuraState
Definition SpellInfo.h:308
SpellCastResult CheckTarget(WorldObject const *caster, WorldObject const *target, bool implicit=true) const
DiminishingGroup GetDiminishingReturnsGroupForSpell(bool triggered) const
bool IsItemFitToSpellRequirements(Item const *item) const
uint32 GetSpellMechanicMaskByEffectMask(uint32 effectMask) const
WeaponAttackType GetAttackType() const
SpellSchoolMask GetSchoolMask() const
AuraStateType GetAuraState() const
bool IsChanneled() const
bool HasAttribute(SpellAttr0 attribute) const
Definition SpellInfo.h:375
bool IsPassiveStackableWithRanks() const
int32 GetDiminishingReturnsLimitDuration(bool triggered) const
int32 GetDuration() const
SpellCastResult CheckExplicitTarget(WorldObject const *caster, WorldObject const *target, Item const *itemTarget=nullptr) const
uint32 GetAllEffectsMechanicMask() const
bool CanPierceImmuneAura(SpellInfo const *auraSpellInfo) const
uint32 SpellIconID
Definition SpellInfo.h:349
bool NeedsExplicitUnitTarget() const
DiminishingReturnsType GetDiminishingReturnsGroupType(bool triggered) const
bool HasEffect(SpellEffects effect) const
bool IsPositive() const
uint32 DmgClass
Definition SpellInfo.h:358
bool IsRangedWeaponSpell() const
bool HasAura(AuraType aura) const
std::array< SpellEffectInfo, MAX_SPELL_EFFECTS > const & GetEffects() const
Definition SpellInfo.h:482
uint32 SpellFamilyName
Definition SpellInfo.h:356
uint32 AuraInterruptFlags
Definition SpellInfo.h:322
bool IsPositiveEffect(uint8 effIndex) const
bool IsSingleTarget() const
Definition Spell.h:152
SpellInfo const * GetSpellInfo() const
Definition Spell.h:459
void cast(bool skipCheck=false)
Definition Spell.cpp:3354
bool IsInterruptable() const
Definition Spell.h:443
void SendChannelUpdate(uint32 time)
Definition Spell.cpp:4646
bool IsProcDisabled() const
Definition Spell.cpp:7518
int32 GetCastTime() const
Definition Spell.h:427
uint32 getState() const
Definition Spell.h:356
void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const &damageInfo, uint32 &resistAmount, int32 &absorbAmount)
Definition Spell.cpp:8319
CurrentSpellTypes GetCurrentContainer() const
Definition Spell.cpp:7363
void cancel(SpellCastResult result=SPELL_FAILED_INTERRUPTED, Optional< SpellCastResult > resultOther={})
Definition Spell.cpp:3292
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition Spell.cpp:3091
Spell ** m_selfContainer
Definition Spell.h:469
void SetReferencedFromCurrent(bool yes)
Definition Spell.h:442
UsedSpellMods m_appliedMods
Definition Spell.h:425
SpellCastResult CheckCast(bool strict, uint32 *param1=nullptr, uint32 *param2=nullptr)
Definition Spell.cpp:5148
void finish(bool ok=true)
Definition Spell.cpp:3943
static void SendCastResult(Player *caster, SpellInfo const *spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError=SPELL_CUSTOM_ERROR_NONE, uint32 *param1=nullptr, uint32 *param2=nullptr)
Definition Spell.cpp:4150
SpellInfo const *const m_spellInfo
Definition Spell.h:396
virtual void UnSummon(uint32 msTime=0)
SummonPropertiesEntry const *const m_Properties
Unit * GetSummonerUnit() const
void ForwardThreatForAssistingMe(Unit *assistant, float baseAmount, SpellInfo const *spell=nullptr, bool ignoreModifiers=false)
== AFFECT OTHERS' THREAT LISTS ==
bool IsThreatListEmpty(bool includeOffline=false) const
void AddThreat(Unit *target, float amount, SpellInfo const *spell=nullptr, bool ignoreModifiers=false, bool ignoreRedirects=false)
== AFFECT MY THREAT LIST ==
uint32 GetSpell(uint8 slot=0) const
Definition Totem.h:47
Utility class to enable range for loop syntax for multimap.equal_range uses.
constexpr end_iterator end() const
constexpr iterator begin() const
virtual void OnCharmed(bool isNew)
Definition UnitAI.cpp:42
Definition Unit.h:783
float GetUnitMissChance() const
Definition Unit.cpp:2684
float GetSpellCritChanceReduction() const
Definition Unit.h:1069
void EnterVehicle(Unit *base, int8 seatId=-1)
Definition Unit.cpp:12540
int32 ModifyHealth(int32 val)
Definition Unit.cpp:8321
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:724
float GetPctModifierValue(UnitMods unitMod, UnitModifierPctType modifierType) const
Definition Unit.cpp:9040
uint32 m_reactiveTimer[MAX_REACTIVE]
Definition Unit.h:1913
Unit * GetCharmed() const
Definition Unit.h:1269
void ClearUnitState(uint32 f)
Definition Unit.h:891
void OutDebugInfo() const
Definition Unit.cpp:13089
bool IsWithinMeleeRangeAt(Position const &pos, Unit const *obj) const
Definition Unit.cpp:627
void SendComboPoints()
Definition Unit.cpp:10471
bool IsStopped() const
Definition Unit.h:1687
bool IsVehicle() const
Definition Unit.h:901
void SetMinion(Minion *minion, bool apply)
Definition Unit.cpp:5852
std::pair< AuraApplicationMap::iterator, AuraApplicationMap::iterator > AuraApplicationMapBoundsNonConst
Definition Unit.h:796
uint32 SpellHealingBonusTaken(Unit *caster, SpellInfo const *spellProto, uint32 healamount, DamageEffectType damagetype) const
Definition Unit.cpp:7498
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition Unit.cpp:8379
void CastStop(uint32 except_spellid=0)
Definition Unit.cpp:999
bool IsUnderLastManaUseEffect() const
Definition Unit.cpp:10822
void SetImmuneToAll(bool apply, bool keepCombat)
Definition Unit.cpp:8243
bool IsCharmed() const
Definition Unit.h:1293
void BuildValuesUpdate(uint8 updatetype, ByteBuffer *data, Player const *target) const override
Definition Unit.cpp:13545
void SetImmuneToPC(bool apply, bool keepCombat)
Definition Unit.cpp:8256
bool m_duringRemoveFromWorld
Definition Unit.h:1988
void RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3584
Vehicle * GetVehicle() const
Definition Unit.h:1753
bool HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag96 familyFlags) const
Definition Unit.cpp:679
void SetVisible(bool x)
Definition Unit.cpp:8453
virtual bool IsMovementPreventedByCasting() const
Definition Unit.cpp:3146
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3788
void AddComboPointHolder(Unit *unit)
Definition Unit.h:1720
void JumpTo(float speedXY, float speedZ, bool forward=true, Optional< Position > dest={})
Definition Unit.cpp:12425
bool HealthAbovePct(int32 pct) const
Definition Unit.h:933
void DeleteCharmInfo()
Definition Unit.cpp:9715
void RemoveGameObject(GameObject *gameObj, bool del)
Definition Unit.cpp:5161
bool isTargetableForAttack(bool checkFakeDeath=true) const
Definition Unit.cpp:8307
bool IsHunterPet() const
Definition Unit.h:899
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition Unit.h:1397
uint32 GetSchoolImmunityMask() const
Definition Unit.cpp:7721
Spell * m_currentSpells[CURRENT_MAX_SPELL]
Definition Unit.h:1881
bool IsBlockCritical()
Definition Unit.cpp:2375
void SetAnimTier(AnimTier animTier)
Definition Unit.cpp:10367
bool IsCharmerOrSelfPlayer() const
Definition Unit.h:1307
float m_baseSpellCritChance
Definition Unit.h:1513
SpellImmuneContainer m_spellImmune[MAX_SPELL_IMMUNITY]
Definition Unit.h:1584
uint32 GetMechanicImmunityMask() const
Definition Unit.cpp:7741
void AIUpdateTick(uint32 diff)
Definition Unit.cpp:9491
Unit * GetCharmerOrSelf() const
Definition Unit.cpp:6238
virtual void RecalculateObjectScale()
Definition Unit.cpp:10375
void HandleAttackPowerModifier(AttackPowerModIndex index, AttackPowerModType modifierType, float amount, bool apply)
Definition Unit.cpp:9091
float CalculateSpellpowerCoefficientLevelPenalty(SpellInfo const *spellInfo) const
Definition Unit.cpp:2345
virtual MovementGeneratorType GetDefaultMovementType() const
Definition Unit.cpp:10284
AuraList m_removedAuras
Definition Unit.h:1885
uint32 GetUnitMovementFlags() const
Definition Unit.h:1695
LiquidTypeEntry const * _lastLiquid
Definition Unit.h:1920
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4462
AuraApplication * GetVisibleAura(uint8 slot) const
Definition Unit.cpp:648
static uint32 SpellCriticalHealingBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition Unit.cpp:7240
void _UpdateAutoRepeatSpell()
Definition Unit.cpp:2925
void SendMoveKnockBack(Player *player, float speedXY, float speedZ, float vcos, float vsin)
Definition Unit.cpp:12164
float GetRangedCritChanceReduction() const
Definition Unit.h:1068
float GetTotalAuraModValue(UnitMods unitMod) const
Definition Unit.cpp:9219
void RestoreDisabledAI()
Definition Unit.cpp:9545
void Heartbeat() override
Definition Unit.cpp:510
void RemoveAllControlled()
Definition Unit.cpp:6193
Pet * ToPet()
Definition Unit.h:1804
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Definition Unit.h:1136
Movement::MoveSpline * movespline
Definition Unit.h:1820
void RemoveGameObjectImpl(GameObject *gameObj, bool del)
Definition Unit.cpp:5134
void RemoveAurasByShapeShift()
Definition Unit.cpp:4132
float GetTotalStatValue(Stats stat) const
Definition Unit.cpp:9206
void SetGender(Gender gender)
Definition Unit.h:913
float GetUnitCriticalChanceTaken(Unit const *attacker, WeaponAttackType attackType, float critDone) const
Definition Unit.cpp:2767
bool IsContestedGuard() const
Definition Unit.cpp:11919
std::unordered_map< ObjectGuid, uint32 > extraAttacksTargets
Definition Unit.h:1984
std::unordered_set< Unit * > m_ComboPointHolders
Definition Unit.h:1981
void UpdateUnitMod(UnitMods unitMod)
Definition Unit.cpp:9051
void UpdateDamagePctDoneMods(WeaponAttackType attackType)
Definition Unit.cpp:9162
float GetSpeed(UnitMoveType mtype) const
Definition Unit.cpp:8608
bool SetFall(bool enable)
Definition Unit.cpp:13314
void _UnregisterDynObject(DynamicObject *dynObj)
Definition Unit.cpp:5056
bool m_canModifyStats
Definition Unit.h:1899
Aura * GetAuraOfRankedSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4480
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3661
void UpdateObjectVisibility(bool forced=true) override
Definition Unit.cpp:12151
void SendEnergizeSpellLog(Unit *victim, uint32 spellId, int32 damage, Powers powerType)
Definition Unit.cpp:6369
std::shared_ptr< UnitAI > i_AI
Definition Unit.h:1974
void SetCurrentCastSpell(Spell *pSpell)
Definition Unit.cpp:2968
bool _isCombatDisallowed
Definition Unit.h:1998
void SetFullHealth()
Definition Unit.h:941
void SetMinionGUID(ObjectGuid guid)
Definition Unit.h:1259
Diminishing m_Diminishing
Definition Unit.h:1962
void UpdateHeight(float newZ)
Only server-side height update, does not broadcast to client.
Definition Unit.cpp:12917
void _RemoveNoStackAurasDueToAura(Aura *aura, bool owned)
Definition Unit.cpp:3555
void SetConfused(bool apply)
Definition Unit.cpp:11434
void _UpdateSpells(uint32 time)
Definition Unit.cpp:2865
ThreatManager & GetThreatManager()
Definition Unit.h:1169
void RemoveNotOwnSingleTargetAuras(uint32 newPhase=0x0)
Definition Unit.cpp:3998
void ReplaceAllPvpFlags(UnitPVPStateFlags flags)
Definition Unit.h:999
void AddToWorld() override
Definition Unit.cpp:9569
void RestoreFaction()
Definition Unit.cpp:11747
float GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const *spellProto) const
Definition Unit.cpp:8110
virtual void AtExitCombat()
Definition Unit.cpp:8720
void _UnapplyAura(AuraApplicationMap::iterator &i, AuraRemoveMode removeMode)
Definition Unit.cpp:3444
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition Unit.cpp:4578
void SetInCombatWith(Unit *enemy, bool addSecondUnitSuppressed=false)
Definition Unit.h:1160
virtual void Say(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition Unit.cpp:13805
void PropagateSpeedChange()
-------—End of Pet responses methods-------—
Definition Unit.cpp:10279
bool HasBreakableByDamageCrowdControlAura(Unit *excludeCasterChannel=nullptr) const
Definition Unit.cpp:701
void DelayOwnedAuras(uint32 spellId, ObjectGuid caster, int32 delaytime)
Definition Unit.cpp:4351
std::vector< std::pair< uint8, AuraApplication * > > AuraApplicationProcContainer
Definition Unit.h:806
void SetControlled(bool apply, UnitState state)
Definition Unit.cpp:11227
uint8 GetClass() const
Definition Unit.h:909
SpellSchools GetSpellSchoolByAuraGroup(UnitMods unitMod) const
Definition Unit.cpp:9235
void SetStunned(bool apply)
Definition Unit.cpp:11326
Stats GetStatByAuraGroup(UnitMods unitMod) const
Definition Unit.cpp:9255
void PushPendingMovementChange(PlayerMovementPendingChange newChange)
Definition Unit.cpp:12936
uint32 m_state
Definition Unit.h:1959
void HandleSpellClick(Unit *clicker, int8 seatId=-1)
Definition Unit.cpp:12449
bool CanUseAttackType(uint8 attacktype) const
Definition Unit.cpp:2405
bool IsWithinCombatRange(Unit const *obj, float dist2compare) const
Definition Unit.cpp:611
std::list< Aura * > AuraList
Definition Unit.h:802
void RemoveAurasWithInterruptFlags(uint32 flag, uint32 except=0)
Definition Unit.cpp:4045
void SendPetAIReaction(ObjectGuid guid) const
Definition Unit.cpp:10265
bool HasAuraTypeWithCaster(AuraType auraType, ObjectGuid caster) const
Definition Unit.cpp:4570
Spell * FindCurrentSpellBySpellId(uint32 spell_id) const
Definition Unit.cpp:3131
uint32 GetMountDisplayId() const
Definition Unit.h:1028
void UpdateAllDamageDoneMods()
Definition Unit.cpp:9156
Vehicle * m_vehicle
Definition Unit.h:1916
Totem * ToTotem()
Definition Unit.h:1807
Creature * GetVehicleCreatureBase() const
Definition Unit.cpp:11818
void UpdateDisplayPower()
Definition Unit.cpp:5395
uint32 MeleeDamageBonusTaken(Unit *attacker, uint32 pdamage, WeaponAttackType attType, SpellInfo const *spellProto=nullptr, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL)
Definition Unit.cpp:7973
float GetCollisionHeight() const override
Definition Unit.cpp:13895
GameClient * _gameClientMovingMe
Definition Unit.h:1909
void RemoveAllGameObjects()
Definition Unit.cpp:5188
static void DealHeal(HealInfo &healInfo)
Definition Unit.cpp:6104
virtual SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType=BASE_ATTACK, uint8 damageIndex=0) const =0
bool isPossessedByPlayer() const
Definition Unit.cpp:6220
void SendClearTarget()
Definition Unit.cpp:13131
std::multimap< uint32, AuraApplication * > AuraApplicationMap
Definition Unit.h:794
void _RegisterDynObject(DynamicObject *dynObj)
Definition Unit.cpp:5051
SpellHistory * _spellHistory
Definition Unit.h:1994
void UpdateSpeed(UnitMoveType mtype)
Definition Unit.cpp:8463
bool IsMovedByClient() const
Definition Unit.h:1313
bool IsPolymorphed() const
Definition Unit.cpp:10354
ShapeshiftForm GetShapeshiftForm() const
Definition Unit.h:1503
void SetFaction(uint32 faction) override
Definition Unit.h:988
virtual void SetPvP(bool state)
Definition Unit.cpp:11927
ObjectGuid GetOwnerGUID() const override
Definition Unit.h:1254
Unit * SelectNearbyTarget(Unit *exclude=nullptr, float dist=NOMINAL_MELEE_RANGE) const
Definition Unit.cpp:10567
bool isInBackInMap(Unit const *target, float distance, float arc=float(M_PI)) const
Definition Unit.cpp:3172
float CalculateDefaultCoefficient(SpellInfo const *spellInfo, DamageEffectType damagetype) const
Definition Unit.cpp:10760
float GetCombatRatingReduction(CombatRating cr) const
Definition Unit.cpp:12192
void RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, WorldObject *dispeller, uint8 chargesRemoved=1)
Definition Unit.cpp:3840
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraApplication *except=nullptr) const
Definition Unit.cpp:4443
uint32 SpellHealingBonusDone(Unit *victim, SpellInfo const *spellProto, uint32 healamount, DamageEffectType damagetype, SpellEffectInfo const &spellEffectInfo, Optional< float > const &donePctTotal, uint32 stack=1) const
Definition Unit.cpp:7274
virtual void UpdateAttackPowerAndDamage(bool ranged=false)=0
static void CalcHealAbsorb(HealInfo &healInfo)
Definition Unit.cpp:2027
virtual void Yell(std::string_view text, Language language, WorldObject const *target=nullptr)
Definition Unit.cpp:13810
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:1006
void StopMoving(bool force=false)
Definition Unit.cpp:10289
Unit * GetVehicleRoot() const
Definition Unit.cpp:11802
void SetCantProc(bool apply)
Definition Unit.cpp:10749
Unit * GetCharmer() const
Definition Unit.h:1266
void SetSpeed(UnitMoveType mtype, float newValue)
Definition Unit.cpp:8613
void ClearComboPoints()
Definition Unit.cpp:10456
void SetStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float val)
Definition Unit.cpp:9020
Unit * getAttackerForHelper() const
Definition Unit.cpp:5454
float GetUnitParryChance(WeaponAttackType attType, Unit const *victim) const
Definition Unit.cpp:2638
void SendMeleeAttackStart(Unit *victim)
Definition Unit.cpp:2353
Pet * CreateTamedPetFrom(Creature *creatureTarget, uint32 spell_id=0)
Definition Unit.cpp:10827
Trinity::unique_trackable_ptr< Vehicle > m_vehicleKit
Definition Unit.h:1917
float GetWeaponDamageRange(WeaponAttackType attType, WeaponDamageRange type, uint8 damageIndex=0) const
Definition Unit.cpp:9307
bool IsInDisallowedMountForm() const
Definition Unit.cpp:8915
uint32 GetDefenseSkillValue(Unit const *target=nullptr) const
Definition Unit.cpp:2580
void ApplyStatPctModifier(UnitMods unitMod, UnitModifierPctType modifierType, float amount)
Definition Unit.cpp:8987
void SendSpellDamageImmune(Unit *target, uint32 spellId)
Definition Unit.cpp:5287
virtual bool IsImmunedToSpell(SpellInfo const *spellInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7631
UnitPVPStateFlags GetPvpFlags() const
Definition Unit.h:995
void SendTeleportPacket(Position const &pos, bool teleportingTransport=false)
Definition Unit.cpp:12820
float m_attackPowerMods[uint32(AttackPowerModIndex::End)][uint32(AttackPowerModType::End)]
Definition Unit.h:1897
virtual void UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot=-1)
Definition Unit.cpp:9126
void _removeAttacker(Unit *pAttacker)
Definition Unit.cpp:5449
void SendAttackStateUpdate(CalcDamageInfo *damageInfo)
Definition Unit.cpp:5297
uint32 GetTransformSpell() const
Definition Unit.h:1604
bool IsGhouled() const
Definition Unit.cpp:8663
void RemoveAllAurasExceptType(AuraType type)
Definition Unit.cpp:4295
void TriggerAurasProcOnEvent(Unit *actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition Unit.cpp:10166
void DealSpellDamage(SpellNonMeleeDamage const *damageInfo, bool durabilityLoss)
Definition Unit.cpp:1120
uint32 _lastExtraAttackSpell
Definition Unit.h:1983
static void CalcAbsorbResist(DamageInfo &damageInfo, Spell *spell=nullptr)
Definition Unit.cpp:1780
CharmInfo * m_charmInfo
Definition Unit.h:1907
PlayerMovementPendingChange PopPendingMovementChange()
Definition Unit.cpp:12929
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:3116
MotionMaster * i_motionMaster
Definition Unit.h:1911
virtual bool CanFly() const =0
void ReplaceAllUnitFlags(UnitFlags flags)
Definition Unit.h:970
void SetAuraStack(uint32 spellId, Unit *target, uint32 stack)
Definition Unit.cpp:11981
Unit * GetVehicleBase() const
Definition Unit.cpp:11797
bool haveOffhandWeapon() const
Definition Unit.cpp:518
MotionMaster * GetMotionMaster()
Definition Unit.h:1683
bool SetFeatherFall(bool enable)
Definition Unit.cpp:13436
bool IsPet() const
Definition Unit.h:898
Powers GetPowerType() const
Definition Unit.h:945
bool HasUnitFlag(UnitFlags flags) const
Definition Unit.h:967
static uint32 CalcArmorReducedDamage(Unit const *attacker, Unit *victim, uint32 damage, SpellInfo const *spellInfo, WeaponAttackType attackType=MAX_ATTACK, uint8 attackerLevel=0)
Definition Unit.cpp:1596
void _addAttacker(Unit *pAttacker)
Definition Unit.cpp:5444
void RemoveVisibleAura(uint8 slot)
Definition Unit.cpp:662
GameClient * GetGameClientMovingMe() const
Definition Unit.h:1315
bool _instantCast
Definition Unit.h:1989
void Dismount()
Definition Unit.cpp:8174
void SetCharm(Unit *target, bool apply)
Definition Unit.cpp:6027
ObjectGuid GetCharmedGUID() const
Definition Unit.h:1268
void RemoveAurasWithFamily(SpellFamilyNames family, flag96 const &familyFlag, ObjectGuid casterGUID)
Definition Unit.cpp:4074
void SetCreatedBySpell(int32 spellId)
Definition Unit.h:978
bool SetHover(bool enable, bool updateAnimTier=true)
Definition Unit.cpp:13475
bool CanDualWield() const
Definition Unit.h:851
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition Unit.cpp:3086
void UpdateInterruptMask()
Definition Unit.cpp:668
void StartReactiveTimer(ReactiveType reactive)
Definition Unit.h:1735
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition Unit.cpp:9656
uint32 GetMaxHealth() const
Definition Unit.h:928
void ResumeMovement(uint32 timer=0, uint8 slot=0)
Definition Unit.cpp:10316
Aura * AddAura(uint32 spellId, Unit *target)
Definition Unit.cpp:11935
AuraEffect * GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition Unit.cpp:4382
bool isAttackingPlayer() const
Definition Unit.cpp:5660
ObjectGuid m_ObjectSlot[MAX_GAMEOBJECT_SLOT]
Definition Unit.h:1501
UnitAIStack i_AIs
Definition Unit.h:1973
float SpellDamagePctDone(Unit *victim, SpellInfo const *spellProto, DamageEffectType damagetype) const
Definition Unit.cpp:6533
virtual void UpdateResistances(uint32 school)=0
int32 GetMaxNegativeAuraModifier(AuraType auraType) const
Definition Unit.cpp:4830
void UpdateSplineMovement(uint32 t_diff)
Definition Unit.cpp:536
uint32 GetSpellCritDamageReduction(uint32 damage) const
Definition Unit.h:1074
float GetMeleeCritChanceReduction() const
Definition Unit.h:1067
bool HasUnitFlag2(UnitFlags2 flags) const
Definition Unit.h:973
bool CanFreeMove() const
Definition Unit.cpp:9315
std::string GetDebugInfo() const override
Definition Unit.cpp:13921
std::pair< AuraMap::const_iterator, AuraMap::const_iterator > AuraMapBounds
Definition Unit.h:791
uint32 GetRangedDamageReduction(uint32 damage) const
Definition Unit.h:1078
uint32 BuildAuraStateUpdateForTarget(Unit const *target) const
Definition Unit.cpp:5746
bool isInFrontInMap(Unit const *target, float distance, float arc=float(M_PI)) const
Definition Unit.cpp:3167
float m_createStats[MAX_STATS]
Definition Unit.h:1863
float m_auraFlatModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_FLAT_END]
Definition Unit.h:1895
bool HasAuraWithMechanic(uint32 mechanicMask) const
Definition Unit.cpp:4625
void SetImmuneToNPC(bool apply, bool keepCombat)
Definition Unit.cpp:8279
void PauseMovement(uint32 timer=0, uint8 slot=0, bool forced=true)
Definition Unit.cpp:10304
void SetPetNameTimestamp(uint32 timestamp)
Definition Unit.h:1304
bool IsSplineEnabled() const
Definition Unit.cpp:13540
void RemoveAllAurasRequiringDeadTarget()
Definition Unit.cpp:4274
void UpdateReactives(uint32 p_time)
Definition Unit.cpp:10525
bool IsAlive() const
Definition Unit.h:1247
virtual bool CanApplyResilience() const
Definition Unit.cpp:11998
AuraEffect * IsScriptOverriden(SpellInfo const *spell, int32 script) const
Definition Unit.cpp:4662
float m_modRangedHitChance
Definition Unit.h:1511
float GetCombatReach() const override
Definition Unit.h:853
void AtTargetAttacked(Unit *target, bool canInitialAggro)
Definition Unit.cpp:8731
static uint32 CalcSpellResistedDamage(Unit const *attacker, Unit *victim, uint32 damage, SpellSchoolMask schoolMask, SpellInfo const *spellInfo)
Definition Unit.cpp:1664
DeathState m_deathState
Definition Unit.h:1868
std::deque< PlayerMovementPendingChange > m_pendingMovementChanges
Definition Unit.h:2004
void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply)
Definition Unit.cpp:10598
int32 GetMinPower(Powers) const
Definition Unit.h:949
uint32 m_unitTypeMask
Definition Unit.h:1919
std::pair< AuraApplicationMap::const_iterator, AuraApplicationMap::const_iterator > AuraApplicationMapBounds
Definition Unit.h:795
int32 GetMaxNegativeAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition Unit.cpp:4865
int32 HealBySpell(HealInfo &healInfo, bool critical=false)
Definition Unit.cpp:6360
void AddPlayerToVision(Player *player)
Definition Unit.cpp:6298
void RemoveNpcFlag(NPCFlags flags)
Definition Unit.h:1112
void SendHealSpellLog(HealInfo &healInfo, bool critical=false)
Definition Unit.cpp:6345
void RewardRage(uint32 damage, uint32 weaponSpeedHitFactor, bool attacker)
Definition Unit.cpp:13019
int32 GetMaxPositiveAuraModifier(AuraType auraType) const
Definition Unit.cpp:4825
GameObject * GetGameObject(uint32 spellId) const
Definition Unit.cpp:5100
virtual ~Unit()
Definition Unit.cpp:408
void _ExitVehicle(Position const *exitPosition=nullptr)
Definition Unit.cpp:12651
float SpellCritChanceTaken(Unit const *caster, SpellInfo const *spellInfo, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType=BASE_ATTACK, bool isPeriodic=false) const
Definition Unit.cpp:7009
uint32 m_removedAurasCount
Definition Unit.h:1887
uint32 GetRangedCritDamageReduction(uint32 damage) const
Definition Unit.h:1073
void RemoveAllAurasOnDeath()
Definition Unit.cpp:4251
uint32 m_movementCounter
Definition Unit.h:2003
void SetHealth(uint32 val)
Definition Unit.cpp:9338
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const *log)
Definition Unit.cpp:5199
void RemoveVehicleKit()
Definition Unit.cpp:11779
bool IsStandState() const
Definition Unit.cpp:10334
TempSummon * ToTempSummon()
Definition Unit.h:1810
void SetMaxPower(Powers power, uint32 val)
Definition Unit.cpp:9439
bool IsGravityDisabled() const
Definition Unit.h:1231
PlayerMovementPendingChange & PeakFirstPendingMovementChange()
Definition Unit.cpp:12924
CharmInfo * GetCharmInfo()
Definition Unit.h:1300
ControlList m_Controlled
Definition Unit.h:1289
bool IsInCombatWith(Unit const *who) const
Definition Unit.h:1159
void DisableSpline()
Definition Unit.cpp:600
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition Unit.h:1273
int32 GetMechanicResistChance(SpellInfo const *spellInfo) const
Definition Unit.cpp:2382
int32 GetMaxPositiveAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:4895
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4558
Unit * m_comboTarget
Definition Unit.h:1979
AuraMap::iterator m_auraUpdateIterator
Definition Unit.h:1886
UnitAI * GetAI() const
Definition Unit.h:814
std::list< AuraApplication * > AuraApplicationList
Definition Unit.h:803
Unit * GetMeleeHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:6161
ObjectGuid _lastDamagedTargetGuid
Definition Unit.h:1985
bool SetDisableGravity(bool disable, bool updateAnimTier=true)
Definition Unit.cpp:13262
void SetSpeedRateReal(UnitMoveType mtype, float rate)
Definition Unit.cpp:8647
void RemoveAllFollowers()
Definition Unit.cpp:8657
bool m_AutoRepeatFirstCast
Definition Unit.h:1861
uint32 CalculateDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, uint8 itemDamagesMask=0) const
Definition Unit.cpp:2293
void _DeleteRemovedAuras()
Definition Unit.cpp:2854
uint32 m_attackTimer[MAX_ATTACK]
Definition Unit.h:1516
Unit * GetNextRandomRaidMemberOrPet(float radius)
Definition Unit.cpp:6246
Powers GetPowerTypeByAuraGroup(UnitMods unitMod) const
Definition Unit.cpp:9274
void SetVirtualItem(uint32 slot, uint32 itemId)
Definition Unit.cpp:13839
virtual bool IsAffectedByDiminishingReturns() const
Definition Unit.h:835
std::pair< AuraStateAurasMap::const_iterator, AuraStateAurasMap::const_iterator > AuraStateAurasMapBounds
Definition Unit.h:799
int32 GetTotalAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition Unit.cpp:4835
void AddUnitState(uint32 f)
Definition Unit.h:889
void ClearComboPointHolders()
Definition Unit.cpp:10504
float SpellCritChanceDone(SpellInfo const *spellInfo, SpellSchoolMask schoolMask, WeaponAttackType attackType=BASE_ATTACK, bool isPeriodic=false) const
Definition Unit.cpp:6955
float GetTotalAuraMultiplier(AuraType auraType) const
Definition Unit.cpp:4820
void Mount(uint32 mount, uint32 vehicleId=0, uint32 creatureEntry=0)
Definition Unit.cpp:8124
bool IsOnVehicle(Unit const *vehicle) const
Definition Unit.cpp:11792
void SendSpellDamageResist(Unit *target, uint32 spellId)
Definition Unit.cpp:5277
void RemoveComboPointHolder(Unit *unit)
Definition Unit.h:1721
uint32 SpellDamageBonusDone(Unit *victim, SpellInfo const *spellProto, uint32 pdamage, DamageEffectType damagetype, SpellEffectInfo const &spellEffectInfo, Optional< float > const &donePctTotal, uint32 stack=1) const
Definition Unit.cpp:6393
bool isInAccessiblePlaceFor(Creature const *c) const
Definition Unit.cpp:3177
bool IsCharmedOwnedByPlayerOrPlayer() const
Definition Unit.h:1274
Gender GetGender() const
Definition Unit.h:912
Unit * EnsureVictim() const
Definition Unit.h:875
int32 GetMaxNegativeAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:4905
uint32 getAttackTimer(WeaponAttackType type) const
Definition Unit.h:848
void RefreshAI()
Definition Unit.cpp:9523
void CheckPendingMovementAcks()
Definition Unit.cpp:12950
bool IsDuringRemoveFromWorld() const
Definition Unit.h:1802
bool m_ControlledByPlayer
Definition Unit.h:1859
void SetFeared(bool apply)
Definition Unit.cpp:11399
void AddInterruptMask(uint32 flags)
Definition Unit.h:1593
Unit * GetCharmerOrOwner() const
Definition Unit.h:1278
uint32 GetDiseasesByCaster(ObjectGuid casterGUID, bool remove=false)
Definition Unit.cpp:4674
void RemoveAurasDueToItemSpell(uint32 spellId, ObjectGuid castItemGuid)
Definition Unit.cpp:3952
virtual void UpdateDamagePhysical(WeaponAttackType attType)
void SetFacingToObject(WorldObject const *object, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13235
virtual Gender GetNativeGender() const
Definition Unit.h:914
void _ApplyAllAuraStatMods()
Definition Unit.cpp:4376
void ProcSkillsAndReactives(bool isVictim, Unit *procTarget, uint32 typeMask, uint32 hitMask, WeaponAttackType attType)
Definition Unit.cpp:10052
uint32 GetCreatureType() const
Definition Unit.cpp:8880
void AddGameObject(GameObject *gameObj)
Definition Unit.cpp:5116
void RemoveAurasWithMechanic(uint32 mechanicMaskToRemove, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, uint32 exceptSpellId=0, bool withEffectMechanics=false)
Definition Unit.cpp:4100
void InterruptMovementBasedAuras()
Definition Unit.cpp:590
virtual bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7751
int32 GetHighestExclusiveSameEffectSpellGroupValue(AuraEffect const *aurEff, AuraType auraType, bool checkMiscValue=false, int32 miscValue=0) const
Definition Unit.cpp:13724
bool IsThreatened() const
Definition Unit.cpp:8302
bool SetSwim(bool enable)
Definition Unit.cpp:13330
uint32 GetWeaponSkillValue(WeaponAttackType attType, Unit const *target=nullptr) const
Definition Unit.cpp:2809
void SetEmoteState(Emote emote)
Definition Unit.h:981
Aura * GetOwnedAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, Aura *except=nullptr) const
Definition Unit.cpp:3645
virtual bool UpdatePosition(float x, float y, float z, float ang, bool teleport=false)
Definition Unit.cpp:12866
DynObjectList m_dynObj
Definition Unit.h:1873
int32 GetHealthGain(int32 dVal)
Definition Unit.cpp:8353
int32 GetMaxPositiveAuraModifierByMiscMask(AuraType auraType, uint32 misc_mask, AuraEffect const *except=nullptr) const
Definition Unit.cpp:4855
PositionUpdateInfo _positionUpdateInfo
Definition Unit.h:1996
void SetPvpFlag(UnitPVPStateFlags flags)
Definition Unit.h:997
bool SetCanFly(bool enable, bool packetOnly=false)
Definition Unit.cpp:13349
AuraApplicationList m_interruptableAuras
Definition Unit.h:1891
float GetTotalAuraMultiplierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:4885
uint32 GetDisplayId() const
Definition Unit.h:1598
uint32 GetVirtualItemId(uint32 slot) const
Definition Unit.cpp:13831
static float CalculateAverageResistReduction(WorldObject const *caster, SpellSchoolMask schoolMask, Unit const *victim, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:1737
int8 m_comboPoints
Definition Unit.h:1980
void ModifyAuraState(AuraStateType flag, bool apply)
Definition Unit.cpp:5691
bool IsAIEnabled() const
Definition Unit.h:812
uint32 GetAuraCount(uint32 spellId) const
Definition Unit.cpp:4542
UnitAI * GetTopAI() const
Definition Unit.h:820
void HandleProcExtraAttackFor(Unit *victim, uint32 count)
Definition Unit.cpp:2141
bool isPossessing() const
Definition Unit.cpp:6230
uint32 GetNativeDisplayId() const
Definition Unit.h:1600
void RemoveAllGroupBuffsFromCaster(ObjectGuid casterGUID)
Definition Unit.cpp:4337
virtual void UpdateArmor()=0
bool HealthBelowPct(int32 pct) const
Definition Unit.h:931
void UpdateCharmAI()
Definition Unit.cpp:9663
void ClearAllReactives()
Definition Unit.cpp:10510
void ApplyControlStatesIfNeeded()
Definition Unit.cpp:11310
void SetRooted(bool apply)
Definition Unit.cpp:11357
void AddUnitMovementFlag(uint32 f)
Definition Unit.h:1692
ThreatManager m_threatManager
Definition Unit.h:1968
uint32 _oldFactionId
faction before charm
Definition Unit.h:1991
bool Attack(Unit *victim, bool meleeAttack)
Definition Unit.cpp:5477
bool IsHovering() const
Definition Unit.h:1233
float GetTotalAuraMultiplierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4925
float MeleeSpellMissChance(Unit const *victim, WeaponAttackType attType, int32 skillDiff, uint32 spellId) const override
Definition Unit.cpp:12073
void UpdateAuraForGroup(uint8 slot)
Definition Unit.cpp:10722
bool HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster=ObjectGuid::Empty) const
Definition Unit.cpp:4528
bool PopAI()
Definition Unit.cpp:9512
ObjectGuid GetMinionGUID() const
Definition Unit.h:1258
bool isPossessed() const
Definition Unit.h:1295
bool HasUnitMovementFlag(uint32 f) const
Definition Unit.h:1694
static void ProcSkillsAndAuras(Unit *actor, Unit *actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition Unit.cpp:5218
bool HasNegativeAuraWithInterruptFlag(uint32 flag, ObjectGuid guid=ObjectGuid::Empty) const
Definition Unit.cpp:4613
Unit * m_charmed
Definition Unit.h:1906
AuraApplication * _CreateAuraApplication(Aura *aura, uint8 effMask)
Definition Unit.cpp:3337
uint32 GetMaxPower(Powers power) const
Definition Unit.h:950
virtual void UpdateMaxPower(Powers power)=0
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed=true, bool withInstant=true, SpellCastResult result=SPELL_FAILED_INTERRUPTED, Optional< SpellCastResult > resultOther={})
Definition Unit.cpp:3044
void _AddAura(UnitAura *aura, Unit *caster)
Definition Unit.cpp:3298
AttackerSet m_attackers
Definition Unit.h:1865
bool IsSummon() const
Definition Unit.h:896
bool IsInWater() const
Definition Unit.cpp:3185
uint32 GetHealth() const
Definition Unit.h:927
TransportBase * GetDirectTransport() const
Returns the transport this unit is on directly (if on vehicle and transport, return vehicle)
Definition Unit.cpp:11837
uint32 GetFaction() const override
Definition Unit.h:987
virtual void TextEmote(std::string_view text, WorldObject const *target=nullptr, bool isBossEmote=false)
Definition Unit.cpp:13815
void RemoveDynObject(uint32 spellId)
Definition Unit.cpp:5077
Unit * m_attacking
Definition Unit.h:1866
void SetPower(Powers power, uint32 val, bool withPowerUpdate=true, bool force=false)
Definition Unit.cpp:9398
bool HasAuraState(AuraStateType flag, SpellInfo const *spellProto=nullptr, Unit const *Caster=nullptr) const
Definition Unit.cpp:5757
void GetDispellableAuraList(WorldObject const *caster, uint32 dispelMask, DispelChargesList &dispelList, bool isReflect=false) const
Definition Unit.cpp:4486
AttackerSet const & getAttackers() const
Definition Unit.h:871
float m_weaponDamage[MAX_ATTACK][2][2]
Definition Unit.h:1898
void RemovePvpFlag(UnitPVPStateFlags flags)
Definition Unit.h:998
void SetAI(UnitAI *newAI)
Definition Unit.cpp:9506
AuraEffect * GetAuraEffectOfRankedSpell(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition Unit.cpp:4396
void SendPlaySpellVisualKit(uint32 id, uint32 type) const
Definition Unit.cpp:11990
std::multimap< uint32, Aura * > AuraMap
Definition Unit.h:790
virtual uint32 GetShieldBlockValue() const =0
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3823
bool IsVisible() const
Definition Unit.cpp:8448
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4565
void RemoveOwnedAuras(std::function< bool(Aura const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3747
bool isMoving() const
Definition Unit.h:1775
bool SetWalk(bool enable)
Definition Unit.cpp:13244
float GetUnitBlockChance(WeaponAttackType attType, Unit const *victim) const
Definition Unit.cpp:2694
void SendPetActionSound(PetAction action) const
Definition Unit.cpp:10245
void EngageWithTarget(Unit *who)
Definition Unit.cpp:8232
void NearTeleportTo(Position const &pos, bool casting=false)
Definition Unit.cpp:12803
void PurgeAndApplyPendingMovementChanges(bool informObservers=true)
Definition Unit.cpp:12981
void CalculateMeleeDamage(Unit *victim, CalcDamageInfo *damageInfo, WeaponAttackType attackType=BASE_ATTACK)
Definition Unit.cpp:1145
SpellMissInfo MeleeSpellHitResult(Unit *victim, SpellInfo const *spellInfo) const override
Definition Unit.cpp:2421
void setAttackTimer(WeaponAttackType type, uint32 time)
Definition Unit.h:846
virtual bool UpdateStats(Stats stat)=0
void RemoveAllDynObjects()
Definition Unit.cpp:5094
bool HasNpcFlag(NPCFlags flags) const
Definition Unit.h:1110
void GetAllMinionsByEntry(std::list< TempSummon * > &Minions, uint32 entry)
Definition Unit.cpp:6004
uint32 GetArmor() const
Definition Unit.h:919
static void ApplyResilience(Unit const *victim, float *crit, int32 *damage, bool isCrit, CombatRating type)
Definition Unit.cpp:12003
float m_modMeleeHitChance
Definition Unit.h:1510
virtual bool CheckAttackFitToAuraRequirement(WeaponAttackType, AuraEffect const *) const
Definition Unit.h:1534
void RemoveArenaAuras()
Definition Unit.cpp:4227
void _RemoveAllAuraStatMods()
Definition Unit.cpp:4370
void SetPhaseMask(uint32 newPhaseMask, bool update) override
Definition Unit.cpp:12123
uint32 GetAttackTime(WeaponAttackType att) const
Definition Unit.cpp:8411
ObjectGuid GetCritterGUID() const
Definition Unit.h:1262
uint8 GetLevelForTarget(WorldObject const *) const override
Definition Unit.h:904
int32 GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:4815
void RemoveAurasDueToSpellBySteal(uint32 spellId, ObjectGuid casterGUID, WorldObject *stealer)
Definition Unit.cpp:3868
AuraApplication * GetAuraApplicationOfRankedSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraApplication *except=nullptr) const
Definition Unit.cpp:4468
void SetFullPower(Powers power)
Definition Unit.h:955
void StopAttackFaction(uint32 faction_id)
Definition Unit.cpp:13050
bool HasScheduledAIChange() const
Definition Unit.cpp:9561
uint32 GetCastingTimeForBonus(SpellInfo const *spellProto, DamageEffectType damagetype, uint32 CastingTime) const
Definition Unit.cpp:10630
void RemoveAreaAurasDueToLeaveWorld()
Definition Unit.cpp:4147
float GetAPMultiplier(WeaponAttackType attType, bool normalized) const
Definition Unit.cpp:10782
bool IsRooted() const
Definition Unit.h:1182
bool CanModifyStats() const
Definition Unit.h:1547
void BuildMovementPacket(ByteBuffer *data) const
Definition Unit.cpp:12740
float GetUnitCriticalChanceDone(WeaponAttackType attackType) const
Definition Unit.cpp:2732
void RemoveCharmedBy(Unit *charmer)
Definition Unit.cpp:11637
bool CreateVehicleKit(uint32 id, uint32 creatureEntry)
Definition Unit.cpp:11767
bool IsMounted() const
Definition Unit.h:1027
void _ApplyAura(AuraApplication *aurApp, uint8 effMask)
Definition Unit.cpp:3393
float GetSpeedRate(UnitMoveType mtype) const
Definition Unit.h:1670
virtual void SetDisplayId(uint32 modelId)
Definition Unit.cpp:10383
bool ApplyDiminishingToDuration(SpellInfo const *auraSpellInfo, bool triggered, int32 &duration, WorldObject *caster, DiminishingLevels previousLevel) const
Definition Unit.cpp:8798
std::set< Unit * > AttackerSet
Definition Unit.h:786
virtual void SetTarget(ObjectGuid const &)=0
void RemoveAppliedAuras(std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3734
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3807
void CleanupBeforeRemoveFromMap(bool finalCleanup)
Definition Unit.cpp:9627
void SetPowerType(Powers power, bool sendUpdate=true)
Definition Unit.cpp:5350
bool IsGuardian() const
Definition Unit.h:897
Unit * GetVictim() const
Definition Unit.h:873
void UpdatePetCombatState()
Definition Unit.cpp:8754
std::vector< Unit * > UnitVector
Definition Unit.h:788
bool IsMovedByServer() const
Definition Unit.h:1314
uint32 GetExtraUnitMovementFlags() const
Definition Unit.h:1701
int32 SpellBaseHealingBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:7546
void UpdateOrientation(float orientation)
Only server-side orientation update, does not broadcast to client.
Definition Unit.cpp:12909
uint32 GetMeleeCritDamageReduction(uint32 damage) const
Definition Unit.h:1072
bool IsUnderWater() const
Definition Unit.cpp:3190
void SetSpeedRate(UnitMoveType mtype, float rate)
Definition Unit.cpp:8618
void AddExtraAttacks(uint32 count)
Definition Unit.cpp:2150
void RemovePlayerFromVision(Player *player)
Definition Unit.cpp:6309
void SendFlightSplineSyncUpdate()
Definition Unit.cpp:579
void EnergizeBySpell(Unit *victim, uint32 spellId, int32 damage, Powers powerType)
Definition Unit.cpp:6380
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
Definition Unit.cpp:7579
float GetCreateStat(Stats stat) const
Definition Unit.h:1469
bool IsHighestExclusiveAura(Aura const *aura, bool removeOtherAuraApplications=false)
Definition Unit.cpp:13748
void GetProcAurasTriggeredOnEvent(AuraApplicationProcContainer &aurasTriggeringProc, AuraApplicationList *procAuras, ProcEventInfo &eventInfo)
Definition Unit.cpp:10135
void UpdateSplinePosition()
Definition Unit.cpp:555
void SetOwnerGUID(ObjectGuid owner)
Definition Unit.cpp:5782
DeathState getDeathState() const
Definition Unit.h:1251
Unit * GetFirstControlled() const
Definition Unit.cpp:6179
float GetTotalAuraMultiplierByMiscMask(AuraType auraType, uint32 misc_mask) const
Definition Unit.cpp:4845
void AddComboPoints(Unit *target, int8 count)
Definition Unit.cpp:10437
ObjectGuid GetTransGUID() const override
Definition Unit.cpp:11827
bool m_aiLocked
Definition Unit.h:1975
void ApplyCastTimePercentMod(float val, bool apply)
Definition Unit.cpp:10618
int32 GetMaxPositiveAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4935
std::vector< DynamicObject * > GetDynObjects(uint32 spellId) const
Definition Unit.cpp:5067
bool IsCritter() const
Definition Unit.h:1131
void DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
Definition Unit.cpp:1444
float GetAttackPowerModifierValue(AttackPowerModIndex index, AttackPowerModType modifierType) const
Definition Unit.cpp:9115
int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, ObjectGuid const &casterGuid) const
Definition Unit.cpp:12062
void UpdateResistanceBuffModsMod(SpellSchools school)
Definition Unit.cpp:4955
bool HasUnitState(const uint32 f) const
Definition Unit.h:890
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply)
Definition Unit.cpp:8082
uint32 GetSpellDamageReduction(uint32 damage) const
Definition Unit.h:1079
bool IsMagnet() const
Definition Unit.cpp:6152
void FinishSpell(CurrentSpellTypes spellType, bool ok=true)
Definition Unit.cpp:3074
std::unordered_set< AbstractFollower * > m_followingMe
Definition Unit.h:1977
virtual void Update(uint32 time) override
Definition Unit.cpp:440
bool IsInRaidWith(Unit const *unit) const
Definition Unit.cpp:11863
void UnsummonAllTotems()
Definition Unit.cpp:6332
GameObjectList m_gameObj
Definition Unit.h:1877
AuraMap m_ownedAuras
Definition Unit.h:1883
void ProcessPositionDataChanged(PositionFullTerrainStatus const &data) override
Definition Unit.cpp:3195
Unit(bool isWorldObject)
Definition Unit.cpp:303
bool IsInFeralForm() const
Definition Unit.cpp:8909
DynamicObject * GetDynObject(uint32 spellId) const
Definition Unit.cpp:5061
void SetLevel(uint8 lvl, bool sendUpdate=true)
Definition Unit.cpp:9321
static uint32 SpellCriticalDamageBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition Unit.cpp:7197
std::pair< AuraMap::iterator, AuraMap::iterator > AuraMapBoundsNonConst
Definition Unit.h:792
void RemoveUnitMovementFlag(uint32 f)
Definition Unit.h:1693
void RemoveBindSightAuras()
Definition Unit.cpp:6319
AuraApplicationMap m_appliedAuras
Definition Unit.h:1884
void HandleEmoteCommand(Emote emoteId)
Definition Unit.cpp:1579
CharmInfo * InitCharmInfo()
Definition Unit.cpp:9707
void RemoveAllAttackers()
Definition Unit.cpp:5678
void SetClass(uint8 classId)
Definition Unit.h:910
void SetFacingTo(float ori, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13226
virtual bool CanSwim() const
Definition Unit.cpp:12789
virtual float GetNativeObjectScale() const
Definition Unit.h:1596
uint32 GetDoTsByCaster(ObjectGuid casterGUID) const
Definition Unit.cpp:4706
void RemoveFromWorld() override
Definition Unit.cpp:9578
bool IsHighestExclusiveAuraEffect(SpellInfo const *spellInfo, AuraType auraType, int32 effectAmount, uint8 auraEffectMask, bool removeOtherAuraApplications=false)
Definition Unit.cpp:13758
void SetVisibleAura(uint8 slot, AuraApplication *aurApp)
Definition Unit.cpp:656
void AttackerStateUpdate(Unit *victim, WeaponAttackType attType=BASE_ATTACK, bool extra=false)
Definition Unit.cpp:2090
Player * GetCharmerOrSelfPlayer() const
Definition Unit.h:1309
void ScheduleAIChange()
Definition Unit.cpp:9532
virtual void UpdateMaxHealth()=0
uint32 HasUnitTypeMask(uint32 mask) const
Definition Unit.h:894
float GetFlatModifierValue(UnitMods unitMod, UnitModifierFlatType modifierType) const
Definition Unit.cpp:9029
void _RegisterAuraEffect(AuraEffect *aurEff, bool apply)
Definition Unit.cpp:3575
void SendPeriodicAuraLog(SpellPeriodicAuraLogInfo *pInfo)
Definition Unit.cpp:5231
void ClearInCombat()
Definition Unit.h:1161
void _EnterVehicle(Vehicle *vehicle, int8 seatId, AuraApplication const *aurApp=nullptr)
Definition Unit.cpp:12547
float GetMeleeRange(Unit const *target) const
Definition Unit.cpp:642
void SetStandState(UnitStandStateType state)
Definition Unit.cpp:10340
bool isDying() const
Definition Unit.h:1248
float GetStat(Stats stat) const
Definition Unit.h:917
virtual void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float &minDamage, float &maxDamage, uint8 damageIndex) const =0
int32 GetTotalAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:4875
void RemoveAllAuras()
Definition Unit.cpp:4180
SpellHistory * GetSpellHistory()
Definition Unit.h:1497
void IncrDiminishing(SpellInfo const *auraSpellInfo, bool triggered)
Definition Unit.cpp:8787
float m_modAttackSpeedPct[MAX_ATTACK]
Definition Unit.h:1515
bool IsControlledByPlayer() const
Definition Unit.h:1271
Unit * m_charmer
Definition Unit.h:1905
void RestoreDisplayId()
Definition Unit.cpp:10391
DiminishingLevels GetDiminishing(DiminishingGroup group) const
Definition Unit.cpp:8774
bool m_canDualWield
Definition Unit.h:862
ObjectGuid GetCharmerGUID() const
Definition Unit.h:1265
Minion * GetFirstMinion() const
Definition Unit.cpp:5820
UnitStandStateType GetStandState() const
Definition Unit.h:1015
float SpellHealingPctDone(Unit *victim, SpellInfo const *spellProto) const
Definition Unit.cpp:7418
UnitAI * GetScheduledChangeAI()
Definition Unit.cpp:9553
bool HasAuraTypeWithValue(AuraType auraType, int32 value) const
Definition Unit.cpp:4596
bool HasBreakableByDamageAuraType(AuraType type, uint32 excludeAura=0) const
Definition Unit.cpp:691
bool SetCharmedBy(Unit *charmer, CharmType type, AuraApplication const *aurApp=nullptr)
Definition Unit.cpp:11460
bool IsAlwaysVisibleFor(WorldObject const *seer) const override
Definition Unit.cpp:8417
void SetPetGUID(ObjectGuid guid)
Definition Unit.h:1261
AuraEffect * GetDummyAuraEffect(SpellFamilyNames name, uint32 iconId, uint8 effIndex) const
Definition Unit.cpp:4438
bool SetWaterWalking(bool enable)
Definition Unit.cpp:13397
bool HasStrongerAuraWithDR(SpellInfo const *auraSpellInfo, Unit *caster, bool triggered) const
Definition Unit.cpp:4642
virtual void setDeathState(DeathState s)
Definition Unit.cpp:8668
void SetMaxHealth(uint32 val)
Definition Unit.cpp:9370
void SetCreatorGUID(ObjectGuid creator)
Definition Unit.h:1257
void GetPartyMembers(std::list< Unit * > &units)
Definition Unit.cpp:11882
virtual void AtEngage(Unit *target)
Definition Unit.cpp:8725
static void Kill(Unit *attacker, Unit *victim, bool durabilityLoss=true)
Definition Unit.cpp:10901
ObjectGuid LastCharmerGUID
Definition Unit.h:1748
uint32 GetPower(Powers power) const
Definition Unit.h:948
uint32 m_interruptMask
Definition Unit.h:1893
uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const
Definition Unit.cpp:12204
void CombatStop(bool includingCast=false, bool mutualPvP=true)
Definition Unit.cpp:5633
float GetUnitDodgeChance(WeaponAttackType attType, Unit const *victim) const
Definition Unit.cpp:2595
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:1587
int32 GetMaxNegativeAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4945
void HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
Definition Unit.cpp:8963
CombatManager & GetCombatManager()
Definition Unit.h:1144
uint32 GetMeleeDamageReduction(uint32 damage) const
Definition Unit.h:1077
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:968
MeleeHitOutcome RollMeleeOutcomeAgainst(Unit const *victim, WeaponAttackType attType) const
Definition Unit.cpp:2165
uint32 GetCreatureTypeMask() const
Definition Unit.cpp:8898
bool InitTamedPet(Pet *pet, uint8 level, uint32 spell_id)
Definition Unit.cpp:10871
bool HasAuraTypeWithTriggerSpell(AuraType auratype, uint32 triggerSpell) const
Definition Unit.cpp:4605
bool HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4587
void SetCritterGUID(ObjectGuid guid)
Definition Unit.h:1263
AuraApplicationMap & GetAppliedAuras()
Definition Unit.h:1351
std::list< AuraEffect * > AuraEffectList
Definition Unit.h:801
void RemoveMovementImpairingAuras(bool withRoot)
Definition Unit.cpp:4092
bool isAttackReady(WeaponAttackType type=BASE_ATTACK) const
Definition Unit.h:849
void InitStatBuffMods()
Definition Unit.cpp:4984
int32 m_procDeep
Definition Unit.h:1870
int32 GetTotalAuraModifierByAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4915
void ClearDiminishings()
Definition Unit.cpp:8874
void SetPetNumberForClient(uint32 petNumber)
Definition Unit.h:1303
virtual void ProcessTerrainStatusUpdate(ZLiquidStatus oldLiquidStatus, Optional< LiquidData > const &newLiquidData)
Definition Unit.cpp:3202
VisibleAuraMap m_visibleAuras
Definition Unit.h:1901
uint32 GetCreateMana() const
Definition Unit.h:1465
std::vector< GameObject * > GetGameObjects(uint32 spellId) const
Definition Unit.cpp:5106
bool IsServiceProvider() const
Definition Unit.cpp:8223
bool IsTotem() const
Definition Unit.h:900
CombatManager m_combatManager
Definition Unit.h:1966
void ChangeSeat(int8 seatId, bool next=true)
Definition Unit.cpp:12600
void SetInFront(WorldObject const *target)
Definition Unit.cpp:13220
void ApplyDiminishingAura(DiminishingGroup group, bool apply)
Definition Unit.cpp:8857
AuraStateAurasMap m_auraStateAuras
Definition Unit.h:1892
int32 GetResistance(SpellSchools school) const
Definition Unit.h:922
float m_speed_rate[MAX_MOVE_TYPE]
Definition Unit.h:1903
AuraList & GetSingleCastAuras()
Definition Unit.h:1399
bool IsAlwaysDetectableFor(WorldObject const *seer) const override
Definition Unit.cpp:8437
uint32 GetMovementCounterAndInc()
Definition Unit.h:1788
void SetModCastingSpeed(float castingSpeed)
Definition Unit.h:964
Vehicle * GetVehicleKit() const
Definition Unit.h:1751
void PushAI(UnitAI *newAI)
Definition Unit.cpp:9501
float m_modSpellHitChance
Definition Unit.h:1512
void ValidateAttackersAndOwnTarget()
Definition Unit.cpp:5615
Guardian * GetGuardianPet() const
Definition Unit.cpp:5836
void resetAttackTimer(WeaponAttackType type=BASE_ATTACK)
Definition Unit.cpp:606
virtual void Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const *target)
Definition Unit.cpp:13797
virtual bool IsEngaged() const
Definition Unit.h:1140
uint32 MeleeDamageBonusDone(Unit *pVictim, uint32 damage, WeaponAttackType attType, SpellInfo const *spellProto=nullptr, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL)
Definition Unit.cpp:7811
AuraEffectList m_modAuras[TOTAL_AURAS]
Definition Unit.h:1889
void _ApplyAuraEffect(Aura *aura, uint8 effIndex)
Definition Unit.cpp:3379
void DeMorph()
Definition Unit.cpp:3231
void RemoveAllMinionsByEntry(uint32 entry)
Definition Unit.cpp:6014
void SendPetActionFeedback(PetActionFeedback msg, uint32 spellId) const
-------—Pet responses methods--------------—
Definition Unit.cpp:10233
AuraMap & GetOwnedAuras()
Definition Unit.h:1341
void UpdateAllDamagePctDoneMods()
Definition Unit.cpp:9200
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:6927
virtual void Whisper(std::string_view text, Language language, Player *target, bool isBossWhisper=false)
Definition Unit.cpp:13820
bool IsFalling() const
Definition Unit.cpp:12784
bool AttackStop()
Definition Unit.cpp:5587
void KnockbackFrom(float x, float y, float speedXY, float speedZ)
Definition Unit.cpp:12175
int32 GetCurrentSpellCastTime(uint32 spell_id) const
Definition Unit.cpp:3139
void RemoveAurasOnEvade()
Definition Unit.cpp:4241
void SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
Definition Unit.cpp:9011
void SetShapeshiftForm(ShapeshiftForm form)
Definition Unit.cpp:8904
float GetUnitCriticalChanceAgainst(WeaponAttackType attackType, Unit const *victim) const
Definition Unit.cpp:2803
bool IsInPartyWith(Unit const *unit) const
Definition Unit.cpp:11844
ObjectGuid m_SummonSlot[MAX_SUMMON_SLOT]
Definition Unit.h:1500
uint32 GetCreatePowerValue(Powers power) const
Definition Unit.cpp:9464
bool m_cleanupDone
Definition Unit.h:1987
static void DealDamageMods(Unit const *victim, uint32 &damage, uint32 *absorb)
Definition Unit.cpp:714
SharedVisionList m_sharedVision
Definition Unit.h:1908
void SendMeleeAttackStop(Unit const *victim=nullptr) const
Definition Unit.cpp:2361
ObjectGuid GetTarget() const
Definition Unit.h:1813
bool _isWalkingBeforeCharm
Are we walking before we were charmed?
Definition Unit.h:1992
uint8 GetLevel() const
Definition Unit.h:903
void SetMountDisplayId(uint32 mountDisplayId)
Definition Unit.h:1029
uint8 GetRace() const
Definition Unit.h:906
void RemoveCharmAuras()
Definition Unit.cpp:6324
bool IsInCombat() const
Definition Unit.h:1158
bool IsWalking() const
Definition Unit.h:1232
bool IsSitState() const
Definition Unit.cpp:10325
float GetTotalAttackPowerValue(WeaponAttackType attType) const
Definition Unit.cpp:9289
uint32 GetModelForForm(ShapeshiftForm form, uint32 spellId) const
Definition Unit.cpp:12210
void RemoveUnitFlag(UnitFlags flags)
Definition Unit.h:969
void MonsterMoveWithSpeed(float x, float y, float z, float speed, bool generatePath=false, bool forceDestination=false)
Definition Unit.cpp:526
uint32 GetDamageImmunityMask() const
Definition Unit.cpp:7731
bool HasPendingMovementChange() const
Definition Unit.h:1792
Player * GetControllingPlayer() const
Definition Unit.cpp:5807
float GetWeaponProcChance() const
Definition Unit.cpp:8099
Aura * _TryStackingOrRefreshingExistingAura(AuraCreateInfo &createInfo)
Definition Unit.cpp:3236
ObjectGuid GetPetGUID() const
Definition Unit.h:1260
uint32 SpellDamageBonusTaken(Unit *caster, SpellInfo const *spellProto, uint32 pdamage, DamageEffectType damagetype) const
Definition Unit.cpp:6850
void RemoveAurasWithAttribute(SpellAttr0 flags)
Definition Unit.cpp:3986
uint32 m_lastManaUse
Definition Unit.h:1960
void UpdateStatBuffMod(Stats stat)
Definition Unit.cpp:4992
virtual void ExitVehicle(Position const *exitPosition=nullptr)
Definition Unit.cpp:12632
void SendPetDismissSound() const
Definition Unit.cpp:10253
float m_auraPctModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_PCT_END]
Definition Unit.h:1896
uint32 GetMaxSkillValueForLevel(Unit const *target=nullptr) const
Definition Unit.h:1033
void CombatStopWithPets(bool includingCast=false)
Definition Unit.cpp:5652
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition Unit.h:1489
void DestroyForPlayer(Player *target, bool onDeath) const override
Definition Unit.cpp:13709
bool BuildPacket(WorldPacket *packet)
void SetBit(uint32 bit)
Definition UpdateMask.h:81
void AppendToPacket(ByteBuffer *data)
Definition UpdateMask.h:87
bool GetBit(uint32 index) const
Definition UpdateMask.h:40
Unit * GetBase() const
May be called from scripts.
Definition Vehicle.h:45
VehicleEntry const * GetVehicleInfo() const
Definition Vehicle.h:46
Vehicle * RemovePassenger(Unit *passenger)
Removes the passenger from the vehicle.
Definition Vehicle.cpp:497
bool AddPassenger(Unit *passenger, int8 seatId=-1)
Attempts to add a passenger to the vehicle on 'seatId'.
Definition Vehicle.cpp:426
uint32 GetCreatureEntry() const
Definition Vehicle.h:47
void Uninstall()
Removes all passengers and sets status to STATUS_UNINSTALLING. No new passengers can be added to the ...
Definition Vehicle.cpp:108
void RelocatePassengers()
Relocate passengers. Must be called after m_base::Relocate.
Definition Vehicle.cpp:554
SeatMap Seats
The collection of all seats on the vehicle. Including vacant ones.
Definition Vehicle.h:63
std::string GetDebugInfo() const
Definition Vehicle.cpp:969
SeatMap::const_iterator GetNextEmptySeat(int8 seatId, bool next) const
Gets the next empty seat based on current seat.
Definition Vehicle.cpp:319
VehicleSeatAddon const * GetSeatAddonForSeatOfPassenger(Unit const *passenger) const
Gets the vehicle seat addon data for the seat of a passenger.
Definition Vehicle.cpp:360
Milliseconds GetDespawnDelay()
Definition Vehicle.cpp:961
void InstallAllAccessories(bool evading)
Definition Vehicle.cpp:84
uint32 GetMapId() const
Definition Position.h:193
int8 GetTransSeat() const
Definition Object.h:573
virtual void SetPhaseMask(uint32 newPhaseMask, bool update)
Definition Object.cpp:3416
uint32 GetPhaseMask() const
Definition Object.h:370
bool IsWithinDist3d(float x, float y, float z, float dist) const
Definition Object.cpp:1168
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition Object.cpp:1784
Map * GetMap() const
Definition Object.h:451
ZLiquidStatus GetLiquidStatus() const
Definition Object.h:380
void UpdateAllowedPositionZ(float x, float y, float &z, float *groundZ=nullptr) const
Definition Object.cpp:1417
void AddToWorld() override
Definition Object.cpp:1061
Unit * GetCharmerOrOwner() const
Definition Object.cpp:2186
void RemoveFromWorld() override
Definition Object.cpp:1067
InstanceScript * GetInstanceScript() const
Definition Object.cpp:1088
virtual uint8 GetLevelForTarget(WorldObject const *) const
Definition Object.h:425
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
Definition Object.cpp:2621
Unit * GetCharmerOrOwnerOrSelf() const
Definition Object.cpp:2196
virtual bool IsAlwaysDetectableFor(WorldObject const *) const
Definition Object.h:629
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2833
std::string GetDebugInfo() const override
Definition Object.cpp:3613
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2857
bool IsHostileTo(WorldObject const *target) const
Definition Object.cpp:2797
Unit * GetOwner() const
Definition Object.cpp:2181
ZoneScript * GetZoneScript() const
Definition Object.h:457
uint32 GetInstanceId() const
Definition Object.h:367
void setActive(bool isActiveObject)
Definition Object.cpp:992
bool InSamePhase(uint32 phasemask) const
Definition Object.h:371
float GetFloorZ() const
Definition Object.cpp:3585
std::string const & GetName() const
Definition Object.h:384
virtual void Heartbeat()
Definition Object.h:631
virtual bool IsAlwaysVisibleFor(WorldObject const *) const
Definition Object.h:626
bool IsWithinLOSInMap(WorldObject const *obj, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition Object.cpp:1227
virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const &data)
Definition Object.cpp:1050
void GetContactPoint(WorldObject const *obj, float &x, float &y, float &z, float distance2d=CONTACT_DISTANCE) const
Definition Object.cpp:3272
Transport * GetTransport() const
Definition Object.h:566
void UpdatePositionData()
Definition Object.cpp:1043
Player * GetSpellModOwner() const
Definition Object.cpp:2224
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition Object.cpp:2204
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:1193
void SetIsStoredInWorldObjectGridContainer(bool apply)
Definition Object.cpp:973
void AddToNotify(uint16 f)
Definition Object.h:548
EventProcessor m_Events
Definition Object.h:593
float GetVisibilityRange() const
Definition Object.cpp:1493
SpellMissInfo SpellHitResult(Unit *victim, SpellInfo const *spellInfo, bool canReflect=false) const
Definition Object.cpp:2572
float GetDistance(WorldObject const *obj) const
Definition Object.cpp:1124
uint32 GetZoneId() const
Definition Object.h:375
MovementInfo m_movementInfo
Definition Object.h:577
FlaggedValuesArray32< int32, uint32, ServerSideVisibilityType, TOTAL_SERVERSIDE_VISIBILITY_TYPES > m_serverSideVisibility
Definition Object.h:446
bool IsFriendlyTo(WorldObject const *target) const
Definition Object.cpp:2802
bool IsInMap(WorldObject const *obj) const
Definition Object.cpp:1161
virtual void Update(uint32 diff)
Definition Object.cpp:961
FactionTemplateEntry const * GetFactionTemplateEntry() const
Definition Object.cpp:2635
int32 CalculateSpellDamage(SpellEffectInfo const &spellEffectInfo, int32 const *basePoints=nullptr) const
Definition Object.cpp:2249
virtual void UpdateObjectVisibility(bool forced=true)
Definition Object.cpp:3481
virtual void CleanupsBeforeDelete(bool finalCleanup=true)
Definition Object.cpp:1032
void Initialize(uint16 opcode, size_t newres=200)
Definition WorldPacket.h:51
void Initialize(ChatMsg chatType, Language language, WorldObject const *sender, WorldObject const *receiver, std::string_view message, uint32 achievementId=0, std::string_view channelName="", LocaleConstant locale=DEFAULT_LOCALE, std::string_view addonPrefix="")
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
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
WorldPacket const * Write() override
WorldPacket const * Write() override
TaggedPosition< Position::XYZ > ModelPosition
Definition PetPackets.h:130
WorldPacket const * Write() override
void SendPacket(WorldPacket const *packet)
Send a packet to the client.
LocaleConstant GetSessionDbLocaleIndex() const
void KickPlayer(std::string const &reason)
Kick a player out of the World.
Definition Util.h:412
Opcodes
Definition Opcodes.h:29
@ SMSG_PET_UPDATE_COMBO_POINTS
Definition Opcodes.h:1199
@ SMSG_SPELLENERGIZELOG
Definition Opcodes.h:366
@ SMSG_MOVE_LAND_WALK
Definition Opcodes.h:252
@ SMSG_SPLINE_MOVE_STOP_SWIM
Definition Opcodes.h:809
@ SMSG_PARTYKILLLOG
Definition Opcodes.h:530
@ MSG_MOVE_HOVER
Definition Opcodes.h:276
@ SMSG_MOVE_FEATHER_FALL
Definition Opcodes.h:271
@ SMSG_MOVE_SET_HOVER
Definition Opcodes.h:273
@ SMSG_SPLINE_MOVE_LAND_WALK
Definition Opcodes.h:807
@ SMSG_SPLINE_MOVE_START_SWIM
Definition Opcodes.h:808
@ SMSG_SPLINE_MOVE_SET_RUN_MODE
Definition Opcodes.h:810
@ MSG_MOVE_ROOT
Definition Opcodes.h:265
@ SMSG_MOVE_WATER_WALK
Definition Opcodes.h:251
@ SMSG_SPLINE_MOVE_GRAVITY_DISABLE
Definition Opcodes.h:1264
@ SMSG_SPELLORDAMAGE_IMMUNE
Definition Opcodes.h:640
@ SMSG_FORCE_MOVE_UNROOT
Definition Opcodes.h:263
@ MSG_MOVE_UPDATE_CAN_FLY
Definition Opcodes.h:970
@ SMSG_MOVE_KNOCK_BACK
Definition Opcodes.h:268
@ SMSG_PROCRESIST
Definition Opcodes.h:637
@ SMSG_BREAK_TARGET
Definition Opcodes.h:367
@ MSG_MOVE_WATER_WALK
Definition Opcodes.h:718
@ SMSG_MOVE_GRAVITY_DISABLE
Definition Opcodes.h:1259
@ SMSG_LOOT_LIST
Definition Opcodes.h:1046
@ SMSG_FORCE_MOVE_ROOT
Definition Opcodes.h:261
@ SMSG_MOVE_GRAVITY_ENABLE
Definition Opcodes.h:1261
@ SMSG_PLAYER_VEHICLE_DATA
Definition Opcodes.h:1220
@ SMSG_MOVE_NORMAL_FALL
Definition Opcodes.h:272
@ SMSG_SPLINE_MOVE_SET_HOVER
Definition Opcodes.h:804
@ SMSG_UPDATE_COMBO_POINTS
Definition Opcodes.h:954
@ SMSG_SPLINE_MOVE_SET_FLYING
Definition Opcodes.h:1087
@ SMSG_SPELLDAMAGESHIELD
Definition Opcodes.h:620
@ SMSG_SPLINE_MOVE_UNSET_HOVER
Definition Opcodes.h:805
@ SMSG_SPLINE_MOVE_UNROOT
Definition Opcodes.h:801
@ MSG_MOVE_FEATHER_FALL
Definition Opcodes.h:717
@ SMSG_SPLINE_MOVE_NORMAL_FALL
Definition Opcodes.h:803
@ SMSG_MOVE_UNSET_HOVER
Definition Opcodes.h:274
@ SMSG_DISMOUNT
Definition Opcodes.h:969
@ SMSG_MOVE_SET_CAN_FLY
Definition Opcodes.h:864
@ SMSG_SPELLHEALLOG
Definition Opcodes.h:365
@ SMSG_SPLINE_MOVE_FEATHER_FALL
Definition Opcodes.h:802
@ SMSG_SPLINE_MOVE_ROOT
Definition Opcodes.h:823
@ SMSG_SPLINE_MOVE_SET_WALK_MODE
Definition Opcodes.h:811
@ SMSG_SPLINE_MOVE_GRAVITY_ENABLE
Definition Opcodes.h:1265
@ SMSG_SPLINE_MOVE_UNSET_FLYING
Definition Opcodes.h:1088
@ SMSG_MOVE_UNSET_CAN_FLY
Definition Opcodes.h:865
@ MSG_MOVE_UNROOT
Definition Opcodes.h:266
@ MSG_MOVE_GRAVITY_CHNG
Definition Opcodes.h:1263
@ SMSG_POWER_UPDATE
Definition Opcodes.h:1181
@ SMSG_PERIODICAURALOG
Definition Opcodes.h:619
@ SMSG_SPLINE_MOVE_WATER_WALK
Definition Opcodes.h:806
#define sWorld
Definition World.h:901
@ CONFIG_PENDING_MOVE_CHANGES_TIMEOUT
Definition World.h:404
@ CONFIG_CREATURE_FAMILY_FLEE_DELAY
Definition World.h:290
@ RATE_POWER_RAGE_INCOME
Definition World.h:413
@ RATE_DURABILITY_LOSS_DAMAGE
Definition World.h:468
@ RATE_DURABILITY_LOSS_ON_DEATH
Definition World.h:467
@ CONFIG_LISTEN_RANGE_YELL
Definition World.h:192
@ CONFIG_LISTEN_RANGE_SAY
Definition World.h:190
@ CONFIG_LISTEN_RANGE_TEXTEMOTE
Definition World.h:191
@ CONFIG_DURABILITY_LOSS_IN_PVP
Definition World.h:91
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP
Definition World.h:98
TimePoint Now()
Current chrono steady_clock time point.
Definition GameTime.cpp:57
time_t GetGameTime()
Definition GameTime.cpp:42
uint32 GetGameTimeMS()
Definition GameTime.cpp:47
TC_GAME_API WorldObject * GetWorldObject(WorldObject const &, ObjectGuid const &)
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreatureOrPetOrVehicle(WorldObject const &, ObjectGuid const &)
auto MapEqualRange(M &map, typename M::key_type const &key)
auto SelectRandomContainerElement(C const &container) -> typename std::add_const< decltype(*std::begin(container))>::type &
Definition Containers.h:108
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition Util.cpp:56
bool IsValidMapCoord(float c)
ObjectGuid CasterGUID
int32 const * BaseAmount
ObjectGuid CastItemGUID
AuraCreateInfo & SetBaseAmount(int32 const *bp)
AuraCreateInfo & SetCaster(Unit *caster)
uint8 GetAuraEffectMask() const
AuraCreateInfo & SetCasterGUID(ObjectGuid const &guid)
SpellInfo const * GetSpellInfo() const
std::string const & GetText(LocaleConstant locale=DEFAULT_LOCALE, uint8 gender=GENDER_MALE, bool forceGender=false) const
Definition ObjectMgr.h:490
WeaponAttackType AttackType
Definition Unit.h:570
uint32 DamageSchoolMask
Definition Unit.h:559
uint32 ProcVictim
Definition Unit.h:572
struct CalcDamageInfo::@227 Damages[2]
Unit * Target
Definition Unit.h:555
uint32 TargetState
Definition Unit.h:567
uint32 ProcAttacker
Definition Unit.h:571
MeleeHitOutcome HitOutCome
Definition Unit.h:574
Unit * Attacker
Definition Unit.h:554
uint32 Damage
Definition Unit.h:560
uint32 Blocked
Definition Unit.h:565
uint32 Resist
Definition Unit.h:562
uint32 CleanDamage
Definition Unit.h:573
uint32 HitInfo
Definition Unit.h:566
uint32 Absorb
Definition Unit.h:561
CastSpellExtraArgs & AddSpellBP0(int32 val)
CastSpellExtraArgs & AddSpellMod(SpellValueMod mod, int32 val)
ObjectGuid OriginalCaster
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:192
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:180
void RestoreState()
Definition Unit.cpp:9742
void SaveStayPosition()
Definition Unit.cpp:13169
CharmInfo(Unit *unit)
Definition Unit.cpp:9725
float _stayY
Definition Unit.h:750
void SetIsCommandFollow(bool val)
Definition Unit.cpp:13159
bool IsCommandAttack()
Definition Unit.cpp:13154
void LoadPetActionBar(const std::string &data)
Definition Unit.cpp:9929
void SetActionBar(uint8 index, uint32 spellOrAction, ActiveStates type)
Definition Unit.h:710
bool _isAtStay
Definition Unit.h:746
bool AddSpellToActionBar(SpellInfo const *spellInfo, ActiveStates newstate=ACT_DECIDE, uint8 preferredSlot=0)
Definition Unit.cpp:9859
void InitPossessCreateSpells()
Definition Unit.cpp:9773
void SetIsAtStay(bool val)
Definition Unit.cpp:13190
bool IsFollowing()
Definition Unit.cpp:13205
float _stayX
Definition Unit.h:749
void SetPetNumber(uint32 petnumber, bool statwindow)
Definition Unit.cpp:9920
float _stayZ
Definition Unit.h:751
bool IsReturning()
Definition Unit.cpp:13215
void SetIsFollowing(bool val)
Definition Unit.cpp:13200
void InitPetActionBar()
Definition Unit.cpp:9748
bool _isCommandFollow
Definition Unit.h:745
UnitActionBarEntry PetActionBar[MAX_UNIT_ACTION_BAR_INDEX]
Definition Unit.h:736
~CharmInfo()
Definition Unit.cpp:9740
void SetIsReturning(bool val)
Definition Unit.cpp:13210
void InitCharmCreateSpells()
Definition Unit.cpp:9809
void BuildActionBar(WorldPacket *data)
Definition Unit.cpp:9960
bool RemoveSpellFromActionBar(uint32 spell_id)
Definition Unit.cpp:9891
void SetSpellAutocast(SpellInfo const *spellInfo, bool state)
Definition Unit.cpp:9966
bool IsAtStay()
Definition Unit.cpp:13195
bool _isFollowing
Definition Unit.h:747
bool _isCommandAttack
Definition Unit.h:744
void GetStayPosition(float &x, float &y, float &z)
Definition Unit.cpp:13183
ReactStates _oldReactState
Definition Unit.h:742
void ToggleCreatureAutocast(SpellInfo const *spellInfo, bool apply)
Definition Unit.cpp:9910
bool IsCommandFollow()
Definition Unit.cpp:13164
void InitEmptyActionBar(bool withAttack=true)
Definition Unit.cpp:9763
void SetIsCommandAttack(bool val)
Definition Unit.cpp:13149
bool _isReturning
Definition Unit.h:748
Unit * _unit
Definition Unit.h:735
uint32 _petnumber
Definition Unit.h:739
CharmSpellInfo _charmspells[4]
Definition Unit.h:737
bool HasFlag(ChrRacesFlags flag) const
uint32 CreatureType
MeleeHitOutcome hitOutCome
Definition Unit.h:437
uint32 absorbed_damage
Definition Unit.h:433
WeaponAttackType attackType
Definition Unit.h:436
bool HasFlag(CreatureModelDataFlags flag) const
uint32 GetFirstVisibleModel() const
Definition Creature.cpp:153
uint32 hitCount
Definition Unit.h:403
uint32 hitTime
Definition Unit.h:402
uint16 stack
Definition Unit.h:401
bool IsFriendlyTo(FactionTemplateEntry const &entry) const
uint32 GetBlock() const
uint32 GetSubClass() const
uint32 GetDelay() const
Definition Loot.h:226
bool empty() const
Definition Loot.h:255
bool isLooted() const
Definition Loot.h:256
void clear()
Definition Loot.cpp:149
bool FillLoot(uint32 lootId, LootStore const &store, Player *lootOwner, bool personal, bool noEmptyError=false, uint16 lootMode=LOOT_MODE_DEFAULT)
Definition Loot.cpp:221
void generateMoneyLoot(uint32 minAmount, uint32 maxAmount)
Definition Loot.cpp:466
ObjectGuid guid
uint16 GetExtraMovementFlags() const
struct MovementInfo::JumpInfo jump
void RemoveMovementFlag(uint32 flag)
uint32 fallTime
struct MovementInfo::TransportInfo transport
float splineElevation
bool HasMovementFlag(uint32 flag) const
uint32 GetMovementFlags() const
void SetFallTime(uint32 val)
bool HasExtraMovementFlag(uint16 flag) const
Position pos
MovementChangeType movementChangeType
Definition Unit.h:320
Optional< LiquidData > liquidInfo
Definition MapDefines.h:113
float m_positionZ
Definition Position.h:58
float GetExactDist2d(const float x, const float y) const
Definition Position.h:109
float GetRelativeAngle(float x, float y) const
Definition Position.h:139
std::string ToString() const
Definition Position.cpp:149
float m_positionX
Definition Position.h:56
float GetPositionZ() const
Definition Position.h:81
float m_positionY
Definition Position.h:57
float GetOrientation() const
Definition Position.h:82
bool HasInArc(float arcangle, Position const *pos, float border=2.0f) const
Definition Position.cpp:120
float GetAbsoluteAngle(float x, float y) const
Definition Position.h:128
void GetSinCos(float x, float y, float &vsin, float &vcos) const
Definition Position.cpp:67
void SetOrientation(float orientation)
Definition Position.h:74
Position GetPosition() const
Definition Position.h:87
float GetPositionX() const
Definition Position.h:79
void GetPosition(float &x, float &y) const
Definition Position.h:84
float GetPositionY() const
Definition Position.h:80
void RelocateOffset(Position const &offset)
Definition Position.cpp:36
void Relocate(float x, float y)
Definition Position.h:66
Unit * attacker
Definition Unit.h:586
uint32 schoolMask
Definition Unit.h:590
uint32 cleanDamage
Definition Unit.h:598
AuraEffect const * auraEff
Definition Unit.h:607
void SetActionAndType(uint32 action, ActiveStates type)
Definition Unit.h:648
bool IsActionBarForSpell() const
Definition Unit.h:642
void SetType(ActiveStates type)
Definition Unit.h:653
void SetAction(uint32 action)
Definition Unit.h:658
uint32 GetAction() const
Definition Unit.h:641
VehicleExitParameters ExitParameter