diff --git a/OpenRA.Mods.Common/Activities/CaptureActor.cs b/OpenRA.Mods.Common/Activities/CaptureActor.cs index 90c4fc2427..6d3adaaa5e 100644 --- a/OpenRA.Mods.Common/Activities/CaptureActor.cs +++ b/OpenRA.Mods.Common/Activities/CaptureActor.cs @@ -40,16 +40,38 @@ namespace OpenRA.Mods.Common.Activities protected override bool TryStartEnter(Actor self) { - // CanEnter is only called when the actor is ready to start entering the target. - // We can (ab)use this as a notification that the capture is starting. - return manager.StartCapture(self, actor, targetManager); - } + // StartCapture returns false when a capture delay is enabled + // We wait until it returns true before allowing entering the target + Captures captures; + if (!manager.StartCapture(self, actor, targetManager, out captures)) + return false; + + if (!captures.Info.ConsumedByCapture) + { + // Immediately capture without entering or disposing the actor + DoCapture(self, captures); + AbortOrExit(self); + return false; + } + + return true; + } protected override void OnInside(Actor self) { if (!CanReserve(self)) return; + // Prioritize capturing over sabotaging + var captures = manager.ValidCapturesWithLowestSabotageThreshold(self, actor, targetManager); + if (captures == null) + return; + + DoCapture(self, captures); + } + + void DoCapture(Actor self, Captures captures) + { if (building != null && !building.Lock()) return; @@ -58,11 +80,6 @@ namespace OpenRA.Mods.Common.Activities if (building != null && building.Locked) building.Unlock(); - // Prioritize capturing over sabotaging - var captures = manager.ValidCapturesWithLowestSabotageThreshold(self, actor, targetManager); - if (captures == null) - return; - // Sabotage instead of capture if (captures.Info.SabotageThreshold > 0 && !actor.Owner.NonCombatant) { @@ -74,7 +91,9 @@ namespace OpenRA.Mods.Common.Activities var damage = (int)((long)health.MaxHP * captures.Info.SabotageHPRemoval / 100); actor.InflictDamage(self, new Damage(damage)); - self.Dispose(); + if (captures.Info.ConsumedByCapture) + self.Dispose(); + return; } } @@ -97,7 +116,8 @@ namespace OpenRA.Mods.Common.Activities exp.GiveExperience(captures.Info.PlayerExperience); } - self.Dispose(); + if (captures.Info.ConsumedByCapture) + self.Dispose(); }); } diff --git a/OpenRA.Mods.Common/Traits/CaptureManager.cs b/OpenRA.Mods.Common/Traits/CaptureManager.cs index b4c65d8908..484e559e18 100644 --- a/OpenRA.Mods.Common/Traits/CaptureManager.cs +++ b/OpenRA.Mods.Common/Traits/CaptureManager.cs @@ -167,8 +167,10 @@ namespace OpenRA.Mods.Common.Traits /// This method grants the capturing conditions on the captor and target and returns /// true if the captor is able to start entering or false if it needs to wait. /// - public bool StartCapture(Actor self, Actor target, CaptureManager targetManager) + public bool StartCapture(Actor self, Actor target, CaptureManager targetManager, out Captures captures) { + captures = null; + if (target != currentTarget) { if (currentTarget != null) @@ -189,7 +191,7 @@ namespace OpenRA.Mods.Common.Traits targetManager.beingCapturedToken == ConditionManager.InvalidConditionToken) targetManager.beingCapturedToken = targetManager.conditionManager.GrantCondition(target, targetManager.info.BeingCapturedCondition); - var captures = enabledCaptures + captures = enabledCaptures .OrderBy(c => c.Info.CaptureDelay) .FirstOrDefault(c => targetManager.CanBeTargetedBy(target, self, c)); @@ -199,7 +201,7 @@ namespace OpenRA.Mods.Common.Traits if (progressWatchers.Any() || targetManager.progressWatchers.Any()) { currentTargetTotal = captures.Info.CaptureDelay; - if (move != null) + if (move != null && captures.Info.ConsumedByCapture) { var pos = target.GetTargetablePositions().PositionClosestTo(self.CenterPosition); currentTargetTotal += move.EstimatedMoveDuration(self, self.CenterPosition, pos); diff --git a/OpenRA.Mods.Common/Traits/Captures.cs b/OpenRA.Mods.Common/Traits/Captures.cs index d8e6697456..cda7f7e9a8 100644 --- a/OpenRA.Mods.Common/Traits/Captures.cs +++ b/OpenRA.Mods.Common/Traits/Captures.cs @@ -35,6 +35,9 @@ namespace OpenRA.Mods.Common.Traits [Desc("Delay (in ticks) that to wait next to the target before initiating the capture.")] public readonly int CaptureDelay = 0; + [Desc("Enter the target actor and be consumed by the capture.")] + public readonly bool ConsumedByCapture = true; + [Desc("Experience granted to the capturing player.")] public readonly int PlayerExperience = 0;