refactor(Core/Combat): Port TrinityCore heap-based threat system (#24715)

Co-authored-by: blinkysc <blinkysc@users.noreply.github.com>
Co-authored-by: Treeston <treeston.mmoc@gmail.com>
Co-authored-by: killerwife <killerwife@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
blinkysc
2026-03-18 13:36:59 -05:00
committed by GitHub
parent c80a0f1fad
commit 984baa92dd
101 changed files with 7045 additions and 2659 deletions
+180 -33
View File
@@ -27,6 +27,7 @@
#include "Log.h"
#include "M2Stores.h"
#include "MapMgr.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "PoolMgr.h"
#include "ScriptMgr.h"
@@ -70,6 +71,8 @@ public:
{
{ "setbit", HandleDebugSet32BitCommand, SEC_ADMINISTRATOR, Console::No },
{ "threat", HandleDebugThreatListCommand, SEC_ADMINISTRATOR, Console::No },
{ "threatinfo", HandleDebugThreatInfoCommand, SEC_ADMINISTRATOR, Console::No },
{ "combat", HandleDebugCombatListCommand, SEC_ADMINISTRATOR, Console::No },
{ "hostile", HandleDebugHostileRefListCommand, SEC_ADMINISTRATOR, Console::No },
{ "anim", HandleDebugAnimCommand, SEC_ADMINISTRATOR, Console::No },
{ "arena", HandleDebugArenaCommand, SEC_ADMINISTRATOR, Console::No },
@@ -816,43 +819,182 @@ public:
static bool HandleDebugThreatListCommand(ChatHandler* handler)
{
Creature* target = handler->getSelectedCreature();
if (!target || target->IsTotem() || target->IsPet())
return false;
Unit* target = handler->getSelectedUnit();
if (!target)
target = handler->GetPlayer();
ThreatManager& mgr = target->GetThreatMgr();
if (!target->IsAlive())
{
handler->PSendSysMessage("{} ({}) is not alive.{}", target->GetName(), target->GetGUID().ToString(), target->IsEngaged() ? " (It is, however, engaged. Huh?)" : "");
return true;
}
auto const& threatList = target->GetThreatMgr().GetThreatList();
ThreatContainer::StorageType::const_iterator itr;
uint32 count = 0;
handler->PSendSysMessage("Threat list of {} ({})", target->GetName(), target->GetGUID().ToString());
for (itr = threatList.begin(); itr != threatList.end(); ++itr)
auto const& threatenedByMe = target->GetThreatMgr().GetThreatenedByMeList();
if (threatenedByMe.empty())
handler->PSendSysMessage("{} ({}) does not threaten any units.", target->GetName(), target->GetGUID().ToString());
else
{
Unit* unit = (*itr)->getTarget();
if (!unit)
handler->PSendSysMessage("List of units threatened by {} ({})", target->GetName(), target->GetGUID().ToString());
for (auto const& pair : threatenedByMe)
{
handler->PSendSysMessage(" {}. No Unit - threat {}", ++count, (*itr)->GetThreat());
continue;
Unit* unit = pair.second->GetOwner();
handler->PSendSysMessage(" {}. {} ({}, SpawnID {}) - threat {}", ++count, unit->GetName(), unit->GetGUID().ToString(), unit->IsCreature() ? unit->ToCreature()->GetSpawnId() : 0, pair.second->GetThreat());
}
handler->PSendSysMessage(" {}. {} ({}) - threat {}", ++count, unit->GetName(), unit->GetGUID().ToString(), (*itr)->GetThreat());
handler->SendSysMessage("End of threatened-by-me list.");
}
auto const& threatList2 = target->GetThreatMgr().GetOfflineThreatList();
for (itr = threatList2.begin(); itr != threatList2.end(); ++itr)
if (mgr.CanHaveThreatList())
{
Unit* unit = (*itr)->getTarget();
if (!unit)
if (!mgr.IsThreatListEmpty(true))
{
handler->PSendSysMessage(" {}. [offline] No Unit - threat {}", ++count, (*itr)->GetThreat());
continue;
}
if (target->IsEngaged())
handler->PSendSysMessage("Threat list of {} ({}, SpawnID {}):", target->GetName(), target->GetGUID().ToString(), target->IsCreature() ? target->ToCreature()->GetSpawnId() : 0);
else
handler->PSendSysMessage("{} ({}, SpawnID {}) is not engaged, but still has a threat list? Well, here it is:", target->GetName(), target->GetGUID().ToString(), target->IsCreature() ? target->ToCreature()->GetSpawnId() : 0);
handler->PSendSysMessage(" {}. [offline] {} ({}) - threat {}", ++count, unit->GetName(), unit->GetGUID().ToString(), (*itr)->GetThreat());
count = 0;
Unit* fixateVictim = mgr.GetFixateTarget();
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;
if (unit == fixateVictim)
tauntStr = " [FIXATE]";
else
switch (ref->GetTauntState())
{
case ThreatReference::TAUNT_STATE_TAUNT:
tauntStr = " [TAUNT]";
break;
case ThreatReference::TAUNT_STATE_DETAUNT:
tauntStr = " [DETAUNT]";
break;
default:
tauntStr = "";
}
handler->PSendSysMessage(" {}. {} ({}) - threat {}{}{}", ++count, unit->GetName(), unit->GetGUID().ToString(), ref->GetThreat(), tauntStr, onlineStr);
}
handler->SendSysMessage("End of threat list.");
}
else if (!target->IsEngaged())
handler->PSendSysMessage("{} ({}, SpawnID {}) is not currently engaged.", target->GetName(), target->GetGUID().ToString(), target->IsCreature() ? target->ToCreature()->GetSpawnId() : 0);
else
handler->PSendSysMessage("{} ({}, SpawnID {}) seems to be engaged, but does not have a threat list??", target->GetName(), target->GetGUID().ToString(), target->IsCreature() ? target->ToCreature()->GetSpawnId() : 0);
}
else if (target->IsEngaged())
handler->PSendSysMessage("{} ({}) is currently engaged. (This unit cannot have a threat list.)", target->GetName(), target->GetGUID().ToString());
else
handler->PSendSysMessage("{} ({}) is not currently engaged. (This unit cannot have a threat list.)", target->GetName(), target->GetGUID().ToString());
return true;
}
static bool HandleDebugThreatInfoCommand(ChatHandler* handler)
{
Unit* target = handler->getSelectedUnit();
if (!target)
{
handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
handler->SendSysMessage("End of threat list.");
handler->PSendSysMessage("Threat info for {} ({}):", target->GetName(), target->GetGUID().ToString());
ThreatManager const& mgr = target->GetThreatMgr();
// _singleSchoolModifiers
{
auto& mods = mgr._singleSchoolModifiers;
handler->SendSysMessage(" - Single-school threat modifiers:");
handler->PSendSysMessage(" |-- Physical: {:.2f}%", mods[SPELL_SCHOOL_NORMAL] * 100.0f);
handler->PSendSysMessage(" |-- Holy : {:.2f}%", mods[SPELL_SCHOOL_HOLY] * 100.0f);
handler->PSendSysMessage(" |-- Fire : {:.2f}%", mods[SPELL_SCHOOL_FIRE] * 100.0f);
handler->PSendSysMessage(" |-- Nature : {:.2f}%", mods[SPELL_SCHOOL_NATURE] * 100.0f);
handler->PSendSysMessage(" |-- Frost : {:.2f}%", mods[SPELL_SCHOOL_FROST] * 100.0f);
handler->PSendSysMessage(" |-- Shadow : {:.2f}%", mods[SPELL_SCHOOL_SHADOW] * 100.0f);
handler->PSendSysMessage(" |-- Arcane : {:.2f}%", mods[SPELL_SCHOOL_ARCANE] * 100.0f);
}
// _multiSchoolModifiers
{
auto& mods = mgr._multiSchoolModifiers;
handler->PSendSysMessage(" - Multi-school threat modifiers ({} entries):", mods.size());
for (auto const& pair : mods)
handler->PSendSysMessage(" |-- Mask 0x{:x}: {:.2f}%", uint32(pair.first), pair.second * 100.0f);
}
// _redirectInfo
{
auto const& redirectInfo = mgr._redirectInfo;
if (redirectInfo.empty())
handler->SendSysMessage(" - No redirects being applied");
else
{
handler->PSendSysMessage(" - {:02} redirects being applied:", redirectInfo.size());
for (auto const& pair : redirectInfo)
{
Unit* unit = ObjectAccessor::GetUnit(*target, pair.first);
handler->PSendSysMessage(" |-- {:02}% to {}", pair.second, unit ? unit->GetName() : pair.first.ToString());
}
}
}
// _redirectRegistry
{
auto const& redirectRegistry = mgr._redirectRegistry;
if (redirectRegistry.empty())
handler->SendSysMessage(" - No redirects are registered");
else
{
handler->PSendSysMessage(" - {:02} spells may have redirects registered", redirectRegistry.size());
for (auto const& outerPair : redirectRegistry)
{
SpellInfo const* const spell = sSpellMgr->GetSpellInfo(outerPair.first);
handler->PSendSysMessage(" |-- #{:06} {} ({} entries):", outerPair.first, spell ? spell->SpellName[0] : "<unknown>", outerPair.second.size());
for (auto const& innerPair : outerPair.second)
{
Unit* unit = ObjectAccessor::GetUnit(*target, innerPair.first);
handler->PSendSysMessage(" |-- {:02}% to {}", innerPair.second, unit ? unit->GetName() : innerPair.first.ToString());
}
}
}
}
return true;
}
static bool HandleDebugCombatListCommand(ChatHandler* handler)
{
Unit* target = handler->getSelectedUnit();
if (!target)
target = handler->GetPlayer();
handler->PSendSysMessage("Combat refs: (Combat state: {} | Manager state: {})", target->IsInCombat(), target->GetCombatManager().HasCombat());
for (auto const& ref : target->GetCombatManager().GetPvPCombatRefs())
{
Unit* unit = ref.second->GetOther(target);
handler->PSendSysMessage("[PvP] {} (SpawnID {})", unit->GetName(), unit->IsCreature() ? unit->ToCreature()->GetSpawnId() : 0);
}
for (auto const& ref : target->GetCombatManager().GetPvECombatRefs())
{
Unit* unit = ref.second->GetOther(target);
handler->PSendSysMessage("[PvE] {} (SpawnID {})", unit->GetName(), unit->IsCreature() ? unit->ToCreature()->GetSpawnId() : 0);
}
return true;
}
@@ -862,27 +1004,32 @@ public:
if (!target)
target = handler->GetSession()->GetPlayer();
HostileReference* ref = target->getHostileRefMgr().getFirst();
uint32 count = 0;
handler->PSendSysMessage("Hostile reference list of {} ({})", target->GetName(), target->GetGUID().ToString());
handler->PSendSysMessage("Threatened by me list of {} ({})", target->GetName(), target->GetGUID().ToString());
while (ref)
for (auto const& pair : target->GetThreatMgr().GetThreatenedByMeList())
{
if (Unit* unit = ref->GetSource()->GetOwner())
ThreatReference const* ref = pair.second;
Creature* owner = ref->GetOwner();
if (owner)
{
handler->PSendSysMessage(" {}. {} {} ({}) - threat {}", ++count, (ref->IsOnline() ? "" : "[offline]"),
unit->GetName(), unit->GetGUID().ToString(), ref->GetThreat());
std::string stateStr = "";
if (ref->IsOffline())
stateStr = "[offline] ";
else if (ref->IsSuppressed())
stateStr = "[suppressed] ";
handler->PSendSysMessage(" {}. {}{} ({}) - threat {}", ++count, stateStr,
owner->GetName(), owner->GetGUID().ToString(), ref->GetThreat());
}
else
{
handler->PSendSysMessage(" {}. No Owner - threat {}", ++count, ref->GetThreat());
}
ref = ref->next();
}
handler->SendSysMessage("End of hostile reference list.");
handler->SendSysMessage("End of threatened by me list.");
return true;
}
+1 -1
View File
@@ -2904,7 +2904,7 @@ public:
}
playerTarget->CombatStop();
playerTarget->getHostileRefMgr().deleteReferences();
playerTarget->GetThreatMgr().RemoveMeFromThreatLists();
return true;
}
+1 -1
View File
@@ -446,7 +446,7 @@ public:
case SPELL_AURA_HASTE_RANGED: return "SPELL_AURA_HASTE_RANGED";
case SPELL_AURA_MOD_MANA_REGEN_FROM_STAT: return "SPELL_AURA_MOD_MANA_REGEN_FROM_STAT";
case SPELL_AURA_MOD_RATING_FROM_STAT: return "SPELL_AURA_MOD_RATING_FROM_STAT";
case SPELL_AURA_IGNORED: return "SPELL_AURA_IGNORED";
case SPELL_AURA_MOD_DETAUNT: return "SPELL_AURA_MOD_DETAUNT";
case SPELL_AURA_222: return "SPELL_AURA_222";
case SPELL_AURA_RAID_PROC_FROM_CHARGE: return "SPELL_AURA_RAID_PROC_FROM_CHARGE";
case SPELL_AURA_224: return "SPELL_AURA_224";
@@ -672,11 +672,12 @@ struct boss_nefarian : public BossAI
case EVENT_CLASSCALL:
if (classesPresent.empty())
{
for (auto& ref : me->GetThreatMgr().GetThreatList())
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
if (ref->getTarget() && ref->getTarget()->IsPlayer())
if (Unit* victim = ref->GetVictim())
{
classesPresent.insert(ref->getTarget()->getClass());
if (victim->IsPlayer())
classesPresent.insert(victim->getClass());
}
}
}
@@ -172,7 +172,9 @@ public:
if (Unit* charmer = ObjectAccessor::GetUnit(*me, _charmerGUID))
{
charmer->RemoveAurasDueToSpell(SPELL_MINDCONTROL_VISUAL);
me->TauntApply(charmer);
me->EngageWithTarget(charmer);
me->AddThreat(charmer, 100.0f);
me->AI()->AttackStart(charmer);
}
}
}
@@ -237,7 +237,7 @@ public:
void EnterEvadeMode(EvadeReason why) override
{
if (!me->GetThreatMgr().GetThreatList().empty())
if (!me->GetThreatMgr().IsThreatListEmpty())
{
if (!_processingMagmaBurst)
{
@@ -389,18 +389,13 @@ class spell_midnight_fixate : public AuraScript
{
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
{
caster->TauntApply(target);
}
caster->GetThreatMgr().FixateTarget(target);
}
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
{
caster->TauntFadeOut(target);
}
caster->GetThreatMgr().ClearFixate();
}
void Register() override
@@ -239,16 +239,14 @@ struct boss_priestess_lackey_commonAI : public ScriptedAI
void RecalculateThreat()
{
ThreatContainer::StorageType const& tList = me->GetThreatMgr().GetThreatList();
for (auto const& ref : tList)
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
Unit* pUnit = ObjectAccessor::GetUnit(*me, ref->getUnitGuid());
Unit* pUnit = ref->GetVictim();
if (pUnit && pUnit->IsPlayer() && me->GetThreatMgr().GetThreat(pUnit))
{
float threatMod = GetThreatMod(me->GetDistance2d(pUnit), (float)pUnit->GetArmor(), pUnit->GetHealth(), pUnit->GetMaxHealth(), pUnit);
me->GetThreatMgr().ModifyThreatByPercent(pUnit, -100);
if (HostileReference* ref = me->GetThreatMgr().GetOnlineContainer().getReferenceByTarget(pUnit))
ref->AddThreat(10000000.0f * threatMod);
me->GetThreatMgr().ResetThreat(pUnit);
me->GetThreatMgr().AddThreat(pUnit, 10000000.0f * threatMod, nullptr, true, true);
}
}
}
@@ -254,14 +254,13 @@ class spell_scholomance_fixate_aura : public AuraScript
{
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
caster->TauntApply(target);
caster->GetThreatMgr().FixateTarget(target);
}
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* target = GetTarget();
if (Unit* caster = GetCaster())
caster->TauntFadeOut(target);
caster->GetThreatMgr().ClearFixate();
}
void Register() override
@@ -339,10 +338,9 @@ public:
Unit* SelectUnitCasting()
{
ThreatContainer::StorageType threatlist = me->GetThreatMgr().GetThreatList();
for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
if (Unit* unit = ref->GetVictim())
{
if (unit->HasUnitState(UNIT_STATE_CASTING))
{
@@ -83,14 +83,14 @@ struct boss_hazzarah : public BossAI
{
if (me->GetThreatMgr().GetThreatListSize() > 1)
{
ThreatContainer::StorageType::const_iterator lastRef = me->GetThreatMgr().GetOnlineContainer().GetThreatList().end();
--lastRef;
if (Unit* lastTarget = (*lastRef)->getTarget())
// Check if target is the lowest threat (last in sorted list)
ThreatReference const* lowestRef = nullptr;
for (ThreatReference const* ref : me->GetThreatMgr().GetSortedThreatList())
lowestRef = ref; // Last iteration will have the lowest threat target
if (lowestRef && lowestRef->GetVictim() != target)
{
if (lastTarget != target)
{
return !target->HasAura(SPELL_SLEEP);
}
return !target->HasAura(SPELL_SLEEP);
}
}
@@ -470,10 +470,10 @@ public:
case EVENT_CLEAVE:
{
std::list<Unit*> meleeRangeTargets;
auto i = me->GetThreatMgr().GetThreatList().begin();
for (; i != me->GetThreatMgr().GetThreatList().end(); ++i)
auto i = me->GetThreatMgr().GetUnsortedThreatList().begin();
for (; i != me->GetThreatMgr().GetUnsortedThreatList().end(); ++i)
{
Unit* target = (*i)->getTarget();
Unit* target = (*i)->GetVictim();
if (me->IsWithinMeleeRange(target))
{
meleeRangeTargets.push_back(target);
@@ -80,14 +80,14 @@ public:
{
if (me->GetThreatMgr().GetThreatListSize() > 1)
{
ThreatContainer::StorageType::const_iterator lastRef = me->GetThreatMgr().GetOnlineContainer().GetThreatList().end();
--lastRef;
if (Unit* lastTarget = (*lastRef)->getTarget())
// Check if target is the lowest threat (last in sorted list)
ThreatReference const* lowestRef = nullptr;
for (ThreatReference const* ref : me->GetThreatMgr().GetSortedThreatList())
lowestRef = ref; // Last iteration will have the lowest threat target
if (lowestRef && lowestRef->GetVictim() != target)
{
if (lastTarget != target)
{
return !target->HasAura(SPELL_GOUGE);
}
return !target->HasAura(SPELL_GOUGE);
}
}
@@ -161,10 +161,9 @@ public:
if (_thousandBladesTargets.empty())
{
std::vector<Unit*> targetList;
ThreatContainer::StorageType const& threatlist = me->GetThreatMgr().GetThreatList();
for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
if (Unit* target = (*itr)->getTarget())
if (Unit* target = ref->GetVictim())
{
if (target->IsAlive() && target->IsWithinDist2d(me, 100.f))
{
@@ -270,7 +270,7 @@ struct boss_ouro : public BossAI
void EnterEvadeMode(EvadeReason /*why*/) override
{
if (me->GetThreatMgr().GetThreatList().empty())
if (me->GetThreatMgr().IsThreatListEmpty())
{
DoCastSelf(SPELL_OURO_SUBMERGE_VISUAL);
me->DespawnOrUnsummon(1s);
@@ -235,9 +235,10 @@ struct boss_hadronox : public BossAI
bool IsInCombatWithPlayer() const
{
return std::ranges::any_of(me->GetThreatMgr().GetThreatList(), [](auto const& ref) {
return ref->getTarget()->IsControlledByPlayer();
});
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
if (ref->GetVictim()->IsControlledByPlayer())
return true;
return false;
}
void DamageTaken(Unit* who, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override
@@ -1080,7 +1080,7 @@ class spell_halion_twilight_phasing_aura : public AuraScript
GetTarget()->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
GetTarget()->ToCreature()->SetReactState(REACT_DEFENSIVE);
GetTarget()->GetMotionMaster()->Clear();
GetTarget()->GetThreatMgr().clearReferences();
GetTarget()->GetThreatMgr().ClearAllThreat();
GetTarget()->RemoveAllAttackers();
GetTarget()->AttackStop();
}
@@ -1090,7 +1090,7 @@ class spell_halion_twilight_phasing_aura : public AuraScript
GetTarget()->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
GetTarget()->ToCreature()->SetReactState(REACT_DEFENSIVE);
GetTarget()->GetMotionMaster()->Clear();
GetTarget()->GetThreatMgr().clearReferences();
GetTarget()->GetThreatMgr().ClearAllThreat();
GetTarget()->RemoveAllAttackers();
GetTarget()->AttackStop();
}
@@ -138,7 +138,7 @@ public:
me->SetFaction(FACTION_FRIENDLY);
events.Reset();
Talk(SAY_EADRIC_DEFEATED);
me->GetThreatMgr().clearReferences();
me->GetThreatMgr().ClearAllThreat();
me->SetRegeneratingHealth(false);
_EnterEvadeMode();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
@@ -281,7 +281,7 @@ public:
me->SetFaction(FACTION_FRIENDLY);
events.Reset();
Talk(SAY_PALETRESS_DEFEATED);
me->GetThreatMgr().clearReferences();
me->GetThreatMgr().ClearAllThreat();
me->SetRegeneratingHealth(false);
_EnterEvadeMode();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
@@ -143,7 +143,6 @@ public:
void Reset() override
{
me->SetReactState(REACT_PASSIVE);
me->getHostileRefMgr().setOnlineOfflineState(false);
}
void OnCharmed(bool apply) override
@@ -103,17 +103,14 @@ struct boss_faction_championsAI : public ScriptedAI
void RecalculateThreat()
{
ThreatContainer::StorageType const& tList = me->GetThreatMgr().GetThreatList();
for( ThreatContainer::StorageType::const_iterator itr = tList.begin(); itr != tList.end(); ++itr )
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
Unit* pUnit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
Unit* pUnit = ref->GetVictim();
if (pUnit && pUnit->IsPlayer() && me->GetThreatMgr().GetThreat(pUnit))
{
float threatMod = GetThreatMod(me->GetDistance2d(pUnit), (float)pUnit->GetArmor(), pUnit->GetHealth(), pUnit->GetMaxHealth(), pUnit);
me->GetThreatMgr().ModifyThreatByPercent(pUnit, -100);
//me->getThreatMgr().DoAddThreat(pUnit, 10000000.0f * threatMod);
if (HostileReference* ref = me->GetThreatMgr().GetOnlineContainer().getReferenceByTarget(pUnit))
ref->AddThreat(10000000.0f * threatMod);
me->GetThreatMgr().ResetThreat(pUnit);
me->GetThreatMgr().AddThreat(pUnit, 10000000.0f * threatMod, nullptr, true, true);
}
}
}
@@ -179,27 +176,23 @@ struct boss_faction_championsAI : public ScriptedAI
uint32 EnemiesInRange(float distance)
{
ThreatContainer::StorageType const& tList = me->GetThreatMgr().GetThreatList();
uint32 count = 0;
Unit* target;
for( ThreatContainer::StorageType::const_iterator iter = tList.begin(); iter != tList.end(); ++iter )
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
target = ObjectAccessor::GetUnit((*me), (*iter)->getUnitGuid());
if (target && me->GetDistance2d(target) < distance )
++count;
if (Unit* target = ref->GetVictim())
if (me->GetDistance2d(target) < distance)
++count;
}
return count;
}
Unit* SelectEnemyCaster(bool casting, float range)
{
ThreatContainer::StorageType const& tList = me->GetThreatMgr().GetThreatList();
Unit* target;
for( ThreatContainer::StorageType::const_iterator iter = tList.begin(); iter != tList.end(); ++iter )
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
target = ObjectAccessor::GetUnit((*me), (*iter)->getUnitGuid());
if (target && target->getPowerType() == POWER_MANA && (!casting || target->HasUnitState(UNIT_STATE_CASTING)) && me->GetExactDist(target) <= range )
return target;
if (Unit* target = ref->GetVictim())
if (target->getPowerType() == POWER_MANA && (!casting || target->HasUnitState(UNIT_STATE_CASTING)) && me->GetExactDist(target) <= range)
return target;
}
return nullptr;
}
@@ -980,7 +980,7 @@ public:
for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
if (Player* p = itr->GetSource())
if (!p->IsGameMaster())
p->SetInCombatState(true);
p->SetInCombatWith(me);
_events.ScheduleEvent(EVENT_KEEP_PLAYER_IN_COMBAT, 4s);
}
break;
@@ -1319,7 +1319,7 @@ public:
for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
if (Player* p = itr->GetSource())
if (!p->IsGameMaster())
p->SetInCombatState(true);
p->SetInCombatWith(me);
_events.ScheduleEvent(EVENT_KEEP_PLAYER_IN_COMBAT, 4s);
}
break;
@@ -301,13 +301,13 @@ public:
if (events.GetPhaseMask() & PHASE_ONE_MASK && damage >= me->GetPower(POWER_MANA))
{
// reset threat
ThreatContainer::StorageType const& threatlist = me->GetThreatMgr().GetThreatList();
for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
Unit* unit = ObjectAccessor::GetUnit((*me), (*itr)->getUnitGuid());
if (unit && DoGetThreat(unit))
DoModifyThreatByPercent(unit, -100);
if (Unit* unit = ref->GetVictim())
{
if (DoGetThreat(unit))
DoModifyThreatByPercent(unit, -100);
}
}
Talk(SAY_PHASE_2);
@@ -209,7 +209,7 @@ public:
bool operator()(Unit const* target) const
{
if (!me || !target || !target->IsPlayer() || target == me->GetThreatMgr().GetCurrentVictim())
if (!me || !target || !target->IsPlayer() || target == me->GetThreatMgr().GetLastVictim())
return false;
if (me->IsWithinCombatRange(target, 7.0f))
@@ -498,7 +498,7 @@ public:
bool Execute(uint64 /*time*/, uint32 /*diff*/) override
{
_owner->SetReactState(REACT_AGGRESSIVE);
if (!_owner->GetThreatMgr().isThreatListEmpty())
if (!_owner->GetThreatMgr().IsThreatListEmpty())
if (Unit* target = _owner->SelectVictim())
_owner->AI()->AttackStart(target);
if (!_owner->GetVictim())
@@ -1180,7 +1180,7 @@ public:
{
if (summon->GetEntry() == NPC_VILE_SPIRIT)
{
summon->m_Events.KillAllEvents(true);
summon->m_Events.KillAllEvents(false);
summon->m_Events.AddEventAtOffset(new VileSpiritActivateEvent(summon), 55s);
summon->GetMotionMaster()->Clear(true);
summon->StopMoving();
@@ -2273,7 +2273,7 @@ public:
{
me->SetControlled(false, UNIT_STATE_ROOT);
if (!me->GetThreatMgr().isThreatListEmpty())
if (!me->GetThreatMgr().IsThreatListEmpty())
if (Unit* target = me->SelectVictim())
AttackStart(target);
if (!me->GetVictim())
@@ -593,12 +593,12 @@ public:
{
checkTimer = 3000;
me->SetInCombatWithZone();
ThreatContainer::StorageType const& threatList = me->GetThreatMgr().GetThreatList();
if (!threatList.empty())
for (ThreatContainer::StorageType::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr)
if (Unit* target = (*itr)->getTarget())
if (target->IsAlive() && target->IsPlayer() && me->GetExactDist(target) < 200.0f && !target->IsImmunedToDamageOrSchool(SPELL_SCHOOL_MASK_ALL))
return;
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
if (Unit* target = ref->GetVictim())
if (target->IsAlive() && target->IsPlayer() && me->GetExactDist(target) < 200.0f && !target->IsImmunedToDamageOrSchool(SPELL_SCHOOL_MASK_ALL))
return;
}
EnterEvadeMode();
}
else
@@ -1762,15 +1762,26 @@ public:
Position myPos = me->GetPosition();
me->NearTeleportTo(c->GetPositionX(), c->GetPositionY(), c->GetPositionZ(), c->GetOrientation());
c->NearTeleportTo(myPos.GetPositionX(), myPos.GetPositionY(), myPos.GetPositionZ(), myPos.GetOrientation());
const ThreatContainer::StorageType me_tl = me->GetThreatMgr().GetThreatList();
const ThreatContainer::StorageType target_tl = c->GetThreatMgr().GetThreatList();
// Store threat values before reset
std::vector<std::pair<Unit*, float>> myThreats;
std::vector<std::pair<Unit*, float>> targetThreats;
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
if (Unit* victim = ref->GetVictim())
myThreats.push_back({victim, ref->GetThreat()});
for (ThreatReference const* ref : c->GetThreatMgr().GetUnsortedThreatList())
if (Unit* victim = ref->GetVictim())
targetThreats.push_back({victim, ref->GetThreat()});
DoResetThreatList();
for (ThreatContainer::StorageType::const_iterator iter = target_tl.begin(); iter != target_tl.end(); ++iter)
me->GetThreatMgr().AddThreat((*iter)->getTarget(), (*iter)->GetThreat());
for (auto const& pair : targetThreats)
me->GetThreatMgr().AddThreat(pair.first, pair.second);
c->GetThreatMgr().ResetAllThreat();
for (ThreatContainer::StorageType::const_iterator iter = me_tl.begin(); iter != me_tl.end(); ++iter)
c->GetThreatMgr().AddThreat((*iter)->getTarget(), (*iter)->GetThreat());
for (auto const& pair : myThreats)
c->GetThreatMgr().AddThreat(pair.first, pair.second);
}
}
@@ -406,16 +406,19 @@ public:
events.Repeat(15s);
break;
case EVENT_TELEPORT:
{
me->AttackStop();
if (IN_LIVE_SIDE(me))
{
me->CastSpell(me, SPELL_TELEPORT_DEAD, false);
}
else
{
me->CastSpell(me, SPELL_TELEPORT_LIVE, false);
}
me->GetThreatMgr().resetAggro(NotOnSameSide(me));
// Clear threat from targets not on the same side as Gothik
NotOnSameSide notOnSameSide(me);
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
if (notOnSameSide(ref->GetVictim()))
me->GetThreatMgr().ClearThreat(ref->GetVictim());
if (Unit* pTarget = SelectTarget(SelectTargetMethod::MaxDistance, 0))
{
me->GetThreatMgr().AddThreat(pTarget, 100.0f);
@@ -423,6 +426,7 @@ public:
}
events.Repeat(20s);
break;
}
case EVENT_CHECK_HEALTH:
if (me->HealthBelowPct(30))
{
@@ -401,15 +401,17 @@ public:
case EVENT_DETONATE_MANA:
{
std::vector<Unit*> unitList;
ThreatContainer::StorageType const& threatList = me->GetThreatMgr().GetThreatList();
for (auto itr : threatList)
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
if (itr->getTarget()->IsPlayer()
&& itr->getTarget()->getPowerType() == POWER_MANA
&& itr->getTarget()->GetPower(POWER_MANA))
{
unitList.push_back(itr->getTarget());
}
if (Unit* target = ref->GetVictim())
{
if (target->IsPlayer()
&& target->getPowerType() == POWER_MANA
&& target->GetPower(POWER_MANA))
{
unitList.push_back(target);
}
}
}
if (!unitList.empty())
{
@@ -117,11 +117,11 @@ public:
std::list<Unit*> meleeRangeTargets;
Unit* finalTarget = nullptr;
uint8 counter = 0;
auto i = me->GetThreatMgr().GetThreatList().begin();
for (; i != me->GetThreatMgr().GetThreatList().end(); ++i, ++counter)
auto threatList = me->GetThreatMgr().GetSortedThreatList();
for (auto i = threatList.begin(); i != threatList.end(); ++i, ++counter)
{
// Gather all units with melee range
Unit* target = (*i)->getTarget();
Unit* target = (*i)->GetVictim();
if (me->IsWithinMeleeRange(target))
{
meleeRangeTargets.push_back(target);
@@ -315,17 +315,17 @@ public:
}
std::vector<Unit*> targets;
auto i = me->GetThreatMgr().GetThreatList().begin();
for (; i != me->GetThreatMgr().GetThreatList().end(); ++i)
auto i = me->GetThreatMgr().GetUnsortedThreatList().begin();
for (; i != me->GetThreatMgr().GetUnsortedThreatList().end(); ++i)
{
if ((*i)->getTarget()->IsPlayer())
if ((*i)->GetVictim()->IsPlayer())
{
bool inList = false;
if (!blockList.empty())
{
for (GuidList::const_iterator itr = blockList.begin(); itr != blockList.end(); ++itr)
{
if ((*i)->getTarget()->GetGUID() == *itr)
if ((*i)->GetVictim()->GetGUID() == *itr)
{
inList = true;
break;
@@ -334,7 +334,7 @@ public:
}
if (!inList)
{
targets.push_back((*i)->getTarget());
targets.push_back((*i)->GetVictim());
}
}
}
@@ -128,8 +128,8 @@ public:
bool IsAnyPlayerInMeleeRange() const
{
for (auto const& ref : me->GetThreatMgr().GetThreatList())
if (Unit* target = ref->getTarget())
for (auto const* ref : me->GetThreatMgr().GetUnsortedThreatList())
if (Unit* target = ref->GetVictim())
if (target->IsPlayer() && me->IsWithinMeleeRange(target))
return true;
return false;
@@ -1419,7 +1419,7 @@ public:
{
me->CastSpell(me, SPELL_SAC_GHOUL_EXPLODE, true);
me->KillSelf();
me->m_Events.KillAllEvents(true);
me->m_Events.KillAllEvents(false);
Deactivate();
}
}
@@ -85,15 +85,16 @@ struct boss_blackheart_the_inciter : public BossAI
DoCastAOE(SPELL_INCITE_CHAOS);
DoCastSelf(SPELL_LAUGHTER, true);
uint32 inciteTriggerID = NPC_INCITE_TRIGGER;
std::list<HostileReference*> t_list = me->GetThreatMgr().GetThreatList();
for (std::list<HostileReference*>::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr)
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
if (target && target->IsPlayer())
if (Unit* target = ref->GetVictim())
{
if (Creature* inciteTrigger = me->SummonCreature(inciteTriggerID++, *target, TEMPSUMMON_TIMED_DESPAWN, 15 * IN_MILLISECONDS))
if (target->IsPlayer())
{
inciteTrigger->CastSpell(target, SPELL_INCITE_CHAOS_B, true);
if (Creature* inciteTrigger = me->SummonCreature(inciteTriggerID++, *target, TEMPSUMMON_TIMED_DESPAWN, 15 * IN_MILLISECONDS))
{
inciteTrigger->CastSpell(target, SPELL_INCITE_CHAOS_B, true);
}
}
}
}
@@ -87,7 +87,7 @@ struct boss_murmur : public BossAI
void EnterEvadeMode(EvadeReason why) override
{
if (me->GetThreatMgr().GetThreatList().empty())
if (me->GetThreatMgr().IsThreatListEmpty())
{
BossAI::EnterEvadeMode(why);
}
@@ -1104,7 +1104,7 @@ struct npc_maiev_illidan : public ScriptedAI
void Reset() override
{
scheduler.CancelAll();
me->m_Events.KillAllEvents(true);
me->m_Events.KillAllEvents(false);
}
void DoAction(int32 param) override
@@ -168,13 +168,14 @@ struct boss_supremus : public BossAI
Unit* FindHatefulStrikeTarget()
{
Unit* target = nullptr;
ThreatContainer::StorageType const& threatlist = me->GetThreatMgr().GetThreatList();
for (ThreatContainer::StorageType::const_iterator i = threatlist.begin(); i != threatlist.end(); ++i)
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
Unit* unit = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid());
if (unit && me->IsWithinMeleeRange(unit))
if (!target || unit->GetHealth() > target->GetHealth())
target = unit;
if (Unit* unit = ref->GetVictim())
{
if (me->IsWithinMeleeRange(unit))
if (!target || unit->GetHealth() > target->GetHealth())
target = unit;
}
}
return target;
@@ -215,8 +215,9 @@ class spell_black_template_harpooners_mark_aura : public AuraScript
GetUnitOwner()->GetCreaturesWithEntryInRange(creatureList, 80.0f, NPC_DRAGON_TURTLE);
for (std::list<Creature*>::const_iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
{
(*itr)->TauntApply(GetUnitOwner());
(*itr)->AddThreat(GetUnitOwner(), 10000000.0f);
if ((*itr)->AI())
(*itr)->AI()->AttackStart(GetUnitOwner());
_turtleSet.insert((*itr)->GetGUID());
}
}
@@ -226,7 +227,6 @@ class spell_black_template_harpooners_mark_aura : public AuraScript
for (ObjectGuid const& guid : _turtleSet)
if (Creature* turtle = ObjectAccessor::GetCreature(*GetUnitOwner(), guid))
{
turtle->TauntFadeOut(GetUnitOwner());
turtle->AddThreat(GetUnitOwner(), -10000000.0f);
}
}
@@ -212,10 +212,9 @@ struct boss_the_lurker_below : public BossAI
}
else
{
ThreatContainer::StorageType const& t_list = me->GetThreatMgr().GetThreatList();
for (ThreatReference const* ref : t_list)
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
if (Unit* threatTarget = ObjectAccessor::GetUnit(*me, ref->getUnitGuid()))
if (Unit* threatTarget = ref->GetVictim())
{
if (me->IsWithinMeleeRange(threatTarget))
{
@@ -172,7 +172,7 @@ struct boss_alar : public BossAI
{
if (why == EVADE_REASON_BOUNDARY)
BossAI::EnterEvadeMode(why);
else if (me->GetThreatMgr().GetThreatList().empty())
else if (me->GetThreatMgr().IsThreatListEmpty())
BossAI::EnterEvadeMode(why);
}
@@ -1083,13 +1083,14 @@ class spell_kaelthas_nether_beam : public SpellScript
{
PreventHitEffect(effIndex);
ThreatContainer::StorageType const& ThreatList = GetCaster()-> GetThreatMgr().GetThreatList();
std::list<Unit*> targetList;
for (ThreatContainer::StorageType::const_iterator itr = ThreatList.begin(); itr != ThreatList.end(); ++itr)
for (ThreatReference const* ref : GetCaster()->GetThreatMgr().GetUnsortedThreatList())
{
Unit* target = ObjectAccessor::GetUnit(*GetCaster(), (*itr)->getUnitGuid());
if (target && target->IsPlayer())
targetList.push_back(target);
if (Unit* target = ref->GetVictim())
{
if (target->IsPlayer())
targetList.push_back(target);
}
}
Acore::Containers::RandomResize(targetList, 5);
@@ -59,8 +59,9 @@ class spell_botanica_call_of_the_falcon_aura : public AuraScript
GetUnitOwner()->GetCreaturesWithEntryInRange(creatureList, 80.0f, NPC_BLOODFALCON);
for (std::list<Creature*>::const_iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr)
{
(*itr)->TauntApply(GetUnitOwner());
(*itr)->AddThreat(GetUnitOwner(), 10000000.0f);
if ((*itr)->AI())
(*itr)->AI()->AttackStart(GetUnitOwner());
_falconSet.insert((*itr)->GetGUID());
}
}
@@ -70,7 +71,6 @@ class spell_botanica_call_of_the_falcon_aura : public AuraScript
for (ObjectGuid const& guid : _falconSet)
if (Creature* falcon = ObjectAccessor::GetCreature(*GetUnitOwner(), guid))
{
falcon->TauntFadeOut(GetUnitOwner());
falcon->AddThreat(GetUnitOwner(), -10000000.0f);
}
}
@@ -195,7 +195,6 @@ public:
if (Creature* Target = GetClosestCreatureWithEntry(me, NPC_DEATHS_DOOR_FEL_CANNON_TARGET_BUNNY, 200.0f))
{
me->SetFacingToObject(Target);
me->TauntFadeOut(Target);
me->CombatStop(); // force
}
+1 -1
View File
@@ -184,7 +184,7 @@ class spell_pet_guard_dog : public AuraScript
return;
float addThreat = CalculatePct(static_cast<float>(procSpellInfo->Effects[EFFECT_0].CalcValue(caster)), aurEff->GetAmount());
target->GetThreatMgr().AddThreat(caster, addThreat, SPELL_SCHOOL_MASK_NORMAL, GetSpellInfo());
target->GetThreatMgr().AddThreat(caster, addThreat, GetSpellInfo());
}
void Register() override
+3 -5
View File
@@ -106,12 +106,10 @@ struct npc_pet_mage_mirror_image : CasterAI
// Xinef: Inherit Master's Threat List (not yet implemented)
//owner->CastSpell((Unit*)nullptr, SPELL_MAGE_MASTERS_THREAT_LIST, true);
HostileReference* ref = owner->getHostileRefMgr().getFirst();
while (ref)
for (auto const& pair : owner->GetThreatMgr().GetThreatenedByMeList())
{
if (Unit* unit = ref->GetSource()->GetOwner())
unit->AddThreat(me, ref->GetThreat() - ref->getTempThreatModifier());
ref = ref->next();
if (Unit* unit = pair.second->GetOwner())
unit->GetThreatMgr().AddThreat(me, pair.second->GetThreat());
}
_ebonGargoyleGUID.Clear();
+15
View File
@@ -673,6 +673,20 @@ class spell_dk_dancing_rune_weapon : public AuraScript
{
PrepareAuraScript(spell_dk_dancing_rune_weapon);
void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* caster = GetCaster();
if (!caster)
return;
// Redirect 100% of the DRW's threat to the DK player
uint32 npcEntry = GetSpellInfo()->Effects[EFFECT_0].MiscValue;
std::list<Creature*> runeWeapons;
caster->GetAllMinionsByEntry(runeWeapons, npcEntry);
for (Creature* temp : runeWeapons)
temp->GetThreatMgr().RegisterRedirectThreat(GetId(), caster->GetGUID(), 100);
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (!eventInfo.GetActor() || !eventInfo.GetActionTarget() || !eventInfo.GetActionTarget()->IsAlive() || !eventInfo.GetActor()->IsPlayer())
@@ -749,6 +763,7 @@ class spell_dk_dancing_rune_weapon : public AuraScript
void Register() override
{
AfterEffectApply += AuraEffectApplyFn(spell_dk_dancing_rune_weapon::HandleApply, EFFECT_2, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
DoCheckProc += AuraCheckProcFn(spell_dk_dancing_rune_weapon::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_dk_dancing_rune_weapon::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
}
+4 -3
View File
@@ -52,6 +52,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,
@@ -893,7 +894,7 @@ class spell_hun_misdirection : public AuraScript
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT || !GetTarget()->HasAura(SPELL_HUNTER_MISDIRECTION_PROC))
GetTarget()->ResetRedirectThreat();
GetTarget()->GetThreatMgr().UnregisterRedirectThreat(SPELL_HUNTER_MISDIRECTION);
}
bool CheckProc(ProcEventInfo& eventInfo)
@@ -902,7 +903,7 @@ class spell_hun_misdirection : public AuraScript
if ((eventInfo.GetProcSpell() && (eventInfo.GetProcSpell()->GetSpellInfo()->SpellFamilyFlags[0] & 0x800000)) || (eventInfo.GetHealInfo() && (eventInfo.GetHealInfo()->GetSpellInfo()->SpellFamilyFlags[0] & 0x800000)))
return false;
return GetTarget()->GetRedirectThreatTarget();
return GetTarget()->GetThreatMgr().HasRedirects();
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
@@ -926,7 +927,7 @@ class spell_hun_misdirection_proc : public AuraScript
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->ResetRedirectThreat();
GetTarget()->GetThreatMgr().UnregisterRedirectThreat(SPELL_HUNTER_MISDIRECTION);
}
void Register() override
+2 -3
View File
@@ -915,9 +915,8 @@ class spell_pri_mind_control : public AuraScript
{
if (Unit* target = GetTarget())
{
uint32 duration = static_cast<uint32>(GetDuration());
caster->SetInCombatWith(target, duration);
target->SetInCombatWith(caster, duration);
caster->SetInCombatWith(target);
target->SetInCombatWith(caster);
}
}
}
+45 -29
View File
@@ -42,6 +42,7 @@ enum RogueSpells
SPELL_ROGUE_KILLING_SPREE_DMG_BUFF = 61851,
SPELL_ROGUE_PREY_ON_THE_WEAK = 58670,
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,
// Proc system spells
@@ -616,53 +617,68 @@ class spell_rog_shiv : public SpellScript
}
};
// 57934 - Tricks of the Trade
class spell_rog_tricks_of_the_trade : public AuraScript
// 57934 - Tricks of the Trade (AuraScript)
class spell_rog_tricks_of_the_trade_aura : public AuraScript
{
PrepareAuraScript(spell_rog_tricks_of_the_trade);
PrepareAuraScript(spell_rog_tricks_of_the_trade_aura);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST, SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC });
}
bool Load() override
{
_redirectTarget = nullptr;
return true;
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT)
GetTarget()->ResetRedirectThreat();
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEFAULT || !GetTarget()->HasAura(SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC))
GetTarget()->GetThreatMgr().UnregisterRedirectThreat(SPELL_ROGUE_TRICKS_OF_THE_TRADE);
}
bool CheckProc(ProcEventInfo& /*eventInfo*/)
{
_redirectTarget = GetTarget()->GetRedirectThreatTarget();
return _redirectTarget;
}
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
{
PreventDefaultAction();
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
Unit* rogue = GetTarget();
Unit* target = ObjectAccessor::GetUnit(*rogue, _redirectTarget);
if (target)
{
rogue->CastSpell(target, SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST, true, nullptr, aurEff);
rogue->CastSpell(rogue, SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC, true, nullptr, aurEff);
}
Remove(AURA_REMOVE_BY_DEFAULT);
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_rog_tricks_of_the_trade::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
DoCheckProc += AuraCheckProcFn(spell_rog_tricks_of_the_trade::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_rog_tricks_of_the_trade::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
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);
}
private:
Unit* _redirectTarget;
ObjectGuid _redirectTarget;
public:
void SetRedirectTarget(ObjectGuid const& guid) { _redirectTarget = guid; }
};
// 57934 - Tricks of the Trade (SpellScript)
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"))
{
if (Unit* explTarget = GetExplTargetUnit())
script->SetRedirectTarget(explTarget->GetGUID());
else
script->SetRedirectTarget(ObjectGuid::Empty);
}
}
void Register() override
{
AfterHit += SpellHitFn(spell_rog_tricks_of_the_trade::DoAfterHit);
}
};
// 59628 - Tricks of the Trade (Proc)
@@ -672,7 +688,7 @@ class spell_rog_tricks_of_the_trade_proc : public AuraScript
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->ResetRedirectThreat();
GetTarget()->GetThreatMgr().UnregisterRedirectThreat(SPELL_ROGUE_TRICKS_OF_THE_TRADE);
}
void Register() override
@@ -1162,7 +1178,7 @@ void AddSC_rogue_spell_scripts()
RegisterSpellScript(spell_rog_prey_on_the_weak);
RegisterSpellScript(spell_rog_rupture);
RegisterSpellScript(spell_rog_shiv);
RegisterSpellScript(spell_rog_tricks_of_the_trade);
RegisterSpellAndAuraScriptPair(spell_rog_tricks_of_the_trade, spell_rog_tricks_of_the_trade_aura);
RegisterSpellScript(spell_rog_tricks_of_the_trade_proc);
RegisterSpellScript(spell_rog_pickpocket);
RegisterSpellScript(spell_rog_vanish_purge);
+1 -1
View File
@@ -748,7 +748,7 @@ class spell_warr_vigilance : public AuraScript
target->RemoveAurasDueToSpell(SPELL_GEN_DAMAGE_REDUCTION_AURA);
}
target->ResetRedirectThreat();
target->GetThreatMgr().UnregisterRedirectThreat(SPELL_WARRIOR_VIGILANCE_REDIRECT_THREAT, GetCasterGUID());
}
bool CheckProc(ProcEventInfo& /*eventInfo*/)
@@ -320,13 +320,13 @@ public:
{
Talk(SAY_YSONDRE_SUMMON_DRUIDS);
auto const& attackers = me->GetThreatMgr().GetThreatList();
uint8 attackersCount = 0;
for (const auto attacker : attackers)
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
if ((*attacker)->ToPlayer() && (*attacker)->IsAlive())
++attackersCount;
if (Unit* victim = ref->GetVictim())
if (victim->ToPlayer() && victim->IsAlive())
++attackersCount;
}
uint8 amount = attackersCount < 30 ? attackersCount * 0.5f : 15;
@@ -53,11 +53,14 @@ void NPCStaveQuestAI::StorePlayerGUID()
return;
}
for (ThreatContainer::StorageType::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr)
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
if ((*itr)->getTarget()->IsPlayer())
if (Unit* target = ref->GetVictim())
{
playerGUID = (*itr)->getUnitGuid();
if (target->IsPlayer())
{
playerGUID = target->GetGUID();
}
}
}
}
@@ -107,18 +110,16 @@ bool NPCStaveQuestAI::UnitIsUnfair(Unit* unit)
bool NPCStaveQuestAI::IsFairFight()
{
for (ThreatContainer::StorageType::const_iterator itr = threatList.begin(); itr != threatList.end(); ++itr)
for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList())
{
Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
if (!(*itr)->GetThreat())
if (!ref->GetThreat())
{
// if target threat is 0 its fair, this prevents despawn in the case when
// there is a bystander since UpdateVictim adds nearby enemies to the threatlist
continue;
}
if (UnitIsUnfair(unit))
if (UnitIsUnfair(ref->GetVictim()))
{
return false;
}
@@ -129,7 +130,7 @@ bool NPCStaveQuestAI::IsFairFight()
bool NPCStaveQuestAI::ValidThreatlist()
{
if (threatList.size() == 1)
if (me->GetThreatMgr().GetThreatListSize() == 1)
{
return true;
}
@@ -232,7 +233,7 @@ void NPCStaveQuestAI::ResetState(uint32 aura = 0)
if (InNormalForm())
{
me->m_Events.KillAllEvents(true);
me->m_Events.KillAllEvents(false);
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
}
@@ -137,7 +137,6 @@ struct NPCStaveQuestAI : public ScriptedAI
ObjectGuid gossipPlayerGUID;
ObjectGuid playerGUID;
bool encounterStarted;
ThreatContainer::StorageType const& threatList = me->GetThreatMgr().GetThreatList();
std::map<int, int> entryKeys = {
{ ARTORIUS_NORMAL_ENTRY, 1 },
+62 -100
View File
@@ -312,123 +312,85 @@ public:
}
};
enum eTrainingDummy
struct npc_training_dummy : NullCreatureAI
{
SPELL_STUN_PERMANENT = 61204
};
npc_training_dummy(Creature* creature) : NullCreatureAI(creature) { }
class npc_training_dummy : public CreatureScript
{
public:
npc_training_dummy() : CreatureScript("npc_training_dummy") { }
struct npc_training_dummyAI : ScriptedAI
void JustEnteredCombat(Unit* who) override
{
npc_training_dummyAI(Creature* creature) : ScriptedAI(creature)
_combatTimer[who->GetGUID()] = 5s;
}
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType damageType, SpellSchoolMask) override
{
damage = 0;
if (!attacker || damageType == DOT)
return;
_combatTimer[attacker->GetGUID()] = 5s;
}
void UpdateAI(uint32 diff) override
{
for (auto itr = _combatTimer.begin(); itr != _combatTimer.end();)
{
me->SetCombatMovement(false);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); //imune to knock aways like blast wave
}
uint32 resetTimer;
void Reset() override
{
me->CastSpell(me, SPELL_STUN_PERMANENT, true);
resetTimer = 5000;
}
void EnterEvadeMode(EvadeReason why) override
{
if (!_EnterEvadeMode(why))
return;
Reset();
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
resetTimer = 5000;
damage = 0;
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (resetTimer <= diff)
itr->second -= Milliseconds(diff);
if (itr->second <= 0s)
{
EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
resetTimer = 5000;
// The attacker has not dealt any damage to the dummy for over 5 seconds. End combat.
auto const& pveRefs = me->GetCombatManager().GetPvECombatRefs();
auto it = pveRefs.find(itr->first);
if (it != pveRefs.end())
it->second->EndCombat();
itr = _combatTimer.erase(itr);
}
else
resetTimer -= diff;
++itr;
}
void MoveInLineOfSight(Unit* /*who*/) override { }
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_training_dummyAI(creature);
}
private:
std::unordered_map<ObjectGuid, Milliseconds> _combatTimer;
};
class npc_target_dummy : public CreatureScript
struct npc_target_dummy : NullCreatureAI
{
public:
npc_target_dummy() : CreatureScript("npc_target_dummy") { }
struct npc_target_dummyAI : ScriptedAI
npc_target_dummy(Creature* creature) : NullCreatureAI(creature)
{
npc_target_dummyAI(Creature* creature) : ScriptedAI(creature)
{
me->SetCombatMovement(false);
deathTimer = 15000;
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); //imune to knock aways like blast wave
}
_deathTimer = 15s;
}
uint32 deathTimer;
void Reset() override
{
me->SetControlled(true, UNIT_STATE_STUNNED);
me->SetLootRecipient(me->GetOwner());
me->SelectLevel();
}
void Reset() override
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
damage = 0;
}
void UpdateAI(uint32 diff) override
{
if (!me->HasUnitState(UNIT_STATE_STUNNED))
me->SetControlled(true, UNIT_STATE_STUNNED);
_deathTimer -= Milliseconds(diff);
if (_deathTimer <= 0s)
{
me->SetControlled(true, UNIT_STATE_STUNNED); //disable rotate
me->SetLootRecipient(me->GetOwner());
me->SelectLevel();
me->LowerPlayerDamageReq(me->GetMaxHealth());
me->KillSelf();
_deathTimer = 600s;
}
void EnterEvadeMode(EvadeReason why) override
{
if (!_EnterEvadeMode(why))
return;
Reset();
}
void UpdateAI(uint32 diff) override
{
if (!me->HasUnitState(UNIT_STATE_STUNNED))
me->SetControlled(true, UNIT_STATE_STUNNED);//disable rotate
if (deathTimer <= diff)
{
me->SetLootRecipient(me->GetOwner());
me->LowerPlayerDamageReq(me->GetMaxHealth());
me->KillSelf();
deathTimer = 600000;
}
else
deathTimer -= diff;
}
void MoveInLineOfSight(Unit* /*who*/) override { }
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_target_dummyAI(creature);
}
private:
Milliseconds _deathTimer;
};
/*########
@@ -2738,8 +2700,8 @@ void AddSC_npcs_special()
{
new npc_elder_clearwater();
new npc_riggle_bassbait();
new npc_target_dummy();
new npc_training_dummy();
RegisterCreatureAI(npc_target_dummy);
RegisterCreatureAI(npc_training_dummy);
new npc_venomhide_hatchling();
new npc_air_force_bots();
new npc_chicken_cluck();