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:
@@ -281,7 +281,7 @@ enum AuraType
|
||||
SPELL_AURA_HASTE_RANGED = 218,
|
||||
SPELL_AURA_MOD_MANA_REGEN_FROM_STAT = 219,
|
||||
SPELL_AURA_MOD_RATING_FROM_STAT = 220,
|
||||
SPELL_AURA_IGNORED = 221,
|
||||
SPELL_AURA_MOD_DETAUNT = 221,
|
||||
SPELL_AURA_222 = 222,
|
||||
SPELL_AURA_RAID_PROC_FROM_CHARGE = 223,
|
||||
SPELL_AURA_224 = 224,
|
||||
|
||||
@@ -283,7 +283,7 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS] =
|
||||
&AuraEffect::HandleAuraModRangedHaste, //218 SPELL_AURA_HASTE_RANGED
|
||||
&AuraEffect::HandleModManaRegen, //219 SPELL_AURA_MOD_MANA_REGEN_FROM_STAT
|
||||
&AuraEffect::HandleModRatingFromStat, //220 SPELL_AURA_MOD_RATING_FROM_STAT
|
||||
&AuraEffect::HandleNoImmediateEffect, //221 SPELL_AURA_IGNORED
|
||||
&AuraEffect::HandleModDetaunt, //221 SPELL_AURA_MOD_DETAUNT
|
||||
&AuraEffect::HandleUnused, //222 unused (3.2.0) only for spell 44586 that not used in real spell cast
|
||||
&AuraEffect::HandleNoImmediateEffect, //223 SPELL_AURA_RAID_PROC_FROM_CHARGE
|
||||
&AuraEffect::HandleUnused, //224 unused (3.0.8a)
|
||||
@@ -2984,19 +2984,17 @@ void AuraEffect::HandleFeignDeath(AuraApplication const* aurApp, uint8 mode, boo
|
||||
}
|
||||
}
|
||||
|
||||
if (target->GetInstanceScript() && target->GetInstanceScript()->IsEncounterInProgress())
|
||||
for (auto& pair : target->GetThreatMgr().GetThreatenedByMeList())
|
||||
pair.second->ScaleThreat(0.0f);
|
||||
|
||||
if (target->GetMap()->IsDungeon()) // feign death does not remove combat in dungeons
|
||||
{
|
||||
// Xinef: replaced with CombatStop(false)
|
||||
target->AttackStop();
|
||||
target->RemoveAllAttackers();
|
||||
target->getHostileRefMgr().addThreatPercent(-100);
|
||||
target->ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
|
||||
if (Player* targetPlayer = target->ToPlayer())
|
||||
targetPlayer->SendAttackSwingCancelAttack();
|
||||
}
|
||||
else
|
||||
{
|
||||
target->CombatStop();
|
||||
target->getHostileRefMgr().deleteReferences();
|
||||
}
|
||||
target->CombatStop(false, false);
|
||||
|
||||
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_IMMUNE_OR_LOST_SELECTION);
|
||||
|
||||
@@ -3551,26 +3549,16 @@ void AuraEffect::HandleForceMoveForward(AuraApplication const* aurApp, uint8 mod
|
||||
/*** THREAT ***/
|
||||
/****************************/
|
||||
|
||||
void AuraEffect::HandleModThreat(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
void AuraEffect::HandleModThreat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
|
||||
{
|
||||
if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK))
|
||||
return;
|
||||
|
||||
Unit* target = aurApp->GetTarget();
|
||||
for (uint8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
|
||||
if (GetMiscValue() & (1 << i))
|
||||
{
|
||||
if (apply)
|
||||
AddPct(target->m_threatModifier[i], GetAmount());
|
||||
else
|
||||
{
|
||||
float amount = target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_THREAT, 1 << i);
|
||||
target->m_threatModifier[i] = amount;
|
||||
}
|
||||
}
|
||||
target->GetThreatMgr().UpdateMySpellSchoolModifiers();
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraModTotalThreat(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
void AuraEffect::HandleAuraModTotalThreat(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
|
||||
{
|
||||
if (!(mode & AURA_EFFECT_HANDLE_CHANGE_AMOUNT_MASK))
|
||||
return;
|
||||
@@ -3582,10 +3570,10 @@ void AuraEffect::HandleAuraModTotalThreat(AuraApplication const* aurApp, uint8 m
|
||||
|
||||
Unit* caster = GetCaster();
|
||||
if (caster && caster->IsAlive())
|
||||
target->getHostileRefMgr().addTempThreat((float)GetAmount(), apply);
|
||||
caster->GetThreatMgr().UpdateMyTempModifiers();
|
||||
}
|
||||
|
||||
void AuraEffect::HandleModTaunt(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
void AuraEffect::HandleModTaunt(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
|
||||
{
|
||||
if (!(mode & AURA_EFFECT_HANDLE_REAL))
|
||||
return;
|
||||
@@ -3595,17 +3583,21 @@ void AuraEffect::HandleModTaunt(AuraApplication const* aurApp, uint8 mode, bool
|
||||
if (!target->IsAlive() || !target->CanHaveThreatList())
|
||||
return;
|
||||
|
||||
Unit* caster = GetCaster();
|
||||
if (!caster || !caster->IsAlive())
|
||||
target->GetThreatMgr().TauntUpdate();
|
||||
}
|
||||
|
||||
void AuraEffect::HandleModDetaunt(AuraApplication const* aurApp, uint8 mode, bool /*apply*/) const
|
||||
{
|
||||
if (!(mode & AURA_EFFECT_HANDLE_REAL))
|
||||
return;
|
||||
|
||||
if (apply)
|
||||
target->TauntApply(caster);
|
||||
else
|
||||
{
|
||||
// When taunt aura fades out, mob will switch to previous target if current has less than 1.1 * secondthreat
|
||||
target->TauntFadeOut(caster);
|
||||
}
|
||||
Unit* caster = GetCaster();
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
if (!caster || !caster->IsAlive() || !target->IsAlive() || !caster->CanHaveThreatList())
|
||||
return;
|
||||
|
||||
caster->GetThreatMgr().TauntUpdate();
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
@@ -3620,6 +3612,8 @@ void AuraEffect::HandleModConfuse(AuraApplication const* aurApp, uint8 mode, boo
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
target->SetControlled(apply, UNIT_STATE_CONFUSED);
|
||||
if (apply)
|
||||
target->GetThreatMgr().EvaluateSuppressed();
|
||||
}
|
||||
|
||||
void AuraEffect::HandleModFear(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
@@ -3640,6 +3634,8 @@ void AuraEffect::HandleAuraModStun(AuraApplication const* aurApp, uint8 mode, bo
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
target->SetControlled(apply, UNIT_STATE_STUNNED);
|
||||
if (apply)
|
||||
target->GetThreatMgr().EvaluateSuppressed();
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraModRoot(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
@@ -4359,6 +4355,9 @@ void AuraEffect::HandleAuraModSchoolImmunity(AuraApplication const* aurApp, uint
|
||||
|
||||
target->ApplySpellImmune(GetId(), IMMUNITY_SCHOOL, GetMiscValue(), (apply));
|
||||
|
||||
if (apply)
|
||||
target->GetThreatMgr().EvaluateSuppressed();
|
||||
|
||||
if (GetSpellInfo()->Mechanic == MECHANIC_BANISH)
|
||||
{
|
||||
if (apply)
|
||||
@@ -4417,6 +4416,9 @@ void AuraEffect::HandleAuraModDmgImmunity(AuraApplication const* aurApp, uint8 m
|
||||
Unit* target = aurApp->GetTarget();
|
||||
|
||||
target->ApplySpellImmune(GetId(), IMMUNITY_DAMAGE, GetMiscValue(), apply);
|
||||
|
||||
if (apply)
|
||||
target->GetThreatMgr().EvaluateSuppressed();
|
||||
}
|
||||
|
||||
void AuraEffect::HandleAuraModDispelImmunity(AuraApplication const* aurApp, uint8 mode, bool apply) const
|
||||
@@ -6895,7 +6897,7 @@ void AuraEffect::HandlePeriodicHealthLeechAuraTick(Unit* target, Unit* caster) c
|
||||
float threat = float(caster->HealBySpell(healInfo)) * 0.5f;
|
||||
if (caster->IsClass(CLASS_PALADIN))
|
||||
threat *= 0.5f;
|
||||
caster->getHostileRefMgr().threatAssist(caster, threat, GetSpellInfo());
|
||||
caster->GetThreatMgr().ForwardThreatForAssistingMe(caster, threat, GetSpellInfo());
|
||||
}
|
||||
|
||||
void AuraEffect::HandlePeriodicHealthFunnelAuraTick(Unit* target, Unit* caster) const
|
||||
@@ -7030,8 +7032,7 @@ void AuraEffect::HandlePeriodicHealAurasTick(Unit* target, Unit* caster) const
|
||||
float threat = float(gain) * 0.5f;
|
||||
if (caster->IsClass(CLASS_PALADIN))
|
||||
threat *= 0.5f;
|
||||
|
||||
target->getHostileRefMgr().threatAssist(caster, threat, GetSpellInfo());
|
||||
target->GetThreatMgr().ForwardThreatForAssistingMe(caster, threat, GetSpellInfo());
|
||||
}
|
||||
|
||||
bool haveCastItem = GetBase()->GetCastItemGUID();
|
||||
@@ -7117,8 +7118,6 @@ void AuraEffect::HandlePeriodicManaLeechAuraTick(Unit* target, Unit* caster) con
|
||||
target->AddThreat(caster, float(gainedAmount) * 0.5f, GetSpellInfo()->GetSchoolMask(), GetSpellInfo());
|
||||
}
|
||||
|
||||
target->AddThreat(caster, float(gainedAmount) * 0.5f, GetSpellInfo()->GetSchoolMask(), GetSpellInfo());
|
||||
|
||||
// remove CC auras
|
||||
target->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE);
|
||||
|
||||
@@ -7169,7 +7168,7 @@ void AuraEffect::HandleObsModPowerAuraTick(Unit* target, Unit* caster) const
|
||||
int32 gain = target->ModifyPower(PowerType, amount);
|
||||
|
||||
if (caster)
|
||||
target->getHostileRefMgr().threatAssist(caster, float(gain) * 0.5f, GetSpellInfo());
|
||||
target->GetThreatMgr().ForwardThreatForAssistingMe(caster, float(gain) * 0.5f, GetSpellInfo(), true);
|
||||
}
|
||||
|
||||
void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) const
|
||||
@@ -7203,7 +7202,7 @@ void AuraEffect::HandlePeriodicEnergizeAuraTick(Unit* target, Unit* caster) cons
|
||||
int32 gain = target->ModifyPower(PowerType, amount);
|
||||
|
||||
if (caster)
|
||||
target->getHostileRefMgr().threatAssist(caster, float(gain) * 0.5f, GetSpellInfo());
|
||||
target->GetThreatMgr().ForwardThreatForAssistingMe(caster, float(gain) * 0.5f, GetSpellInfo(), true);
|
||||
}
|
||||
|
||||
void AuraEffect::HandlePeriodicPowerBurnAuraTick(Unit* target, Unit* caster) const
|
||||
|
||||
@@ -206,6 +206,7 @@ public:
|
||||
void HandleModThreat(AuraApplication const* aurApp, uint8 mode, bool apply) const;
|
||||
void HandleAuraModTotalThreat(AuraApplication const* aurApp, uint8 mode, bool apply) const;
|
||||
void HandleModTaunt(AuraApplication const* aurApp, uint8 mode, bool apply) const;
|
||||
void HandleModDetaunt(AuraApplication const* aurApp, uint8 mode, bool apply) const;
|
||||
// control
|
||||
void HandleModConfuse(AuraApplication const* aurApp, uint8 mode, bool apply) const;
|
||||
void HandleModFear(AuraApplication const* aurApp, uint8 mode, bool apply) const;
|
||||
|
||||
@@ -237,6 +237,12 @@ public:
|
||||
|
||||
AuraScript* GetScriptByName(std::string const& scriptName) const;
|
||||
|
||||
template <class Script>
|
||||
Script* GetScript(std::string const& scriptName) const
|
||||
{
|
||||
return dynamic_cast<Script*>(GetScriptByName(scriptName));
|
||||
}
|
||||
|
||||
std::list<AuraScript*> m_loadedScripts;
|
||||
|
||||
virtual std::string GetDebugInfo() const;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -2652,7 +2652,7 @@ void Spell::EffectDispel(SpellEffIndex effIndex)
|
||||
|
||||
// put in combat
|
||||
if (unitTarget->IsFriendlyTo(m_caster))
|
||||
unitTarget->getHostileRefMgr().threatAssist(m_caster, 0.0f, m_spellInfo);
|
||||
unitTarget->GetThreatMgr().ForwardThreatForAssistingMe(m_caster, 0.0f, m_spellInfo);
|
||||
|
||||
if (success_list.empty())
|
||||
return;
|
||||
@@ -3299,33 +3299,25 @@ void Spell::EffectTaunt(SpellEffIndex /*effIndex*/)
|
||||
if (!unitTarget)
|
||||
return;
|
||||
|
||||
// xinef: Hand of Reckoning, cast before checing canhavethreatlist. fixes damage against pets
|
||||
// xinef: Hand of Reckoning, cast before checking canhavethreatlist. fixes damage against pets
|
||||
if (m_spellInfo->Id == 62124 && unitTarget->GetVictim() != m_caster)
|
||||
{
|
||||
m_caster->CastSpell(unitTarget, 67485, true);
|
||||
unitTarget->CombatStart(m_caster);
|
||||
}
|
||||
|
||||
// this effect use before aura Taunt apply for prevent taunt already attacking target
|
||||
// for spell as marked "non effective at already attacking target"
|
||||
if (!unitTarget->CanHaveThreatList() || (unitTarget->GetVictim() == m_caster && !m_spellInfo->HasAura(SPELL_AURA_MOD_TAUNT)))
|
||||
if (!unitTarget->CanHaveThreatList())
|
||||
{
|
||||
SendCastResult(SPELL_FAILED_DONT_REPORT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!unitTarget->GetThreatMgr().GetOnlineContainer().empty())
|
||||
ThreatManager& mgr = unitTarget->GetThreatMgr();
|
||||
if (mgr.GetCurrentVictim() == m_caster)
|
||||
{
|
||||
// Also use this effect to set the taunter's threat to the taunted creature's highest value
|
||||
float myThreat = unitTarget->GetThreatMgr().GetThreat(m_caster);
|
||||
float topThreat = unitTarget->GetThreatMgr().GetOnlineContainer().getMostHated()->GetThreat();
|
||||
if (topThreat > myThreat)
|
||||
unitTarget->GetThreatMgr().DoAddThreat(m_caster, topThreat - myThreat);
|
||||
|
||||
//Set aggro victim to caster
|
||||
if (HostileReference* forcedVictim = unitTarget->GetThreatMgr().GetOnlineContainer().getReferenceByTarget(m_caster))
|
||||
unitTarget->GetThreatMgr().setCurrentVictim(forcedVictim);
|
||||
SendCastResult(SPELL_FAILED_DONT_REPORT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mgr.IsThreatListEmpty())
|
||||
mgr.MatchUnitThreatToHighestThreat(m_caster);
|
||||
}
|
||||
|
||||
void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
|
||||
@@ -3677,7 +3669,8 @@ void Spell::EffectThreat(SpellEffIndex /*effIndex*/)
|
||||
if (!unitTarget->CanHaveThreatList() || m_caster->IsFriendlyTo(unitTarget))
|
||||
return;
|
||||
|
||||
unitTarget->AddThreat(m_caster, float(damage));
|
||||
// SPELL_EFFECT_THREAT adds flat threat that should not be modified by threat reduction
|
||||
unitTarget->GetThreatMgr().AddThreat(m_caster, float(damage), m_spellInfo, true);
|
||||
}
|
||||
|
||||
void Spell::EffectHealMaxHealth(SpellEffIndex /*effIndex*/)
|
||||
@@ -4002,24 +3995,18 @@ void Spell::EffectSanctuary(SpellEffIndex /*effIndex*/)
|
||||
if (!unitTarget)
|
||||
return;
|
||||
|
||||
if (unitTarget->GetInstanceScript() && unitTarget->GetInstanceScript()->IsEncounterInProgress())
|
||||
unitTarget->GetThreatMgr().EvaluateSuppressed();
|
||||
|
||||
if (unitTarget->IsPlayer() && !unitTarget->GetMap()->IsDungeon())
|
||||
{
|
||||
unitTarget->getHostileRefMgr().UpdateVisibility(true);
|
||||
// Xinef: replaced with CombatStop(false)
|
||||
unitTarget->AttackStop();
|
||||
unitTarget->RemoveAllAttackers();
|
||||
|
||||
// Night Elf: Shadowmeld only resets threat temporarily
|
||||
if (m_spellInfo->Id != 59646)
|
||||
unitTarget->getHostileRefMgr().addThreatPercent(-100);
|
||||
|
||||
if (unitTarget->IsPlayer())
|
||||
unitTarget->ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel
|
||||
// stop all pve combat for players outside dungeons, suppress pvp combat
|
||||
unitTarget->CombatStop(false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
unitTarget->getHostileRefMgr().UpdateVisibility(m_spellInfo->Id == 59646); // Night Elf: Shadowmeld
|
||||
unitTarget->CombatStop(true);
|
||||
// in dungeons (or for nonplayers), reset this unit on all enemies' threat lists
|
||||
for (auto const& pair : unitTarget->GetThreatMgr().GetThreatenedByMeList())
|
||||
pair.second->ScaleThreat(0.0f);
|
||||
}
|
||||
|
||||
UnitList targets;
|
||||
@@ -5185,7 +5172,7 @@ void Spell::EffectDispelMechanic(SpellEffIndex effIndex)
|
||||
|
||||
// put in combat
|
||||
if (unitTarget->IsFriendlyTo(m_caster))
|
||||
unitTarget->getHostileRefMgr().threatAssist(m_caster, 0.0f, m_spellInfo);
|
||||
unitTarget->GetThreatMgr().ForwardThreatForAssistingMe(m_caster, 0.0f, m_spellInfo);
|
||||
}
|
||||
|
||||
void Spell::EffectResurrectPet(SpellEffIndex /*effIndex*/)
|
||||
@@ -5903,7 +5890,7 @@ void Spell::EffectRedirectThreat(SpellEffIndex /*effIndex*/)
|
||||
return;
|
||||
|
||||
if (unitTarget)
|
||||
m_caster->SetRedirectThreat(unitTarget->GetGUID(), uint32(damage));
|
||||
m_caster->GetThreatMgr().RegisterRedirectThreat(m_spellInfo->Id, unitTarget->GetGUID(), uint32(damage));
|
||||
}
|
||||
|
||||
void Spell::EffectGameObjectDamage(SpellEffIndex /*effIndex*/)
|
||||
|
||||
@@ -1286,6 +1286,11 @@ bool SpellInfo::IsAutoRepeatRangedSpell() const
|
||||
return AttributesEx2 & SPELL_ATTR2_AUTO_REPEAT;
|
||||
}
|
||||
|
||||
bool SpellInfo::HasInitialAggro() const
|
||||
{
|
||||
return !(HasAttribute(SPELL_ATTR1_NO_THREAT) || HasAttribute(SPELL_ATTR3_SUPPRESS_TARGET_PROCS));
|
||||
}
|
||||
|
||||
bool SpellInfo::IsAffected(uint32 familyName, flag96 const& familyFlags) const
|
||||
{
|
||||
if (!familyName)
|
||||
|
||||
@@ -466,6 +466,7 @@ public:
|
||||
bool IsBreakingStealth() const;
|
||||
bool IsRangedWeaponSpell() const;
|
||||
bool IsAutoRepeatRangedSpell() const;
|
||||
bool HasInitialAggro() const;
|
||||
|
||||
[[nodiscard]] bool IsAffected(uint32 familyName, flag96 const& familyFlags) const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user