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

View File

@@ -2751,8 +2751,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
float threat = float(gain) * 0.5f;
if (caster->IsClass(CLASS_PALADIN))
threat *= 0.5f;
unitTarget->getHostileRefMgr().threatAssist(caster, threat, m_spellInfo);
unitTarget->GetThreatMgr().ForwardThreatForAssistingMe(caster, threat, m_spellInfo);
m_healing = gain;
// Xinef: if heal actually healed something, add no overheal flag
@@ -2877,8 +2876,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (missInfo == SPELL_MISS_RESIST && m_spellInfo->HasAttribute(SPELL_ATTR0_CU_PICKPOCKET) && unitTarget->IsCreature() && m_caster)
{
m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TALK);
if (unitTarget->ToCreature()->IsAIEnabled)
unitTarget->ToCreature()->AI()->AttackStart(m_caster);
unitTarget->ToCreature()->EngageWithTarget(m_caster);
}
}
@@ -2887,19 +2885,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
if (missInfo != SPELL_MISS_EVADE && !m_caster->IsFriendlyTo(effectUnit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)))
{
if (!m_triggeredByAuraSpell.spellInfo || m_damage || (!(m_triggeredByAuraSpell.spellInfo->Effects[m_triggeredByAuraSpell.effectIndex].TriggerSpell == m_spellInfo->Id) && !(m_triggeredByAuraSpell.spellInfo->IsAuraEffectEqual(m_spellInfo))))
m_caster->CombatStart(effectUnit, !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_SUPPRESS_TARGET_PROCS));
// Patch 3.0.8: All player spells which cause a creature to become aggressive to you will now also immediately cause the creature to be tapped.
if (effectUnit->IsInCombatWith(m_caster))
{
if (Creature* creature = effectUnit->ToCreature())
{
if (!creature->hasLootRecipient() && m_caster->IsPlayer())
{
creature->SetLootRecipient(m_caster);
}
}
}
m_caster->AtTargetAttacked(effectUnit, !(m_spellInfo->HasAttribute(SPELL_ATTR1_NO_THREAT) || m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS)));
// Unsure if there are more spells that are not supposed to stop enemy from
// regenerating HP from food, so for now it stays as an ID.
@@ -3036,10 +3022,11 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
}
// xinef: triggered spells should not prolong combat
if (unit->IsInCombat() && !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS) && !m_triggeredByAuraSpell)
if (m_originalCaster && unit->IsInCombat() && !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS) && !m_triggeredByAuraSpell)
{
m_caster->SetInCombatState(unit->GetCombatTimer() > 0, unit);
unit->getHostileRefMgr().threatAssist(m_caster, 0.0f);
if (m_originalCaster->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED))
m_originalCaster->GetCombatManager().InheritCombatStatesFrom(unit);
unit->GetThreatMgr().ForwardThreatForAssistingMe(m_originalCaster, 0.0f, nullptr, true);
}
}
}
@@ -4048,12 +4035,6 @@ void Spell::_cast(bool skipCheck)
if (target->IsCreature())
m_caster->CastSpell(target, 32747, true);
// xinef: start combat at cast for delayed spells, only for explicit target
if (Unit* target = m_targets.GetUnitTarget())
if (m_caster->IsPlayer() || (m_caster->IsPet() && m_caster->IsControlledByPlayer()))
if (GetDelayMoment() > 0 && !m_caster->IsFriendlyTo(target) && !m_spellInfo->HasAura(SPELL_AURA_BIND_SIGHT) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)))
m_caster->CombatStartOnCast(target, !m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS), GetDelayMoment() + 500); // xinef: increase this time so we dont leave and enter combat in a moment
if (m_caster->IsPlayer())
if (m_caster->ToPlayer()->GetCommandStatus(CHEAT_COOLDOWN))
m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true);
@@ -5558,11 +5539,13 @@ void Spell::HandleThreatSpells()
if (m_spellInfo->HasAttribute(SPELL_ATTR1_NO_THREAT) || m_spellInfo->HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS))
return;
Unit* unitCaster = m_originalCaster ? m_originalCaster : m_caster;
float threat = 0.0f;
if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(m_spellInfo->Id))
{
if (threatEntry->apPctMod != 0.0f)
threat += threatEntry->apPctMod * m_caster->GetTotalAttackPowerValue(BASE_ATTACK);
threat += threatEntry->apPctMod * unitCaster->GetTotalAttackPowerValue(BASE_ATTACK);
threat += threatEntry->flatMod;
}
@@ -5576,23 +5559,27 @@ void Spell::HandleThreatSpells()
// since 2.0.1 threat from positive effects also is distributed among all targets, so the overall caused threat is at most the defined bonus
threat /= m_UniqueTargetInfo.size();
for (std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
for (auto& ihit : m_UniqueTargetInfo)
{
float threatToAdd = threat;
if (ihit->missCondition != SPELL_MISS_NONE)
if (ihit.missCondition != SPELL_MISS_NONE)
threatToAdd = 0.0f;
Unit* target = ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
Unit* target = ObjectAccessor::GetUnit(*unitCaster, ihit.targetGUID);
if (!target)
continue;
bool IsFriendly = m_caster->IsFriendlyTo(target);
// positive spells distribute threat among all units that are in combat with target, like healing
if (m_spellInfo->_IsPositiveSpell() && IsFriendly)
target->getHostileRefMgr().threatAssist(m_caster, threatToAdd, m_spellInfo);
if (m_spellInfo->_IsPositiveSpell())
target->GetThreatMgr().ForwardThreatForAssistingMe(unitCaster, threatToAdd, m_spellInfo);
// for negative spells threat gets distributed among affected targets
else if (!m_spellInfo->_IsPositiveSpell() && !IsFriendly && target->CanHaveThreatList())
target->AddThreat(m_caster, threatToAdd, m_spellInfo->GetSchoolMask(), m_spellInfo);
// ignoreModifiers=true because flat SpellThreatEntry threat should not have modifiers applied twice
else
{
if (!target->CanHaveThreatList())
continue;
target->GetThreatMgr().AddThreat(unitCaster, threatToAdd, m_spellInfo, true);
}
}
LOG_DEBUG("spells.aura", "Spell {}, added an additional {} threat for {} {} target(s)", m_spellInfo->Id, threat, m_spellInfo->_IsPositiveSpell() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size()));
}
@@ -5772,8 +5759,7 @@ SpellCastResult Spell::CheckCast(bool strict)
if (Unit* victim = member->GetVictim())
if (victim->IsInCombat() && m_caster->GetDistance(victim) < m_caster->GetVisibilityRange())
{
m_caster->CombatStart(victim);
victim->AddThreat(m_caster, 1.0f);
m_caster->EngageWithTarget(victim);
break;
}
return SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED;