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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -2904,7 +2904,7 @@ public:
|
||||
}
|
||||
|
||||
playerTarget->CombatStop();
|
||||
playerTarget->getHostileRefMgr().deleteReferences();
|
||||
playerTarget->GetThreatMgr().RemoveMeFromThreatLists();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
+4
-3
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -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();
|
||||
}
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
-1
@@ -143,7 +143,6 @@ public:
|
||||
void Reset() override
|
||||
{
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->getHostileRefMgr().setOnlineOfflineState(false);
|
||||
}
|
||||
|
||||
void OnCharmed(bool apply) override
|
||||
|
||||
+12
-19
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
+7
-6
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user