Core/Combat Improve extra attacks handling
Port From (https://github.com/TrinityCore/TrinityCore/commit/6c9bde098b40f38905ea7407d0cd77437b0b953c)
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user