aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Entities/Unit
diff options
context:
space:
mode:
authortrickerer <onlysuffering@gmail.com>2021-10-01 21:40:20 +0700
committerGitHub <noreply@github.com>2021-10-01 16:40:20 +0200
commit084f8f3ded45150a57eabd3ad117f1152d4d046d (patch)
tree5fd3fb733d8618c043704bc373c3a19a40a3969f /src/server/game/Entities/Unit
parente317beb449fb36b9f13c3bda192f86dc72d07581 (diff)
Core/Combat Improve extra attacks handling (#26859)
* Core/Combat Improve extra attacks handling * Remove unnecessary _lastDamagedTargetGuid check * Add missing initialization of _lastExtraAttackSpell. Do not use hardcoded spell ids. * Partially revert 9f90b835019b
Diffstat (limited to 'src/server/game/Entities/Unit')
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp48
-rw-r--r--src/server/game/Entities/Unit/Unit.h13
2 files changed, 54 insertions, 7 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index e515a048830..2daf345215c 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -314,7 +314,6 @@ Unit::Unit(bool isWorldObject) :
m_modAttackSpeedPct[OFF_ATTACK] = 1.0f;
m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f;
- m_extraAttacks = 0;
m_canDualWield = false;
m_movementCounter = 0;
@@ -389,6 +388,8 @@ Unit::Unit(bool isWorldObject) :
_isWalkingBeforeCharm = false;
_instantCast = false;
_isCombatDisallowed = false;
+
+ _lastExtraAttackSpell = 0;
}
////////////////////////////////////////////////////////////
@@ -445,6 +446,21 @@ void Unit::Update(uint32 p_time)
m_combatManager.Update(p_time);
+ _lastDamagedTargetGuid = ObjectGuid::Empty;
+ if (_lastExtraAttackSpell)
+ {
+ while (!extraAttacksTargets.empty())
+ {
+ auto itr = extraAttacksTargets.begin();
+ ObjectGuid targetGuid = itr->first;
+ uint32 count = itr->second;
+ extraAttacksTargets.erase(itr);
+ if (Unit* victim = ObjectAccessor::GetUnit(*this, targetGuid))
+ HandleProcExtraAttackFor(victim, count);
+ }
+ _lastExtraAttackSpell = 0;
+ }
+
// not implemented before 3.0.2
if (uint32 base_att = getAttackTimer(BASE_ATTACK))
setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time));
@@ -2056,7 +2072,10 @@ void Unit::HandleEmoteCommand(Emote emoteId)
void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra)
{
- if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
+ if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
+ return;
+
+ if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) && !extra)
return;
if (!victim->IsAlive())
@@ -2071,6 +2090,9 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr
if (attType != BASE_ATTACK && attType != OFF_ATTACK)
return; // ignore ranged case
+ if (!extra && _lastExtraAttackSpell)
+ _lastExtraAttackSpell = 0;
+
if (GetTypeId() == TYPEID_UNIT && !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_POSSESSED) && !HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_CANNOT_TURN))
SetFacingToObject(victim, false); // update client side facing to face the target (prevents visual glitches when casting untargeted spells)
@@ -2090,6 +2112,8 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr
Unit::DealDamageMods(victim, damageInfo.Damages[i].Damage, &damageInfo.Damages[i].Absorb);
SendAttackStateUpdate(&damageInfo);
+ _lastDamagedTargetGuid = victim->GetGUID();
+
DealMeleeDamage(&damageInfo, true);
DamageInfo dmgInfo(damageInfo);
@@ -2104,15 +2128,29 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr
}
}
-void Unit::HandleProcExtraAttackFor(Unit* victim)
+void Unit::HandleProcExtraAttackFor(Unit* victim, uint32 count)
{
- while (m_extraAttacks)
+ while (count)
{
+ --count;
AttackerStateUpdate(victim, BASE_ATTACK, true);
- --m_extraAttacks;
}
}
+void Unit::AddExtraAttacks(uint32 count)
+{
+ ObjectGuid targetGUID = _lastDamagedTargetGuid;
+ if (!targetGUID)
+ {
+ if (ObjectGuid selection = GetTarget())
+ targetGUID = selection; // Spell was cast directly (not triggered by aura)
+ else
+ return;
+ }
+
+ extraAttacksTargets[targetGUID] += count;
+}
+
MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackType attType) const
{
if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode())
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index cffd683d28e..ea63c22ea3a 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -834,7 +834,6 @@ class TC_GAME_API Unit : public WorldObject
bool IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const;
float GetMeleeRange(Unit const* target) const;
virtual SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = BASE_ATTACK, uint8 damageIndex = 0) const = 0;
- uint32 m_extraAttacks;
bool m_canDualWield;
void _addAttacker(Unit* pAttacker); // must be called only from Unit::Attack(Unit*)
@@ -991,7 +990,13 @@ class TC_GAME_API Unit : public WorldObject
void CalculateMeleeDamage(Unit* victim, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK);
void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss);
- void HandleProcExtraAttackFor(Unit* victim);
+ void HandleProcExtraAttackFor(Unit* victim, uint32 count);
+
+ void SetLastExtraAttackSpell(uint32 spellId) { _lastExtraAttackSpell = spellId; }
+ uint32 GetLastExtraAttackSpell() const { return _lastExtraAttackSpell; }
+ void AddExtraAttacks(uint32 count);
+ void SetLastDamagedTargetGuid(ObjectGuid guid) { _lastDamagedTargetGuid = guid; }
+ ObjectGuid GetLastDamagedTargetGuid() const { return _lastDamagedTargetGuid; }
void CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = BASE_ATTACK, bool crit = false, Spell* spell = nullptr);
void DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss);
@@ -1884,6 +1889,10 @@ class TC_GAME_API Unit : public WorldObject
int8 m_comboPoints;
std::unordered_set<Unit*> m_ComboPointHolders;
+ uint32 _lastExtraAttackSpell;
+ std::unordered_map<ObjectGuid /*guid*/, uint32 /*count*/> extraAttacksTargets;
+ ObjectGuid _lastDamagedTargetGuid;
+
bool m_cleanupDone; // lock made to not add stuff after cleanup before delete
bool m_duringRemoveFromWorld; // lock made to not add stuff after begining removing from world
bool _instantCast;