Fix ResupplyAircraft being cancelable by Stop command

It is now immediately queued again, as long as the actor
has not finished rearming/repairing yet.
This commit is contained in:
reaperrr
2019-03-18 01:00:22 +01:00
committed by reaperrr
parent b92aef5754
commit 32ab822786

View File

@@ -171,8 +171,8 @@ namespace OpenRA.Mods.Common.Traits
public readonly AircraftInfo Info; public readonly AircraftInfo Info;
readonly Actor self; readonly Actor self;
RepairableInfo repairableInfo; Repairable repairable;
RearmableInfo rearmableInfo; Rearmable rearmable;
ConditionManager conditionManager; ConditionManager conditionManager;
IDisposable reservation; IDisposable reservation;
IEnumerable<int> speedModifiers; IEnumerable<int> speedModifiers;
@@ -228,8 +228,8 @@ namespace OpenRA.Mods.Common.Traits
protected virtual void Created(Actor self) protected virtual void Created(Actor self)
{ {
repairableInfo = self.Info.TraitInfoOrDefault<RepairableInfo>(); repairable = self.TraitOrDefault<Repairable>();
rearmableInfo = self.Info.TraitInfoOrDefault<RearmableInfo>(); rearmable = self.TraitOrDefault<Rearmable>();
conditionManager = self.TraitOrDefault<ConditionManager>(); conditionManager = self.TraitOrDefault<ConditionManager>();
speedModifiers = self.TraitsImplementing<ISpeedModifier>().ToArray().Select(sm => sm.GetSpeedModifier()); speedModifiers = self.TraitsImplementing<ISpeedModifier>().ToArray().Select(sm => sm.GetSpeedModifier());
cachedPosition = self.CenterPosition; cachedPosition = self.CenterPosition;
@@ -469,8 +469,8 @@ namespace OpenRA.Mods.Common.Traits
if (self.AppearsHostileTo(a)) if (self.AppearsHostileTo(a))
return false; return false;
return (rearmableInfo != null && rearmableInfo.RearmActors.Contains(a.Info.Name)) return (rearmable != null && rearmable.Info.RearmActors.Contains(a.Info.Name))
|| (repairableInfo != null && repairableInfo.RepairActors.Contains(a.Info.Name)); || (repairable != null && repairable.Info.RepairActors.Contains(a.Info.Name));
} }
public int MovementSpeed public int MovementSpeed
@@ -503,14 +503,23 @@ namespace OpenRA.Mods.Common.Traits
return Info.LandableTerrainTypes.Contains(type); return Info.LandableTerrainTypes.Contains(type);
} }
public bool CanRearmAt(Actor host)
{
return rearmable != null && rearmable.Info.RearmActors.Contains(host.Info.Name) && rearmable.RearmableAmmoPools.Any(p => !p.FullAmmo());
}
public bool CanRepairAt(Actor host)
{
return repairable != null && repairable.Info.RepairActors.Contains(host.Info.Name) && self.GetDamageState() != DamageState.Undamaged;
}
public virtual IEnumerable<Activity> GetResupplyActivities(Actor a) public virtual IEnumerable<Activity> GetResupplyActivities(Actor a)
{ {
var name = a.Info.Name; // The ResupplyAircraft activity guarantees that we're on the helipad/repair depot
if (rearmableInfo != null && rearmableInfo.RearmActors.Contains(name)) if (CanRearmAt(a))
yield return new Rearm(self, a, WDist.Zero); yield return new Rearm(self, a, WDist.Zero);
// The ResupplyAircraft activity guarantees that we're on the helipad if (CanRepairAt(a))
if (repairableInfo != null && repairableInfo.RepairActors.Contains(name))
yield return new Repair(self, a, WDist.Zero); yield return new Repair(self, a, WDist.Zero);
} }
@@ -521,21 +530,45 @@ namespace OpenRA.Mods.Common.Traits
void INotifyBecomingIdle.OnBecomingIdle(Actor self) void INotifyBecomingIdle.OnBecomingIdle(Actor self)
{ {
if (Info.VTOL && Info.LandWhenIdle) OnBecomingIdle(self);
}
protected virtual void OnBecomingIdle(Actor self)
{
var atLandAltitude = self.World.Map.DistanceAboveTerrain(CenterPosition) == Info.LandAltitude;
// Work-around to prevent players from accidentally canceling resupply by pressing 'Stop',
// by re-queueing ResupplyAircraft as long as resupply hasn't finished and aircraft is still on resupplier.
// TODO: Investigate moving this back to ResolveOrder's "Stop" handling,
// once conflicts with other traits' "Stop" orders have been fixed.
if (atLandAltitude)
{
var host = GetActorBelow();
if (host != null && (CanRearmAt(host) || CanRepairAt(host)))
{
self.QueueActivity(new ResupplyAircraft(self));
return;
}
}
if (!atLandAltitude && Info.VTOL && Info.LandWhenIdle)
{ {
if (Info.TurnToLand) if (Info.TurnToLand)
self.QueueActivity(new Turn(self, Info.InitialFacing)); self.QueueActivity(new Turn(self, Info.InitialFacing));
self.QueueActivity(new HeliLand(self, true)); self.QueueActivity(new HeliLand(self, true));
} }
else if (!Info.CanHover && (Info.TakeOffOnResupply || ReservedActor == null || self.World.Map.DistanceAboveTerrain(CenterPosition) != Info.LandAltitude)) else if (!Info.CanHover && !atLandAltitude)
self.QueueActivity(new FlyCircle(self, -1, Info.IdleTurnSpeed > -1 ? Info.IdleTurnSpeed : TurnSpeed)); self.QueueActivity(new FlyCircle(self, -1, Info.IdleTurnSpeed > -1 ? Info.IdleTurnSpeed : TurnSpeed));
else if (atLandAltitude && (Info.TakeOffOnResupply || ReservedActor == null))
self.QueueActivity(new TakeOff(self));
else if (Info.CanHover && self.Info.HasTraitInfo<AutoCarryallInfo>() && Info.IdleTurnSpeed > -1)
{
// Temporary HACK for the AutoCarryall special case (needs CanHover, but also HeliFlyCircle on idle). // Temporary HACK for the AutoCarryall special case (needs CanHover, but also HeliFlyCircle on idle).
// Will go away soon (in a separate PR) with the arrival of ActionsWhenIdle. // Will go away soon (in a separate PR) with the arrival of ActionsWhenIdle.
else if (Info.CanHover && self.Info.HasTraitInfo<AutoCarryallInfo>() && Info.IdleTurnSpeed > -1)
self.QueueActivity(new HeliFlyCircle(self, Info.IdleTurnSpeed > -1 ? Info.IdleTurnSpeed : TurnSpeed)); self.QueueActivity(new HeliFlyCircle(self, Info.IdleTurnSpeed > -1 ? Info.IdleTurnSpeed : TurnSpeed));
} }
}
#region Implement IPositionable #region Implement IPositionable
@@ -717,13 +750,13 @@ namespace OpenRA.Mods.Common.Traits
Order IIssueDeployOrder.IssueDeployOrder(Actor self, bool queued) Order IIssueDeployOrder.IssueDeployOrder(Actor self, bool queued)
{ {
if (rearmableInfo == null || !rearmableInfo.RearmActors.Any()) if (rearmable == null || !rearmable.Info.RearmActors.Any())
return null; return null;
return new Order("ReturnToBase", self, queued); return new Order("ReturnToBase", self, queued);
} }
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self) { return rearmableInfo != null && rearmableInfo.RearmActors.Any(); } bool IIssueDeployOrder.CanIssueDeployOrder(Actor self) { return rearmable != null && rearmable.Info.RearmActors.Any(); }
public string VoicePhraseForOrder(Actor self, Order order) public string VoicePhraseForOrder(Actor self, Order order)
{ {
@@ -742,7 +775,7 @@ namespace OpenRA.Mods.Common.Traits
case "Stop": case "Stop":
return Info.Voice; return Info.Voice;
case "ReturnToBase": case "ReturnToBase":
return rearmableInfo != null && rearmableInfo.RearmActors.Any() ? Info.Voice : null; return rearmable != null && rearmable.Info.RearmActors.Any() ? Info.Voice : null;
default: return null; default: return null;
} }
} }
@@ -791,15 +824,15 @@ namespace OpenRA.Mods.Common.Traits
else if (order.OrderString == "Stop") else if (order.OrderString == "Stop")
{ {
self.CancelActivity(); self.CancelActivity();
// HACK: If the player accidentally pressed 'Stop', we don't want this to cancel reservation.
// If unreserving is actually desired despite an actor below, it should be triggered from OnBecomingIdle.
if (GetActorBelow() != null) if (GetActorBelow() != null)
{
self.QueueActivity(new ResupplyAircraft(self));
return; return;
}
UnReserve(); UnReserve();
} }
else if (order.OrderString == "ReturnToBase" && rearmableInfo != null && rearmableInfo.RearmActors.Any()) else if (order.OrderString == "ReturnToBase" && rearmable != null && rearmable.Info.RearmActors.Any())
{ {
if (!order.Queued) if (!order.Queued)
UnReserve(); UnReserve();