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:
@@ -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