From 532ab1c7f8653d1a2e48aa1f1f8a9ba1041d4bb7 Mon Sep 17 00:00:00 2001 From: Treeston Date: Wed, 3 Jan 2018 20:04:19 +0100 Subject: Core: Combat/threat system rewrite (PR #19930) - PvE combat is now always mutual. UNIT_FLAG_IN_COMBAT is backed by actual references to the units we're in combat with. - PvP combat is now also tracked, and almost always mutual; spells like Vanish and Feign Death can break this rule. That means we can easily determine a list of players we're fighting. - By extension, IsInCombatWith now has sensible behavior when invoked on nonplayers. - Threat and combat systems are no longer the same. - They still have an enforced relationship (threat implies combat - clearing combat clears threat)... - ...but we can have combat without threat. A creature (with threat list) isn't considered to be engaged until it has an entry on its threat list... - ...which means we can now faithfully replicate retail engage behavior. Combat on projectile launch - engagement start on projectile impact. Yay for progress! - AI method refactor, as already ported in 6113b9d - `JustEngagedWith`, `JustEnteredCombat` and `JustExitedCombat`. - Vehicle threat is now properly pooled on the main vehicle body (fixes #16542). - Various edge case bug fixes for threat redirects (Misdirection "cancelling" Vigilance and similar). - Target re-selection is now significantly faster. - Fixed a ton of other smaller edge case bugs, probably. Closes #7951 and #19998. --- src/server/game/Spells/SpellEffects.cpp | 61 +++++++++++++++------------------ 1 file changed, 28 insertions(+), 33 deletions(-) (limited to 'src/server/game/Spells/SpellEffects.cpp') diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 45ecb4a8e15..59f5d9b764a 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1229,7 +1229,7 @@ void Spell::EffectPowerDrain(SpellEffIndex effIndex) int32 gain = int32(newDamage* gainMultiplier); - m_caster->EnergizeBySpell(m_caster, m_spellInfo->Id, gain, powerType); + m_caster->EnergizeBySpell(m_caster, m_spellInfo, gain, powerType); } ExecuteLogEffectTakeTargetPower(effIndex, unitTarget, powerType, newDamage, gainMultiplier); } @@ -1781,7 +1781,7 @@ void Spell::EffectEnergize(SpellEffIndex effIndex) if (damage < 0) return; - m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, damage, power); + m_caster->EnergizeBySpell(unitTarget, m_spellInfo, damage, power); } void Spell::EffectEnergizePct(SpellEffIndex effIndex) @@ -1807,7 +1807,7 @@ void Spell::EffectEnergizePct(SpellEffIndex effIndex) return; uint32 gain = CalculatePct(maxPower, damage); - m_caster->EnergizeBySpell(unitTarget, m_spellInfo->Id, gain, power); + m_caster->EnergizeBySpell(unitTarget, m_spellInfo, gain, power); } void Spell::SendLoot(ObjectGuid guid, LootType loottype) @@ -3040,30 +3040,26 @@ void Spell::EffectTaunt(SpellEffIndex /*effIndex*/) // 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 || !unitTarget->CanHaveThreatList() || unitTarget->GetVictim() == m_caster) + if (!unitTarget || !unitTarget->CanHaveThreatList()) { SendCastResult(SPELL_FAILED_DONT_REPORT); return; } - if (m_spellInfo->Id == 62124 && (!unitTarget->IsPet() || !unitTarget->GetOwnerGUID().IsPlayer())) - m_caster->CastSpell(unitTarget, 67485, true); - - if (!unitTarget->GetThreatManager().getOnlineContainer().empty()) + ThreatManager& mgr = unitTarget->GetThreatManager(); + 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->GetThreatManager().getThreat(m_caster); - float topThreat = unitTarget->GetThreatManager().getOnlineContainer().getMostHated()->getThreat(); - if (topThreat > myThreat) - unitTarget->GetThreatManager().doAddThreat(m_caster, topThreat - myThreat); - - //Set aggro victim to caster - if (HostileReference* forcedVictim = unitTarget->GetThreatManager().getOnlineContainer().getReferenceByTarget(m_caster)) - unitTarget->GetThreatManager().setCurrentVictim(forcedVictim); + SendCastResult(SPELL_FAILED_DONT_REPORT); + return; } - if (unitTarget->ToCreature()->IsAIEnabled && !unitTarget->ToCreature()->HasReactState(REACT_PASSIVE)) - unitTarget->ToCreature()->AI()->AttackStart(m_caster); + // Hand of Reckoning + if (m_spellInfo->Id == 62124) + m_caster->CastSpell(unitTarget, 67485, true); + + if (!mgr.IsThreatListEmpty()) + // Set threat equal to highest threat currently on target + mgr.MatchUnitThreatToHighestThreat(m_caster); } void Spell::EffectWeaponDmg(SpellEffIndex effIndex) @@ -3354,13 +3350,13 @@ void Spell::EffectThreat(SpellEffIndex /*effIndex*/) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; - if (!unitTarget || !unitTarget->IsAlive() || !m_caster->IsAlive()) + if (!unitTarget || !m_caster->IsAlive()) return; if (!unitTarget->CanHaveThreatList()) return; - unitTarget->GetThreatManager().AddThreat(m_caster, float(damage)); + unitTarget->GetThreatManager().AddThreat(m_caster, float(damage), m_spellInfo, true); } void Spell::EffectHealMaxHealth(SpellEffIndex /*effIndex*/) @@ -3925,20 +3921,19 @@ void Spell::EffectSanctuary(SpellEffIndex /*effIndex*/) if (!unitTarget) return; - if (unitTarget->GetTypeId() == TYPEID_PLAYER) - unitTarget->ToPlayer()->SendAttackSwingCancelAttack(); // melee and ranged forced attack cancel - - unitTarget->getHostileRefManager().UpdateVisibility(); - - Unit::AttackerSet const& attackers = unitTarget->getAttackers(); - for (Unit::AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end();) + if (unitTarget->GetTypeId() == TYPEID_PLAYER && !unitTarget->GetMap()->IsDungeon()) { - if (!(*itr)->CanSeeOrDetect(unitTarget)) - (*(itr++))->AttackStop(); - else - ++itr; + // stop all pve combat for players outside dungeons, suppress pvp combat + unitTarget->CombatStop(false, false); + } + else + { + // in dungeons (or for nonplayers), reset this unit on all enemies' threat lists + for (auto const& pair : unitTarget->GetThreatManager().GetThreatenedByMeList()) + pair.second->SetThreat(0.0f); } + // makes spells cast before this time fizzle unitTarget->m_lastSanctuaryTime = GameTime::GetGameTimeMS(); } @@ -5478,7 +5473,7 @@ void Spell::EffectRedirectThreat(SpellEffIndex /*effIndex*/) return; if (unitTarget) - m_caster->SetRedirectThreat(unitTarget->GetGUID(), uint32(damage)); + m_caster->GetThreatManager().RegisterRedirectThreat(m_spellInfo->Id, unitTarget->GetGUID(), uint32(damage)); } void Spell::EffectGameObjectDamage(SpellEffIndex /*effIndex*/) -- cgit v1.2.3