diff --git a/Source/Game/Combat/CombatManager.cs b/Source/Game/Combat/CombatManager.cs index 0f1428386..6c1184d47 100644 --- a/Source/Game/Combat/CombatManager.cs +++ b/Source/Game/Combat/CombatManager.cs @@ -113,7 +113,7 @@ namespace Game.Combat return null; } - public bool SetInCombatWith(Unit who) + public bool SetInCombatWith(Unit who, bool suppressPvpSecond = false) { // Are we already in combat? If yes, refresh pvp combat var pvpRefe = _pvpRefs.LookupByKey(who.GetGUID()); @@ -126,13 +126,18 @@ namespace Game.Combat return true; // Otherwise, check validity... - if (!CombatManager.CanBeginCombat(_owner, who)) + if (!CanBeginCombat(_owner, who)) return false; // ...then create new reference CombatReference refe; if (_owner.IsControlledByPlayer() && who.IsControlledByPlayer()) - refe = new PvPCombatReference(_owner, who); + { + PvPCombatReference refPvp = new PvPCombatReference(_owner, who); + if (suppressPvpSecond) + refPvp.SuppressFor(who); + refe = refPvp; + } else refe = new CombatReference(_owner, who); diff --git a/Source/Game/Entities/Unit/Unit.Combat.cs b/Source/Game/Entities/Unit/Unit.Combat.cs index 51bb67662..804cabea1 100644 --- a/Source/Game/Entities/Unit/Unit.Combat.cs +++ b/Source/Game/Entities/Unit/Unit.Combat.cs @@ -95,10 +95,10 @@ namespace Game.Entities public bool IsPetInCombat() { return HasUnitFlag(UnitFlags.PetInCombat); } - public void SetInCombatWith(Unit enemy) + public void SetInCombatWith(Unit enemy, bool suppressPvpTargetCombat = false) { if (enemy != null) - m_combatManager.SetInCombatWith(enemy); + m_combatManager.SetInCombatWith(enemy, suppressPvpTargetCombat); } public void EngageWithTarget(Unit enemy) diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 3e013ca3e..ba1c0e139 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -1852,8 +1852,13 @@ namespace Game.Spells // Calculate hit result WorldObject caster = m_originalCaster ? m_originalCaster : m_caster; + Unit unitCaster = m_caster.ToUnit(); targetInfo.MissCondition = caster.SpellHitResult(target, m_spellInfo, m_canReflect && !(IsPositive() && m_caster.IsFriendlyTo(target))); + // This will only cause combat - the target will engage once the projectile hits (in DoAllEffectOnTarget) + if (m_originalCaster != null && targetInfo.MissCondition != SpellMissInfo.Evade && !m_originalCaster.IsFriendlyTo(target) && (!m_spellInfo.IsPositive() || m_spellInfo.HasEffect(SpellEffectName.Dispel)) && (m_spellInfo.HasInitialAggro() || target.IsEngaged())) + m_originalCaster.SetInCombatWith(target, true); + // Spell have speed - need calculate incoming time // Incoming time is zero for self casts. At least I think so. if (m_caster != target) @@ -1886,6 +1891,15 @@ namespace Game.Spells } targetInfo.TimeDelay += (ulong)Math.Floor(hitDelay * 1000.0f); + + if (unitCaster != null && targetInfo.MissCondition != SpellMissInfo.Evade) + { + bool enterCombat = !caster.IsFriendlyTo(target) && (!m_spellInfo.IsPositive() || m_spellInfo.HasEffect(SpellEffectName.Dispel)) && (m_spellInfo.HasInitialAggro() || target.IsEngaged()); + bool enablePVP = targetInfo.IsPVPEnabling(); + + if (enterCombat || enablePVP) + target.m_Events.AddEvent(new ProcImpactDelayed(target, m_originalCasterGUID, enterCombat, enablePVP), target.m_Events.CalculateTime(TimeSpan.FromMilliseconds(targetInfo.TimeDelay))); + } } else targetInfo.TimeDelay = 0L; @@ -1894,7 +1908,7 @@ namespace Game.Spells if (targetInfo.MissCondition == SpellMissInfo.Reflect) { // Calculate reflected spell result on caster (shouldn't be able to reflect gameobject spells) - Unit unitCaster = m_caster.ToUnit(); + Cypher.Assert(unitCaster != null); targetInfo.ReflectResult = unitCaster.SpellHitResult(unitCaster, m_spellInfo, false); // can't reflect twice // Proc spell reflect aura when missile hits the original target @@ -7212,10 +7226,6 @@ namespace Game.Spells if (unit == null) return; - // This will only cause combat - the target will engage once the projectile hits (in DoAllEffectOnTarget) - if (m_originalCaster != null && targetInfo.MissCondition != SpellMissInfo.Evade && !m_originalCaster.IsFriendlyTo(unit) && (!m_spellInfo.IsPositive() || m_spellInfo.HasEffect(SpellEffectName.Dispel)) && (m_spellInfo.HasInitialAggro() || unit.IsEngaged())) - m_originalCaster.SetInCombatWith(unit); - m_damage = 0; m_healing = 0; @@ -8552,7 +8562,7 @@ namespace Game.Spells } } - if (!spell.m_spellInfo.HasAttribute(SpellAttr3.DoNotTriggerTargetStand) && !unit.IsStandState()) + if (!spell.m_spellInfo.HasAttribute(SpellAttr3.DoNotTriggerTargetStand) && !unit.IsStandState()) unit.SetStandState(UnitStandStateType.Stand); } @@ -8596,7 +8606,7 @@ namespace Game.Spells // Needs to be called after dealing damage/healing to not remove breaking on damage auras spell.DoTriggersOnSpellHit(_spellHitTarget); } - + if (_enablePVP) spell.GetCaster().ToPlayer().UpdatePvP(true); @@ -8604,6 +8614,8 @@ namespace Game.Spells spell.CallScriptAfterHitHandlers(); spell.spellAura = null; } + + public bool IsPVPEnabling() { return _enablePVP; } } public class GOTargetInfo : TargetInfoBase @@ -9101,6 +9113,41 @@ namespace Game.Spells Spell m_Spell; } + class ProcImpactDelayed : BasicEvent + { + Unit _owner; + ObjectGuid _casterGUID; + bool _enterCombat; + bool _enablePVP; + + public ProcImpactDelayed(Unit owner, ObjectGuid casterGUID, bool enterCombat, bool enablePVP) + { + _owner = owner; + _casterGUID = casterGUID; + _enterCombat = enterCombat; + _enablePVP = enablePVP; + } + + public override bool Execute(ulong e_time, uint p_time) + { + if (_owner == null) + return true; + + Unit caster = Global.ObjAccessor.GetUnit(_owner, _casterGUID); + if (caster == null) + return true; + + // This will only cause combat - the target will engage once the projectile hits (in DoAllEffectOnTarget) + if (_enterCombat) + _owner.SetInCombatWith(caster); + + if (_enablePVP && caster.ToPlayer()) + caster.ToPlayer().UpdatePvP(true); + + return true; + } + } + class ProcReflectDelayed : BasicEvent { public ProcReflectDelayed(Unit owner, ObjectGuid casterGuid)