diff options
| author | Treeston <treeston.mmoc@gmail.com> | 2018-01-03 20:04:19 +0100 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-01-03 20:04:19 +0100 | 
| commit | 532ab1c7f8653d1a2e48aa1f1f8a9ba1041d4bb7 (patch) | |
| tree | 81e2f7eb89b3144c14dd488ea6304f6d44d19848 /src/server/scripts | |
| parent | 425b181544a21d2246fdf0261ba76a37e2510883 (diff) | |
Core: Combat/threat system rewrite (PR #19930)
- PvE combat is now always mutual. UNIT_FLAG_IN_COMBAT is backed by actual references to the units we're in combat with.
- PvP combat is now also tracked, and almost always mutual; spells like Vanish and Feign Death can break this rule. That means we can easily determine a list of players we're fighting.
- By extension, IsInCombatWith now has sensible behavior when invoked on nonplayers.
- Threat and combat systems are no longer the same.
  - They still have an enforced relationship (threat implies combat - clearing combat clears threat)...
  - ...but we can have combat without threat. A creature (with threat list) isn't considered to be engaged until it has an entry on its threat list...
  - ...which means we can now faithfully replicate retail engage behavior. Combat on projectile launch - engagement start on projectile impact. Yay for progress!
- AI method refactor, as already ported in 6113b9d - `JustEngagedWith`, `JustEnteredCombat` and `JustExitedCombat`.
- Vehicle threat is now properly pooled on the main vehicle body (fixes #16542).
- Various edge case bug fixes for threat redirects (Misdirection "cancelling" Vigilance and similar).
- Target re-selection is now significantly faster.
- Fixed a ton of other smaller edge case bugs, probably.
Closes #7951 and #19998.
Diffstat (limited to 'src/server/scripts')
21 files changed, 254 insertions, 250 deletions
diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 9cb8e554372..54f80e6abb4 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -842,23 +842,73 @@ public:      static bool HandleDebugThreatListCommand(ChatHandler* handler, char const* /*args*/)      { -        Creature* target = handler->getSelectedCreature(); -        if (!target || target->IsTotem() || target->IsPet()) -            return false; +        Unit* target = handler->getSelectedUnit(); +        if (!target) +            target = handler->GetSession()->GetPlayer(); +         +        ThreatManager& mgr = target->GetThreatManager(); +        if (!target->IsAlive()) +        { +            handler->PSendSysMessage("%s (guid %u) is not alive.", target->GetName().c_str(), target->GetGUID().GetCounter()); +            return true; +        } +        if (!target->CanHaveThreatList()) +            handler->PSendSysMessage("%s (guid %u) cannot have a threat list.", target->GetName().c_str(), target->GetGUID().GetCounter()); -        ThreatContainer::StorageType const& threatList = target->GetThreatManager().getThreatList(); -        ThreatContainer::StorageType::const_iterator itr;          uint32 count = 0; -        handler->PSendSysMessage("Threat list of %s (guid %u)", target->GetName().c_str(), target->GetGUID().GetCounter()); -        for (itr = threatList.begin(); itr != threatList.end(); ++itr) +        auto const& threatenedByMe = target->GetThreatManager().GetThreatenedByMeList(); +        if (threatenedByMe.empty()) +            handler->PSendSysMessage("%s (guid %u) does not threaten any units.", target->GetName().c_str(), target->GetGUID().GetCounter()); +        else          { -            Unit* unit = (*itr)->getTarget(); -            if (!unit) -                continue; -            ++count; -            handler->PSendSysMessage("   %u.   %s   (guid %u)  - threat %f", count, unit->GetName().c_str(), unit->GetGUID().GetCounter(), (*itr)->getThreat()); +            handler->PSendSysMessage("List of units threatened by %s (guid %u)", target->GetName().c_str(), target->GetGUID().GetCounter()); +            for (auto const& pair : threatenedByMe) +            { +                Unit* unit = pair.second->GetOwner(); +                handler->PSendSysMessage("   %u.   %s   (current guid %u, DB guid %u)  - threat %f", ++count, unit->GetName().c_str(), unit->GetGUID().GetCounter(), unit->GetTypeId() == TYPEID_UNIT ? unit->ToCreature()->GetSpawnId() : 0, pair.second->GetThreat()); +            } +            handler->SendSysMessage("End of threatened-by-me list.");          } -        handler->SendSysMessage("End of threat list."); + +        if (!mgr.CanHaveThreatList()) +            return true; +        if (mgr.IsEngaged()) +        { +            count = 0; +            handler->PSendSysMessage("Threat list of %s (guid %u, DB GUID %u)", target->GetName().c_str(), target->GetGUID().GetCounter(), target->GetTypeId() == TYPEID_UNIT ? target->ToCreature()->GetSpawnId() : 0); +            for (ThreatReference const* ref : mgr.GetSortedThreatList()) +            { +                Unit* unit = ref->GetVictim(); +                char const* onlineStr; +                switch (ref->GetOnlineState()) +                { +                    case ThreatReference::ONLINE_STATE_SUPPRESSED: +                        onlineStr = " [SUPPRESSED]"; +                        break; +                    case ThreatReference::ONLINE_STATE_OFFLINE: +                        onlineStr = " [OFFLINE]"; +                        break; +                    default: +                        onlineStr = ""; +                } +                char const* tauntStr; +                switch (ref->GetTauntState()) +                { +                    case ThreatReference::TAUNT_STATE_TAUNT: +                        tauntStr = " [TAUNT]"; +                        break; +                    case ThreatReference::TAUNT_STATE_DETAUNT: +                        tauntStr = " [DETAUNT]"; +                        break; +                    default: +                        tauntStr = ""; +                } +                handler->PSendSysMessage("   %u.   %s   (guid %u)  - threat %f%s%s", ++count, unit->GetName().c_str(), unit->GetGUID().GetCounter(), ref->GetThreat(), tauntStr, onlineStr); +            } +            handler->SendSysMessage("End of threat list."); +        } +        else +            handler->PSendSysMessage("%s (guid %u, DB GUID %u) is not currently engaged.", target->GetName().c_str(), target->GetGUID().GetCounter(), target->GetTypeId() == TYPEID_UNIT ? target->ToCreature()->GetSpawnId() : 0);          return true;      } @@ -867,19 +917,18 @@ public:          Unit* target = handler->getSelectedUnit();          if (!target)              target = handler->GetSession()->GetPlayer(); -        HostileReference* ref = target->getHostileRefManager().getFirst(); -        uint32 count = 0; -        handler->PSendSysMessage("Hostil reference list of %s (guid %u)", target->GetName().c_str(), target->GetGUID().GetCounter()); -        while (ref) + +        handler->PSendSysMessage("Combat refs: (Combat state: %d | Manager state: %d)", target->IsInCombat(), target->GetCombatManager().HasCombat()); +        for (auto const& ref : target->GetCombatManager().GetPvPCombatRefs())          { -            if (Unit* unit = ref->GetSource()->GetOwner()) -            { -                ++count; -                handler->PSendSysMessage("   %u.   %s   (current guid %u, DB guid %u)  - threat %f", count, unit->GetName().c_str(), unit->GetGUID().GetCounter(), unit->GetTypeId() == TYPEID_UNIT ? unit->ToCreature()->GetSpawnId() : 0, ref->getThreat()); -            } -            ref = ref->next(); +            Unit* unit = ref.second->GetOther(target); +            handler->PSendSysMessage("[PvP] %s (DBGUID %u)", unit->GetName().c_str(), unit->GetTypeId() == TYPEID_UNIT ? unit->ToCreature()->GetSpawnId() : 0); +        } +        for (auto const& ref : target->GetCombatManager().GetPvECombatRefs()) +        { +            Unit* unit = ref.second->GetOther(target); +            handler->PSendSysMessage("[PvE] %s (DBGUID %u)", unit->GetName().c_str(), unit->GetTypeId() == TYPEID_UNIT ? unit->ToCreature()->GetSpawnId() : 0);          } -        handler->SendSysMessage("End of hostil reference list.");          return true;      } diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index aecef71a961..cc28b2da8ab 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -2420,7 +2420,6 @@ public:              return false;          target->CombatStop(); -        target->getHostileRefManager().deleteReferences();          return true;      } diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp index 6635fc0bc7b..4ffaf1c5f42 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp @@ -199,30 +199,21 @@ public:              if (!summonedUnit)                  return; -            ThreatContainer::StorageType const& threatlist = me->GetThreatManager().getThreatList(); -            ThreatContainer::StorageType::const_iterator i = threatlist.begin(); -            for (i = threatlist.begin(); i != threatlist.end(); ++i) +            for (auto* ref : me->GetThreatManager().GetUnsortedThreatList())              { -                Unit* unit = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()); +                Unit* unit = ref->GetVictim();                  if (unit && unit->IsAlive()) -                { -                    float threat = me->GetThreatManager().getThreat(unit); -                    AddThreat(unit, threat, summonedUnit); -                } +                    AddThreat(unit, ref->GetThreat(), summonedUnit);              }          }          void TeleportPlayersToSelf()          { -            float x = KaelLocations[0][0]; -            float y = KaelLocations[0][1]; -            me->UpdatePosition(x, y, LOCATION_Z, 0.0f); -            ThreatContainer::StorageType threatlist = me->GetThreatManager().getThreatList(); -            ThreatContainer::StorageType::const_iterator i = threatlist.begin(); -            for (i = threatlist.begin(); i != threatlist.end(); ++i) +            me->UpdatePosition(KaelLocations[0][0], KaelLocations[0][1], LOCATION_Z, 0.0f); +            for (auto const& pair : me->GetCombatManager().GetPvECombatRefs())              { -                Unit* unit = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()); -                if (unit && (unit->GetTypeId() == TYPEID_PLAYER)) +                Unit* unit = pair.second->GetOther(me); +                if (unit->GetTypeId() == TYPEID_PLAYER)                      unit->CastSpell(unit, SPELL_TELEPORT_CENTER, true);              }              DoCast(me, SPELL_TELEPORT_CENTER, true); @@ -230,14 +221,11 @@ public:          void CastGravityLapseKnockUp()          { -            ThreatContainer::StorageType threatlist = me->GetThreatManager().getThreatList(); -            ThreatContainer::StorageType::const_iterator i = threatlist.begin(); -            for (i = threatlist.begin(); i != threatlist.end(); ++i) +            for (auto const& pair : me->GetCombatManager().GetPvECombatRefs())              { -                Unit* unit = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()); -                if (unit && (unit->GetTypeId() == TYPEID_PLAYER)) +                Unit* unit = pair.second->GetOther(me); +                if (unit->GetTypeId() == TYPEID_PLAYER)                  { -                    // Knockback into the air                      CastSpellExtraArgs args;                      args.TriggerFlags = TRIGGERED_FULL_MASK;                      args.OriginalCaster = me->GetGUID(); @@ -248,12 +236,10 @@ public:          void CastGravityLapseFly()                              // Use Fly Packet hack for now as players can't cast "fly" spells unless in map 530. Has to be done a while after they get knocked into the air...          { -            ThreatContainer::StorageType threatlist = me->GetThreatManager().getThreatList(); -            ThreatContainer::StorageType::const_iterator i = threatlist.begin(); -            for (i = threatlist.begin(); i != threatlist.end(); ++i) +            for (auto const& pair : me->GetCombatManager().GetPvECombatRefs())              { -                Unit* unit = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()); -                if (unit && (unit->GetTypeId() == TYPEID_PLAYER)) +                Unit* unit = pair.second->GetOther(me); +                if (unit->GetTypeId() == TYPEID_PLAYER)                  {                      // Also needs an exception in spell system.                      CastSpellExtraArgs args; @@ -267,12 +253,10 @@ public:          void RemoveGravityLapse()          { -            ThreatContainer::StorageType threatlist = me->GetThreatManager().getThreatList(); -            ThreatContainer::StorageType::const_iterator i = threatlist.begin(); -            for (i = threatlist.begin(); i != threatlist.end(); ++i) +            for (auto const& pair : me->GetCombatManager().GetPvECombatRefs())              { -                Unit* unit = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()); -                if (unit && (unit->GetTypeId() == TYPEID_PLAYER)) +                Unit* unit = pair.second->GetOther(me); +                if (unit->GetTypeId() == TYPEID_PLAYER)                  {                      unit->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_FLY);                      unit->RemoveAurasDueToSpell(SPELL_GRAVITY_LAPSE_DOT); @@ -684,8 +668,8 @@ public:              {                  if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))                  { -                    AddThreat(target, 1.0f); -                    me->TauntApply(target); +                    ResetThreatList(); +                    AddThreat(target, 1000000.0f);                      AttackStart(target);                  } diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp index 9480bf038a5..6d7816ff0d8 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp @@ -855,17 +855,12 @@ public:              if (Blink_Timer <= diff)              {                  bool InMeleeRange = false; -                ThreatContainer::StorageType const& t_list = me->GetThreatManager().getThreatList(); -                for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) +                for (auto const& pair : me->GetCombatManager().GetPvECombatRefs())                  { -                    if (Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid())) +                    if (pair.second->GetOther(me)->IsWithinMeleeRange(me))                      { -                        //if in melee range -                        if (target->IsWithinDistInMap(me, 5)) -                        { -                            InMeleeRange = true; -                            break; -                        } +                        InMeleeRange = true; +                        break;                      }                  } @@ -949,17 +944,12 @@ public:              if (Intercept_Stun_Timer <= diff)              {                  bool InMeleeRange = false; -                ThreatContainer::StorageType const& t_list = me->GetThreatManager().getThreatList(); -                for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) +                for (auto const& pair : me->GetCombatManager().GetPvECombatRefs())                  { -                    if (Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid())) +                    if (pair.second->GetOther(me)->IsWithinMeleeRange(me))                      { -                        //if in melee range -                        if (target->IsWithinDistInMap(me, ATTACK_DISTANCE)) -                        { -                            InMeleeRange = true; -                            break; -                        } +                        InMeleeRange = true; +                        break;                      }                  } diff --git a/src/server/scripts/Kalimdor/boss_azuregos.cpp b/src/server/scripts/Kalimdor/boss_azuregos.cpp index 8a98eae734a..e4e12a765ca 100644 --- a/src/server/scripts/Kalimdor/boss_azuregos.cpp +++ b/src/server/scripts/Kalimdor/boss_azuregos.cpp @@ -118,13 +118,10 @@ class boss_azuregos : public CreatureScript                          case EVENT_TELEPORT:                          {                              Talk(SAY_TELEPORT); -                            ThreatContainer::StorageType const& threatlist = me->GetThreatManager().getThreatList(); -                            for (ThreatContainer::StorageType::const_iterator i = threatlist.begin(); i != threatlist.end(); ++i) -                            { -                                if (Player* player = ObjectAccessor::GetPlayer(*me, (*i)->getUnitGuid())) +                            for (auto const& pair : me->GetCombatManager().GetPvECombatRefs()) +                                if (Player* player = pair.second->GetOther(me)->ToPlayer())                                      DoTeleportPlayer(player, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()+3, player->GetOrientation()); -                            } - +                                                       ResetThreatList();                              events.ScheduleEvent(EVENT_TELEPORT, 30000);                              break; diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp index c6cae404478..1d6eed64946 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_prince_taldaram.cpp @@ -41,6 +41,7 @@ enum Spells      SPELL_FLAME_SPHERE_DEATH_EFFECT         = 55947,      SPELL_EMBRACE_OF_THE_VAMPYR             = 55959,      SPELL_VANISH                            = 55964, +    SPELL_SHADOWSTEP                        = 55966,      NPC_FLAME_SPHERE_1                      = 30106,      NPC_FLAME_SPHERE_2                      = 31686, @@ -77,9 +78,8 @@ enum Events      EVENT_CONJURE_FLAME_SPHERES             = 1,      EVENT_BLOODTHIRST,      EVENT_VANISH, -    EVENT_JUST_VANISHED, -    EVENT_VANISHED, -    EVENT_FEEDING, +    EVENT_START_FEEDING, +    EVENT_DONE_FEEDING,      // Flame Sphere      EVENT_START_MOVE, @@ -97,6 +97,7 @@ class boss_prince_taldaram : public CreatureScript              {                  me->SetDisableGravity(true);                  _embraceTakenDamage = 0; +                _initialCheckTimer = 3000;              }              void Reset() override @@ -140,8 +141,30 @@ class boss_prince_taldaram : public CreatureScript              void UpdateAI(uint32 diff) override              { -                if (!UpdateVictim()) -                    return; +                if (_initialCheckTimer) +                { +                    if (_initialCheckTimer <= diff) +                    { +                        CheckSpheres(); +                        _initialCheckTimer = 0; +                    } +                    else +                        _initialCheckTimer -= diff; +                } + +                if (me->HasAura(SPELL_VANISH)) +                { +                    if (me->GetThreatManager().IsThreatListEmpty(true)) +                    { +                        EnterEvadeMode(EVADE_REASON_NO_HOSTILES); +                        return; +                    } +                } +                else +                { +                    if (!UpdateVictim()) +                        return; +                }                  events.Update(diff); @@ -167,47 +190,29 @@ class boss_prince_taldaram : public CreatureScript                              break;                          case EVENT_VANISH:                          { -                            Map::PlayerList const& players = me->GetMap()->GetPlayers(); -                            uint32 targets = 0; -                            for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i) -                            { -                                Player* player = i->GetSource(); -                                if (player && player->IsAlive()) -                                    ++targets; -                            } - -                            if (targets > 2) +                            if (me->GetThreatManager().GetThreatListSize() > 1)                              { +                                if (Unit* embraceTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) +                                    _embraceTargetGUID = embraceTarget->GetGUID();                                  Talk(SAY_VANISH);                                  DoCast(me, SPELL_VANISH); -                                me->SetInCombatState(true); // Prevents the boss from resetting                                  events.DelayEvents(500); -                                events.ScheduleEvent(EVENT_JUST_VANISHED, 500); -                                if (Unit* embraceTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) -                                    _embraceTargetGUID = embraceTarget->GetGUID(); +                                events.ScheduleEvent(EVENT_START_FEEDING, 2000);                              }                              events.ScheduleEvent(EVENT_VANISH, urand(25000, 35000));                              break;                          } -                        case EVENT_JUST_VANISHED: +                        case EVENT_START_FEEDING: +                            me->RemoveAurasDueToSpell(SPELL_VANISH);                              if (Unit* embraceTarget = GetEmbraceTarget())                              { -                                me->GetMotionMaster()->Clear(); -                                me->SetSpeedRate(MOVE_WALK, 2.0f); -                                me->GetMotionMaster()->MoveChase(embraceTarget); -                            } -                            events.ScheduleEvent(EVENT_VANISHED, 1300); -                            break; -                        case EVENT_VANISHED: -                            if (Unit* embraceTarget = GetEmbraceTarget()) +                                DoCast(embraceTarget, SPELL_SHADOWSTEP);                                  DoCast(embraceTarget, SPELL_EMBRACE_OF_THE_VAMPYR); -                            Talk(SAY_FEED); -                            me->GetMotionMaster()->Clear(); -                            me->SetSpeedRate(MOVE_WALK, 1.0f); -                            me->GetMotionMaster()->MoveChase(me->GetVictim()); -                            events.ScheduleEvent(EVENT_FEEDING, 20000); +                                Talk(SAY_FEED); +                                events.ScheduleEvent(EVENT_DONE_FEEDING, 20000); +                            }                              break; -                        case EVENT_FEEDING: +                        case EVENT_DONE_FEEDING:                              _embraceTargetGUID.Clear();                              break;                          default: @@ -289,6 +294,7 @@ class boss_prince_taldaram : public CreatureScript              ObjectGuid _flameSphereTargetGUID;              ObjectGuid _embraceTargetGUID;              uint32 _embraceTakenDamage; +            uint32 _initialCheckTimer;          };          CreatureAI* GetAI(Creature* creature) const override diff --git a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp index 9ba7cce3130..8ce416a5eba 100644 --- a/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/AzjolNerub/boss_hadronox.cpp @@ -163,13 +163,9 @@ public:          bool IsInCombatWithPlayer() const          { -            std::list<HostileReference*> const& refs = me->GetThreatManager().getThreatList(); -            for (HostileReference const* hostileRef : refs) -            { -                if (Unit const* target = hostileRef->getTarget()) -                    if (target->IsControlledByPlayer()) -                        return true; -            } +            for (auto const& pair : me->GetCombatManager().GetPvECombatRefs()) +                if (pair.second->GetOther(me)->IsControlledByPlayer()) +                    return true;              return false;          } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index 1c4f444234b..6f77a251f31 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -822,7 +822,7 @@ class npc_anubarak_spike : public CreatureScript                  DoCast(who, SPELL_MARK);                  me->SetSpeedRate(MOVE_RUN, 0.5f);                  // make sure the Spine will really follow the one he should -                ResetThreatList(); +                me->GetThreatManager().ResetAllThreat();                  me->SetInCombatWithZone();                  AddThreat(who, 1000000.0f);                  me->GetMotionMaster()->Clear(true); diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp index 7ea01046763..6bc1bdc9e10 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_faction_champions.cpp @@ -673,14 +673,10 @@ struct boss_faction_championsAI : public BossAI      Unit* SelectEnemyCaster(bool /*casting*/)      { -        std::list<HostileReference*> const& tList = me->GetThreatManager().getThreatList(); -        std::list<HostileReference*>::const_iterator iter; -        for (iter = tList.begin(); iter!=tList.end(); ++iter) -        { -            Unit* target = ObjectAccessor::GetUnit(*me, (*iter)->getUnitGuid()); -            if (target && target->getPowerType() == POWER_MANA) -                return target; -        } +        for (auto const& pair : me->GetCombatManager().GetPvECombatRefs()) +            if (Player* player = pair.second->GetOther(me)->ToPlayer()) +                if (player->getPowerType() == POWER_MANA) +                    return player;          return nullptr;      } diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index e87248ddff0..1a78118b7c1 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -1342,7 +1342,7 @@ class npc_the_lich_king_escape_hor : public CreatureScript                              AttackStart(victim);                      return me->GetVictim() != nullptr;                  } -                else if (me->GetThreatManager().GetThreatListSize() < 2 && me->HasAura(SPELL_REMORSELESS_WINTER)) +                else if (me->GetCombatManager().GetPvECombatRefs().size() < 2 && me->HasAura(SPELL_REMORSELESS_WINTER))                  {                      EnterEvadeMode(EVADE_REASON_OTHER);                      return false; diff --git a/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp b/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp index 02afc219aa3..4ac7f99e2c2 100644 --- a/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp +++ b/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp @@ -148,15 +148,12 @@ class boss_drakkari_colossus : public CreatureScript                          if (me->GetReactState() == REACT_AGGRESSIVE)                              return; -                        me->SetReactState(REACT_AGGRESSIVE);                          me->SetImmuneToPC(false); +                        me->SetReactState(REACT_AGGRESSIVE);                          me->RemoveAura(SPELL_FREEZE_ANIM);                          me->SetInCombatWithZone(); -                        if (me->GetVictim()) -                            me->GetMotionMaster()->MoveChase(me->GetVictim(), 0, 0); -                          break;                  }              } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp index 90c9224669f..f940d67f8c7 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -560,25 +560,15 @@ class npc_green_dragon_combat_trigger : public CreatureScript                  if (!me->IsInCombat())                      return; -                // @TODO check out of bounds on all encounter creatures, evade if matched - -                std::list<HostileReference*> const& threatList = me->GetThreatManager().getThreatList(); -                if (threatList.empty()) -                { -                    EnterEvadeMode(); -                    return; -                } -                  // check evade every second tick                  _evadeCheck ^= true;                  if (!_evadeCheck)                      return; -                // check if there is any player on threatlist, if not - evade -                for (std::list<HostileReference*>::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr) -                    if (Unit* target = (*itr)->getTarget()) -                        if (target->GetTypeId() == TYPEID_PLAYER) -                            return; // found any player, return +                // check if there is any player engaged, if not - evade +                for (auto const& pair : me->GetCombatManager().GetPvECombatRefs()) +                    if (pair.second->GetOther(me)->GetTypeId() == TYPEID_PLAYER) +                        return;                  EnterEvadeMode();              } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp index 777b9a8cf1a..3bbb13258f1 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp @@ -487,12 +487,11 @@ class boss_hodir : public CreatureScript                  if (gettingColdInHereTimer <= diff && gettingColdInHere)                  { -                    std::list<HostileReference*> ThreatList = me->GetThreatManager().getThreatList(); -                    for (std::list<HostileReference*>::const_iterator itr = ThreatList.begin(); itr != ThreatList.end(); ++itr) -                        if (Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid())) +                    for (auto const& pair : me->GetCombatManager().GetPvECombatRefs()) +                        if (Player* target = pair.second->GetOther(me)->ToPlayer())                              if (Aura* BitingColdAura = target->GetAura(SPELL_BITING_COLD_TRIGGERED)) -                                if ((target->GetTypeId() == TYPEID_PLAYER) && (BitingColdAura->GetStackAmount() > 2)) -                                        SetData(DATA_GETTING_COLD_IN_HERE, 0); +                                if (BitingColdAura->GetStackAmount() > 2) +                                    SetData(DATA_GETTING_COLD_IN_HERE, 0);                      gettingColdInHereTimer = 1000;                  }                  else diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp index 53850b38f54..c67c88a397d 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp @@ -198,7 +198,7 @@ class boss_ingvar_the_plunderer : public CreatureScript              void UpdateAI(uint32 diff) override              { -                if (!events.IsInPhase(PHASE_EVENT) && !UpdateVictim()) +                if (!UpdateVictim())                      return;                  events.Update(diff); @@ -231,9 +231,7 @@ class boss_ingvar_the_plunderer : public CreatureScript                              ScheduleSecondPhase();                              me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);                              me->SetImmuneToPC(false); -                            if (Unit* target = me->GetThreatManager().SelectVictim()) -                                AttackStart(target); -                            else +                            if (!me->IsThreatened())                              {                                  EnterEvadeMode(EVADE_REASON_NO_HOSTILES);                                  return; diff --git a/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp b/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp index eba719e957e..bcc0f7c0c51 100644 --- a/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp +++ b/src/server/scripts/Northrend/VaultOfArchavon/boss_toravon.cpp @@ -184,7 +184,7 @@ class spell_toravon_random_aggro : public SpellScript          if (!caster->IsAIEnabled)              return; -        caster->GetThreatManager().resetAllAggro(); +        caster->GetThreatManager().ResetAllThreat();          if (Unit* target = caster->AI()->SelectTarget(SELECT_TARGET_RANDOM, 1))              caster->GetThreatManager().AddThreat(target, 1000000); diff --git a/src/server/scripts/Pet/pet_hunter.cpp b/src/server/scripts/Pet/pet_hunter.cpp index 5a295c04f05..50c61f4c885 100644 --- a/src/server/scripts/Pet/pet_hunter.cpp +++ b/src/server/scripts/Pet/pet_hunter.cpp @@ -238,8 +238,11 @@ class spell_pet_guard_dog : public SpellScriptLoader                  Unit* caster = eventInfo.GetActor();                  caster->CastSpell(nullptr, SPELL_PET_GUARD_DOG_HAPPINESS, aurEff); +                Unit* target = eventInfo.GetProcTarget(); +                if (!target->CanHaveThreatList()) +                    return;                  float addThreat = CalculatePct(ASSERT_NOTNULL(eventInfo.GetSpellInfo())->Effects[EFFECT_0].CalcValue(caster), aurEff->GetAmount()); -                eventInfo.GetProcTarget()->GetThreatManager().AddThreat(caster, addThreat, GetSpellInfo(), false, true); +                target->GetThreatManager().AddThreat(caster, addThreat, GetSpellInfo(), false, true);              }              void Register() override diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index c9ae8848d40..89b14f71ccb 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -45,6 +45,7 @@ enum HunterSpells      SPELL_HUNTER_IMPROVED_MEND_PET                  = 24406,      SPELL_HUNTER_INVIGORATION_TRIGGERED             = 53398,      SPELL_HUNTER_MASTERS_CALL_TRIGGERED             = 62305, +    SPELL_HUNTER_MISDIRECTION                       = 34477,      SPELL_HUNTER_MISDIRECTION_PROC                  = 35079,      SPELL_HUNTER_PET_LAST_STAND_TRIGGERED           = 53479,      SPELL_HUNTER_PET_HEART_OF_THE_PHOENIX           = 55709, @@ -911,12 +912,7 @@ class spell_hun_misdirection : public SpellScriptLoader              void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)              {                  if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT || !GetTarget()->HasAura(SPELL_HUNTER_MISDIRECTION_PROC)) -                    GetTarget()->ResetRedirectThreat(); -            } - -            bool CheckProc(ProcEventInfo& /*eventInfo*/) -            { -                return GetTarget()->GetRedirectThreatTarget() != nullptr; +                    GetTarget()->GetThreatManager().UnregisterRedirectThreat(SPELL_HUNTER_MISDIRECTION);              }              void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) @@ -928,7 +924,6 @@ class spell_hun_misdirection : public SpellScriptLoader              void Register() override              {                  AfterEffectRemove += AuraEffectRemoveFn(spell_hun_misdirection_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); -                DoCheckProc += AuraCheckProcFn(spell_hun_misdirection_AuraScript::CheckProc);                  OnEffectProc += AuraEffectProcFn(spell_hun_misdirection_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);              }          }; @@ -951,7 +946,7 @@ class spell_hun_misdirection_proc : public SpellScriptLoader              void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)              { -                GetTarget()->ResetRedirectThreat(); +                GetTarget()->GetThreatManager().UnregisterRedirectThreat(SPELL_HUNTER_MISDIRECTION);              }              void Register() override diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index fd46173675d..e04c0f76791 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -43,7 +43,8 @@ enum RogueSpells      SPELL_ROGUE_KILLING_SPREE_WEAPON_DMG        = 57841,      SPELL_ROGUE_KILLING_SPREE_DMG_BUFF          = 61851,      SPELL_ROGUE_PREY_ON_THE_WEAK                = 58670, -    SPELL_ROGUE_SHIV_TRIGGERED                  = 5940, +    SPELL_ROGUE_SHIV_TRIGGERED                  =  5940, +    SPELL_ROGUE_TRICKS_OF_THE_TRADE             = 57934,      SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST   = 57933,      SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC        = 59628,      SPELL_ROGUE_HONOR_AMONG_THIEVES             = 51698, @@ -52,7 +53,7 @@ enum RogueSpells      SPELL_ROGUE_T10_2P_BONUS                    = 70804,      SPELL_ROGUE_GLYPH_OF_BACKSTAB_TRIGGER       = 63975,      SPELL_ROGUE_QUICK_RECOVERY_ENERGY           = 31663, -    SPELL_ROGUE_CRIPPLING_POISON                = 3409, +    SPELL_ROGUE_CRIPPLING_POISON                =  3409,      SPELL_ROGUE_MASTER_OF_SUBTLETY_BUFF         = 31665,      SPELL_ROGUE_OVERKILL_BUFF                   = 58427  }; @@ -879,87 +880,86 @@ class spell_rog_shiv : public SpellScriptLoader  };  // 57934 - Tricks of the Trade -class spell_rog_tricks_of_the_trade : public SpellScriptLoader +class spell_rog_tricks_of_the_trade_aura : public AuraScript  { -    public: -        spell_rog_tricks_of_the_trade() : SpellScriptLoader("spell_rog_tricks_of_the_trade") { } +    PrepareAuraScript(spell_rog_tricks_of_the_trade_aura); -        class spell_rog_tricks_of_the_trade_AuraScript : public AuraScript +    bool Validate(SpellInfo const* /*spellInfo*/) override +    { +        return ValidateSpellInfo(          { -            PrepareAuraScript(spell_rog_tricks_of_the_trade_AuraScript); +            SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST, +            SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC +        }); +    } -            bool Validate(SpellInfo const* /*spellInfo*/) override -            { -                return ValidateSpellInfo( -                { -                    SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST, -                    SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC -                }); -            } +    void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +    { +        if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT || !GetTarget()->HasAura(SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC)) +            GetTarget()->GetThreatManager().UnregisterRedirectThreat(SPELL_ROGUE_TRICKS_OF_THE_TRADE); +    } -            void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) -            { -                if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT) -                    GetTarget()->ResetRedirectThreat(); -            } +    void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) +    { +        PreventDefaultAction(); -            bool CheckProc(ProcEventInfo& /*eventInfo*/) -            { -                _redirectTarget = GetTarget()->GetRedirectThreatTarget(); -                return _redirectTarget != nullptr; -            } +        Unit* rogue = GetTarget(); +        Unit* target = ObjectAccessor::GetUnit(*rogue, _redirectTarget); +        if (target) +        { +            rogue->CastSpell(target, SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST, aurEff); +            rogue->CastSpell(rogue, SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC, aurEff); +        } +        Remove(AURA_REMOVE_BY_DEFAULT); +    } -            void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/) -            { -                PreventDefaultAction(); +    void Register() override +    { +        AfterEffectRemove += AuraEffectRemoveFn(spell_rog_tricks_of_the_trade_aura::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); +        OnEffectProc += AuraEffectProcFn(spell_rog_tricks_of_the_trade_aura::HandleProc, EFFECT_1, SPELL_AURA_DUMMY); +    } -                Unit* target = GetTarget(); -                target->CastSpell(_redirectTarget, SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST, true); -                target->CastSpell(target, SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC, true); -                Remove(AURA_REMOVE_BY_DEFAULT); // maybe handle by proc charges -            } +    ObjectGuid _redirectTarget; +public: +    void SetRedirectTarget(ObjectGuid const& guid) { _redirectTarget = guid; } +}; -            void Register() override +class spell_rog_tricks_of_the_trade : public SpellScript +{ +    PrepareSpellScript(spell_rog_tricks_of_the_trade); + +    void DoAfterHit() +    { +        if (Aura* aura = GetHitAura()) +            if (auto* script = aura->GetScript<spell_rog_tricks_of_the_trade_aura>("spell_rog_tricks_of_the_trade"))              { -                AfterEffectRemove += AuraEffectRemoveFn(spell_rog_tricks_of_the_trade_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); -                DoCheckProc += AuraCheckProcFn(spell_rog_tricks_of_the_trade_AuraScript::CheckProc); -                OnEffectProc += AuraEffectProcFn(spell_rog_tricks_of_the_trade_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY); +                if (Unit* explTarget = GetExplTargetUnit()) +                    script->SetRedirectTarget(explTarget->GetGUID()); +                else +                    script->SetRedirectTarget(ObjectGuid::Empty);              } +    } -            Unit* _redirectTarget = nullptr; -        }; - -        AuraScript* GetAuraScript() const override -        { -            return new spell_rog_tricks_of_the_trade_AuraScript(); -        } +    void Register() override +    { +        AfterHit += SpellHitFn(spell_rog_tricks_of_the_trade::DoAfterHit); +    }  };  // 59628 - Tricks of the Trade (Proc) -class spell_rog_tricks_of_the_trade_proc : public SpellScriptLoader +class spell_rog_tricks_of_the_trade_proc : public AuraScript  { -    public: -        spell_rog_tricks_of_the_trade_proc() : SpellScriptLoader("spell_rog_tricks_of_the_trade_proc") { } +    PrepareAuraScript(spell_rog_tricks_of_the_trade_proc); -        class spell_rog_tricks_of_the_trade_proc_AuraScript : public AuraScript -        { -            PrepareAuraScript(spell_rog_tricks_of_the_trade_proc_AuraScript); - -            void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) -            { -                GetTarget()->ResetRedirectThreat(); -            } - -            void Register() override -            { -                AfterEffectRemove += AuraEffectRemoveFn(spell_rog_tricks_of_the_trade_proc_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); -            } -        }; +    void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +    { +        GetTarget()->GetThreatManager().UnregisterRedirectThreat(SPELL_ROGUE_TRICKS_OF_THE_TRADE); +    } -        AuraScript* GetAuraScript() const override -        { -            return new spell_rog_tricks_of_the_trade_proc_AuraScript(); -        } +    void Register() override +    { +        AfterEffectRemove += AuraEffectRemoveFn(spell_rog_tricks_of_the_trade_proc::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); +    }  };  // 51698,51700,51701 - Honor Among Thieves @@ -1135,8 +1135,8 @@ void AddSC_rogue_spell_scripts()      new spell_rog_glyph_of_backstab_triggered();      new spell_rog_setup();      new spell_rog_shiv(); -    new spell_rog_tricks_of_the_trade(); -    new spell_rog_tricks_of_the_trade_proc(); +    RegisterSpellAndAuraScriptPair(spell_rog_tricks_of_the_trade, spell_rog_tricks_of_the_trade_aura); +    RegisterAuraScript(spell_rog_tricks_of_the_trade_proc);      new spell_rog_honor_among_thieves();      new spell_rog_honor_among_thieves_proc();      new spell_rog_turn_the_tables(); diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index 4be4717c9e4..38772874e0e 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -63,7 +63,7 @@ enum WarlockSpells      SPELL_WARLOCK_NETHER_PROTECTION_ARCANE          = 54373,      SPELL_WARLOCK_NETHER_PROTECTION_SHADOW          = 54374,      SPELL_WARLOCK_NETHER_PROTECTION_NATURE          = 54375, -    SPELL_WARLOCK_SOULSHATTER                       = 32835, +    SPELL_WARLOCK_SOULSHATTER_EFFECT                = 32835,      SPELL_WARLOCK_SIPHON_LIFE_HEAL                  = 63106,      SPELL_WARLOCK_UNSTABLE_AFFLICTION_DISPEL        = 31117,      SPELL_WARLOCK_GLYPH_OF_LIFE_TAP_TRIGGERED       = 63321, @@ -1383,17 +1383,15 @@ class spell_warl_soulshatter : public SpellScriptLoader              bool Validate(SpellInfo const* /*spellInfo*/) override              { -                return ValidateSpellInfo({ SPELL_WARLOCK_SOULSHATTER }); +                return ValidateSpellInfo({ SPELL_WARLOCK_SOULSHATTER_EFFECT });              }              void HandleDummy(SpellEffIndex /*effIndex*/)              {                  Unit* caster = GetCaster();                  if (Unit* target = GetHitUnit()) -                { -                    if (target->CanHaveThreatList() && target->GetThreatManager().IsThreatenedBy(caster, true)) -                        caster->CastSpell(target, SPELL_WARLOCK_SOULSHATTER, true); -                } +                    if (target->GetThreatManager().IsThreatenedBy(caster, true)) +                        caster->CastSpell(target, SPELL_WARLOCK_SOULSHATTER_EFFECT, true);              }              void Register() override diff --git a/src/server/scripts/Spells/spell_warrior.cpp b/src/server/scripts/Spells/spell_warrior.cpp index 3693ccf6eca..929bdb8fac3 100644 --- a/src/server/scripts/Spells/spell_warrior.cpp +++ b/src/server/scripts/Spells/spell_warrior.cpp @@ -1091,7 +1091,7 @@ class spell_warr_vigilance : public SpellScriptLoader                      target->RemoveAurasDueToSpell(SPELL_GEN_DAMAGE_REDUCTION_AURA);                  } -                target->ResetRedirectThreat(); +                target->GetThreatManager().UnregisterRedirectThreat(SPELL_WARRIOR_VIGILANCE_REDIRECT_THREAT, GetCasterGUID());              }              bool CheckProc(ProcEventInfo& /*eventInfo*/) diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 533228bcbb0..402761b9a6c 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -1811,21 +1811,28 @@ public:                  {                      case EVENT_TD_CHECK_COMBAT:                      { -                        time_t now = GameTime::GetGameTime(); -                        for (std::unordered_map<ObjectGuid, time_t>::iterator itr = _damageTimes.begin(); itr != _damageTimes.end();) +                        time_t const now = GameTime::GetGameTime(); +                        auto const& pveRefs = me->GetCombatManager().GetPvECombatRefs(); +                        for (auto itr = _damageTimes.begin(); itr != _damageTimes.end();)                          {                              // If unit has not dealt damage to training dummy for 5 seconds, remove him from combat                              if (itr->second < now - 5)                              { -                                if (Unit* unit = ObjectAccessor::GetUnit(*me, itr->first)) -                                    unit->getHostileRefManager().deleteReference(me); +                                auto it = pveRefs.find(itr->first); +                                if (it != pveRefs.end()) +                                    it->second->EndCombat();                                  itr = _damageTimes.erase(itr);                              }                              else                                  ++itr;                          } -                        _events.ScheduleEvent(EVENT_TD_CHECK_COMBAT, 1000); + +                        for (auto const& pair : pveRefs) +                            if (_damageTimes.find(pair.first) == _damageTimes.end()) +                                _damageTimes[pair.first] = now; + +                        _events.Repeat(1s);                          break;                      }                      case EVENT_TD_DESPAWN:  | 
