diff --git a/OpenRA.Mods.Common/Activities/RepairBuilding.cs b/OpenRA.Mods.Common/Activities/RepairBuilding.cs index 1822b5e661..f6c3ad06d6 100644 --- a/OpenRA.Mods.Common/Activities/RepairBuilding.cs +++ b/OpenRA.Mods.Common/Activities/RepairBuilding.cs @@ -14,35 +14,61 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Activities { - class RepairBuilding : LegacyEnter + class RepairBuilding : Enter { - readonly Actor target; - readonly IHealth health; + readonly EnterBehaviour enterBehaviour; readonly Stance validStances; - public RepairBuilding(Actor self, Actor target, EnterBehaviour enterBehaviour, Stance validStances) - : base(self, target, enterBehaviour, targetLineColor: Color.Yellow) + Actor enterActor; + IHealth enterHealth; + + public RepairBuilding(Actor self, Target target, EnterBehaviour enterBehaviour, Stance validStances) + : base(self, target, Color.Yellow) { - this.target = target; + this.enterBehaviour = enterBehaviour; this.validStances = validStances; - health = target.Trait(); } - protected override bool CanReserve(Actor self) + protected override bool TryStartEnter(Actor self, Actor targetActor) { - return health.DamageState != DamageState.Undamaged; + enterActor = targetActor; + enterHealth = targetActor.TraitOrDefault(); + + // Make sure we can still repair the target before entering + // (but not before, because this may stop the actor in the middle of nowhere) + var stance = self.Owner.Stances[enterActor.Owner]; + if (enterHealth == null || enterHealth.DamageState == DamageState.Undamaged || !stance.HasStance(validStances)) + { + Cancel(self, true); + return false; + } + + return true; } - protected override void OnInside(Actor self) + protected override void OnEnterComplete(Actor self, Actor targetActor) { - var stance = self.Owner.Stances[target.Owner]; + // Make sure the target hasn't changed while entering + // OnEnterComplete is only called if targetActor is alive + if (targetActor != enterActor) + return; + + if (enterHealth.DamageState == DamageState.Undamaged) + return; + + var stance = self.Owner.Stances[enterActor.Owner]; if (!stance.HasStance(validStances)) return; - if (health.DamageState == DamageState.Undamaged) + if (enterHealth.DamageState == DamageState.Undamaged) return; - target.InflictDamage(self, new Damage(-health.MaxHP)); + enterActor.InflictDamage(self, new Damage(-enterHealth.MaxHP)); + + if (enterBehaviour == EnterBehaviour.Dispose) + self.Dispose(); + else if (enterBehaviour == EnterBehaviour.Suicide) + self.Kill(self); } } } diff --git a/OpenRA.Mods.Common/Traits/EngineerRepair.cs b/OpenRA.Mods.Common/Traits/EngineerRepair.cs index 844fc3aa2f..9f8e317393 100644 --- a/OpenRA.Mods.Common/Traits/EngineerRepair.cs +++ b/OpenRA.Mods.Common/Traits/EngineerRepair.cs @@ -76,15 +76,11 @@ namespace OpenRA.Mods.Common.Traits if (order.OrderString != "EngineerRepair" || !IsValidOrder(self, order)) return; - var target = self.ResolveFrozenActorOrder(order, Color.Yellow); - if (target.Type != TargetType.Actor) - return; - if (!order.Queued) self.CancelActivity(); - self.SetTargetLine(target, Color.Yellow); - self.QueueActivity(new RepairBuilding(self, target.Actor, info.EnterBehaviour, info.ValidStances)); + self.SetTargetLine(order.Target, Color.Yellow); + self.QueueActivity(new RepairBuilding(self, order.Target, info.EnterBehaviour, info.ValidStances)); } class EngineerRepairOrderTargeter : UnitOrderTargeter