Core/Combat Improve extra attacks handling

Port From (https://github.com/TrinityCore/TrinityCore/commit/6c9bde098b40f38905ea7407d0cd77437b0b953c)
This commit is contained in:
hondacrx
2022-05-29 23:42:17 -04:00
parent 44b70d8db9
commit faa937a9da
8 changed files with 71 additions and 48 deletions
@@ -3304,10 +3304,6 @@ namespace Game.Entities
continue; continue;
} }
// not allow proc extra attack spell at extra attack
if (ExtraAttacks != 0 && spellInfo.HasEffect(SpellEffectName.AddExtraAttacks))
return;
float chance = spellInfo.ProcChance; float chance = spellInfo.ProcChance;
if (proto.SpellPPMRate != 0) if (proto.SpellPPMRate != 0)
+36 -5
View File
@@ -229,15 +229,30 @@ namespace Game.Entities
minion.StopAttackFaction(factionId); minion.StopAttackFaction(factionId);
} }
public void HandleProcExtraAttackFor(Unit victim) public void HandleProcExtraAttackFor(Unit victim, uint count)
{ {
while (ExtraAttacks != 0) while (count != 0)
{ {
--count;
AttackerStateUpdate(victim, WeaponAttackType.BaseAttack, true); AttackerStateUpdate(victim, WeaponAttackType.BaseAttack, true);
--ExtraAttacks;
} }
} }
public void AddExtraAttacks(uint count)
{
ObjectGuid targetGUID = _lastDamagedTargetGuid;
if (!targetGUID.IsEmpty())
{
ObjectGuid selection = GetTarget();
if (!selection.IsEmpty())
targetGUID = selection; // Spell was cast directly (not triggered by aura)
else
return;
}
extraAttacksTargets[targetGUID] += count;
}
public bool Attack(Unit victim, bool meleeAttack) public bool Attack(Unit victim, bool meleeAttack)
{ {
if (victim == null || victim.GetGUID() == GetGUID()) if (victim == null || victim.GetGUID() == GetGUID())
@@ -408,6 +423,14 @@ namespace Game.Entities
attackerList.Remove(pAttacker); attackerList.Remove(pAttacker);
} }
public void SetLastExtraAttackSpell(uint spellId) { _lastExtraAttackSpell = spellId; }
public uint GetLastExtraAttackSpell() { return _lastExtraAttackSpell; }
public void SetLastDamagedTargetGuid(ObjectGuid guid) { _lastDamagedTargetGuid = guid; }
ObjectGuid GetLastDamagedTargetGuid() { return _lastDamagedTargetGuid; }
public Unit GetVictim() public Unit GetVictim()
{ {
return attacking; return attacking;
@@ -481,7 +504,10 @@ namespace Game.Entities
public void AttackerStateUpdate(Unit victim, WeaponAttackType attType = WeaponAttackType.BaseAttack, bool extra = false) public void AttackerStateUpdate(Unit victim, WeaponAttackType attType = WeaponAttackType.BaseAttack, bool extra = false)
{ {
if (HasUnitState(UnitState.CannotAutoattack) || HasUnitFlag(UnitFlags.Pacified)) if (HasUnitFlag(UnitFlags.Pacified))
return;
if (HasUnitState(UnitState.CannotAutoattack) && !extra)
return; return;
if (HasAuraType(AuraType.DisableAttackingExceptAbilities)) if (HasAuraType(AuraType.DisableAttackingExceptAbilities))
@@ -500,6 +526,9 @@ namespace Game.Entities
if (attType != WeaponAttackType.BaseAttack && attType != WeaponAttackType.OffAttack) if (attType != WeaponAttackType.BaseAttack && attType != WeaponAttackType.OffAttack)
return; return;
if (!extra && _lastExtraAttackSpell != 0)
_lastExtraAttackSpell = 0;
if (IsTypeId(TypeId.Unit) && !HasUnitFlag(UnitFlags.Possessed) && !HasUnitFlag2(UnitFlags2.CannotTurn)) if (IsTypeId(TypeId.Unit) && !HasUnitFlag(UnitFlags.Possessed) && !HasUnitFlag2(UnitFlags2.CannotTurn))
SetFacingToObject(victim, false); // update client side facing to face the target (prevents visual glitches when casting untargeted spells) SetFacingToObject(victim, false); // update client side facing to face the target (prevents visual glitches when casting untargeted spells)
@@ -544,6 +573,8 @@ namespace Game.Entities
DealDamageMods(damageInfo.Attacker, victim, ref damageInfo.Damage, ref damageInfo.Absorb); DealDamageMods(damageInfo.Attacker, victim, ref damageInfo.Damage, ref damageInfo.Absorb);
SendAttackStateUpdate(damageInfo); SendAttackStateUpdate(damageInfo);
_lastDamagedTargetGuid = victim.GetGUID();
DealMeleeDamage(damageInfo, true); DealMeleeDamage(damageInfo, true);
DamageInfo dmgInfo = new(damageInfo); DamageInfo dmgInfo = new(damageInfo);
@@ -810,7 +841,7 @@ namespace Game.Entities
} }
} }
} }
// Proc auras on death - must be before aura/combat remove // Proc auras on death - must be before aura/combat remove
ProcSkillsAndAuras(victim, victim, new ProcFlagsInit(ProcFlags.None), new ProcFlagsInit(ProcFlags.Death), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null); ProcSkillsAndAuras(victim, victim, new ProcFlagsInit(ProcFlags.None), new ProcFlagsInit(ProcFlags.Death), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, null, null, null);
+4 -1
View File
@@ -69,7 +69,10 @@ namespace Game.Entities
public bool m_canDualWield; public bool m_canDualWield;
public int BaseSpellCritChance { get; set; } public int BaseSpellCritChance { get; set; }
public uint RegenTimer { get; set; } public uint RegenTimer { get; set; }
public uint ExtraAttacks { get; set; }
uint _lastExtraAttackSpell;
Dictionary<ObjectGuid, uint> extraAttacksTargets = new();
ObjectGuid _lastDamagedTargetGuid;
//Charm //Charm
public List<Unit> m_Controlled = new(); public List<Unit> m_Controlled = new();
+15
View File
@@ -147,6 +147,21 @@ namespace Game.Entities
m_combatManager.Update(diff); m_combatManager.Update(diff);
_lastDamagedTargetGuid = ObjectGuid.Empty;
if (_lastExtraAttackSpell != 0)
{
while (!extraAttacksTargets.Empty())
{
var (targetGuid, count) = extraAttacksTargets.FirstOrDefault();
extraAttacksTargets.Remove(targetGuid);
Unit victim = Global.ObjAccessor.GetUnit(this, targetGuid);
if (victim != null)
HandleProcExtraAttackFor(victim, count);
}
_lastExtraAttackSpell = 0;
}
uint att; uint att;
// not implemented before 3.0.2 // not implemented before 3.0.2
if ((att = GetAttackTimer(WeaponAttackType.BaseAttack)) != 0) if ((att = GetAttackTimer(WeaponAttackType.BaseAttack)) != 0)
+10 -2
View File
@@ -645,8 +645,16 @@ namespace Game.Spells
uint triggerSpellId = GetSpellEffectInfo().TriggerSpell; uint triggerSpellId = GetSpellEffectInfo().TriggerSpell;
SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId, GetBase().GetCastDifficulty()); SpellInfo triggeredSpellInfo = Global.SpellMgr.GetSpellInfo(triggerSpellId, GetBase().GetCastDifficulty());
if (triggeredSpellInfo != null) if (triggeredSpellInfo != null)
if (aurApp.GetTarget().ExtraAttacks != 0 && triggeredSpellInfo.HasEffect(SpellEffectName.AddExtraAttacks)) {
return false; if (triggeredSpellInfo.HasEffect(SpellEffectName.AddExtraAttacks))
{
uint lastExtraAttackSpell = eventInfo.GetActor().GetLastExtraAttackSpell();
// Patch 1.12.0(?) extra attack abilities can no longer chain proc themselves
if (lastExtraAttackSpell == triggerSpellId)
return false;
}
}
break; break;
} }
case AuraType.ModSpellCritChance: case AuraType.ModSpellCritChance:
+5 -9
View File
@@ -140,7 +140,7 @@ namespace Game.Spells
void InitExplicitTargets(SpellCastTargets targets) void InitExplicitTargets(SpellCastTargets targets)
{ {
m_targets = targets; m_targets = targets;
m_targets.SetOrigUnitTarget(m_targets.GetUnitTarget());
// this function tries to correct spell explicit targets for spell // this function tries to correct spell explicit targets for spell
// client doesn't send explicit targets correctly sometimes - we need to fix such spells serverside // client doesn't send explicit targets correctly sometimes - we need to fix such spells serverside
// this also makes sure that we correctly send explicit targets to client (removes redundant data) // this also makes sure that we correctly send explicit targets to client (removes redundant data)
@@ -3132,14 +3132,8 @@ namespace Game.Spells
if (m_comboPointGain != 0) if (m_comboPointGain != 0)
unitCaster.AddComboPoints(m_comboPointGain); unitCaster.AddComboPoints(m_comboPointGain);
if (unitCaster.ExtraAttacks != 0 && m_spellInfo.HasEffect(SpellEffectName.AddExtraAttacks)) if (m_spellInfo.HasEffect(SpellEffectName.AddExtraAttacks))
{ unitCaster.SetLastExtraAttackSpell(m_spellInfo.Id);
Unit victim = Global.ObjAccessor.GetUnit(unitCaster, m_targets.GetOrigUnitTargetGUID());
if (victim)
unitCaster.HandleProcExtraAttackFor(victim);
else
unitCaster.ExtraAttacks = 0;
}
} }
// Handle procs on finish // Handle procs on finish
@@ -8337,6 +8331,8 @@ namespace Game.Spells
} }
else else
{ {
caster.SetLastDamagedTargetGuid(spell.unitTarget.GetGUID());
// Add bonuses and fill damageInfo struct // Add bonuses and fill damageInfo struct
caster.CalculateSpellDamageTaken(damageInfo, spell.m_damage, spell.m_spellInfo, spell.m_attackType, IsCrit); caster.CalculateSpellDamageTaken(damageInfo, spell.m_damage, spell.m_spellInfo, spell.m_attackType, IsCrit);
Unit.DealDamageMods(damageInfo.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb); Unit.DealDamageMods(damageInfo.attacker, damageInfo.target, ref damageInfo.damage, ref damageInfo.absorb);
-23
View File
@@ -114,28 +114,6 @@ namespace Game.Spells
data.Name = m_strTarget; data.Name = m_strTarget;
} }
public ObjectGuid GetOrigUnitTargetGUID()
{
switch (m_origObjectTargetGUID.GetHigh())
{
case HighGuid.Player:
case HighGuid.Vehicle:
case HighGuid.Creature:
case HighGuid.Pet:
return m_origObjectTargetGUID;
default:
return ObjectGuid.Empty;
}
}
public void SetOrigUnitTarget(Unit target)
{
if (!target)
return;
m_origObjectTargetGUID = target.GetGUID();
}
public ObjectGuid GetUnitTargetGUID() public ObjectGuid GetUnitTargetGUID()
{ {
if (m_objectTargetGUID.IsUnit()) if (m_objectTargetGUID.IsUnit())
@@ -420,7 +398,6 @@ namespace Game.Spells
Item m_itemTarget; Item m_itemTarget;
// object GUID/etc, can be used always // object GUID/etc, can be used always
ObjectGuid m_origObjectTargetGUID;
ObjectGuid m_objectTargetGUID; ObjectGuid m_objectTargetGUID;
ObjectGuid m_itemTargetGUID; ObjectGuid m_itemTargetGUID;
uint m_itemTargetEntry; uint m_itemTargetEntry;
+1 -4
View File
@@ -3487,10 +3487,7 @@ namespace Game.Spells
if (!unitTarget || !unitTarget.IsAlive()) if (!unitTarget || !unitTarget.IsAlive())
return; return;
if (unitTarget.ExtraAttacks != 0) unitTarget.AddExtraAttacks((uint)damage);
return;
unitTarget.ExtraAttacks = (uint)damage;
ExecuteLogEffectExtraAttacks(effectInfo.Effect, unitTarget, (uint)damage); ExecuteLogEffectExtraAttacks(effectInfo.Effect, unitTarget, (uint)damage);
} }