Merge pull request #11956 from obrakmann/fix11953_fix-aircraft-reservation-madness

Fix aircraft reservation madness
This commit is contained in:
Matthias Mailänder
2016-09-04 21:54:28 +02:00
committed by GitHub
5 changed files with 62 additions and 25 deletions

View File

@@ -19,6 +19,7 @@ namespace OpenRA.Mods.Common.Activities
public class FlyAttack : Activity public class FlyAttack : Activity
{ {
readonly Target target; readonly Target target;
readonly Aircraft aircraft;
readonly AttackPlane attackPlane; readonly AttackPlane attackPlane;
readonly AmmoPool[] ammoPools; readonly AmmoPool[] ammoPools;
@@ -28,6 +29,7 @@ namespace OpenRA.Mods.Common.Activities
public FlyAttack(Actor self, Target target) public FlyAttack(Actor self, Target target)
{ {
this.target = target; this.target = target;
aircraft = self.Trait<Aircraft>();
attackPlane = self.TraitOrDefault<AttackPlane>(); attackPlane = self.TraitOrDefault<AttackPlane>();
ammoPools = self.TraitsImplementing<AmmoPool>().ToArray(); ammoPools = self.TraitsImplementing<AmmoPool>().ToArray();
ticksUntilTurn = attackPlane.AttackPlaneInfo.AttackTurnDelay; ticksUntilTurn = attackPlane.AttackPlaneInfo.AttackTurnDelay;
@@ -38,10 +40,9 @@ namespace OpenRA.Mods.Common.Activities
if (!target.IsValidFor(self)) if (!target.IsValidFor(self))
return NextActivity; return NextActivity;
// Move to the next activity only if all ammo pools are depleted and none reload automatically
// TODO: This should check whether there is ammo left that is actually suitable for the target // TODO: This should check whether there is ammo left that is actually suitable for the target
if (ammoPools.All(x => !x.Info.SelfReloads && !x.HasAmmo())) if (ammoPools.All(x => !x.Info.SelfReloads && !x.HasAmmo()))
return ActivityUtils.SequenceActivities(new ReturnToBase(self), NextActivity); return ActivityUtils.SequenceActivities(new ReturnToBase(self), this);
if (attackPlane != null) if (attackPlane != null)
attackPlane.DoAttack(self, target); attackPlane.DoAttack(self, target);
@@ -56,6 +57,10 @@ namespace OpenRA.Mods.Common.Activities
inner = ActivityUtils.SequenceActivities(new FlyTimed(ticksUntilTurn, self), new Fly(self, target), new FlyTimed(ticksUntilTurn, self)); inner = ActivityUtils.SequenceActivities(new FlyTimed(ticksUntilTurn, self), new Fly(self, target), new FlyTimed(ticksUntilTurn, self));
else else
inner = ActivityUtils.SequenceActivities(new Fly(self, target), new FlyTimed(ticksUntilTurn, self)); inner = ActivityUtils.SequenceActivities(new Fly(self, target), new FlyTimed(ticksUntilTurn, self));
// HACK: This needs to be done in this round-about way because TakeOff doesn't behave as expected when it doesn't have a NextActivity.
if (self.World.Map.DistanceAboveTerrain(self.CenterPosition).Length < aircraft.Info.MinAirborneAltitude)
inner = ActivityUtils.SequenceActivities(new TakeOff(self), inner);
} }
inner = ActivityUtils.RunActivity(self, inner); inner = ActivityUtils.RunActivity(self, inner);

View File

@@ -65,9 +65,9 @@ namespace OpenRA.Mods.Common.Activities
return ActivityUtils.SequenceActivities(new HeliFly(self, newTarget)); return ActivityUtils.SequenceActivities(new HeliFly(self, newTarget));
} }
// If any AmmoPool is depleted and no weapon is valid against target, return to helipad to reload and then move to next activity // If any AmmoPool is depleted and no weapon is valid against target, return to helipad to reload and then resume the activity
if (ammoPools.Any(x => !x.Info.SelfReloads && !x.HasAmmo()) && !attackHeli.HasAnyValidWeapons(target)) if (ammoPools.Any(x => !x.Info.SelfReloads && !x.HasAmmo()) && !attackHeli.HasAnyValidWeapons(target))
return ActivityUtils.SequenceActivities(new HeliReturnToBase(self), NextActivity); return ActivityUtils.SequenceActivities(new HeliReturnToBase(self), this);
var dist = target.CenterPosition - self.CenterPosition; var dist = target.CenterPosition - self.CenterPosition;

View File

@@ -19,6 +19,7 @@ namespace OpenRA.Mods.Common.Activities
public class ResupplyAircraft : Activity public class ResupplyAircraft : Activity
{ {
readonly Aircraft aircraft; readonly Aircraft aircraft;
Activity inner;
public ResupplyAircraft(Actor self) public ResupplyAircraft(Actor self)
{ {
@@ -27,22 +28,45 @@ namespace OpenRA.Mods.Common.Activities
public override Activity Tick(Actor self) public override Activity Tick(Actor self)
{ {
var host = aircraft.GetActorBelow(); if (IsCanceled)
if (host == null)
return NextActivity; return NextActivity;
if (aircraft.IsPlane) if (inner == null)
return ActivityUtils.SequenceActivities( {
aircraft.GetResupplyActivities(host) var host = aircraft.GetActorBelow();
.Append(new CallFunc(() => aircraft.UnReserve()))
.Append(new WaitFor(() => NextActivity != null || Reservable.IsReserved(host)))
.Append(new TakeOff(self))
.Append(NextActivity).ToArray());
// If is helicopter move away as soon as the resupply ends if (host == null)
return ActivityUtils.SequenceActivities( return NextActivity;
aircraft.GetResupplyActivities(host).Append(new TakeOff(self)).Append(NextActivity).ToArray());
if (aircraft.IsPlane)
{
inner = ActivityUtils.SequenceActivities(
aircraft.GetResupplyActivities(host)
.Append(new CallFunc(() => aircraft.MayYieldReservation = true))
.Append(new WaitFor(() => NextActivity != null || aircraft.ReservedActor == null))
.ToArray());
}
else
{
// Helicopters should take off from their helipad immediately after resupplying.
// HACK: NextActivity needs to be appended here because otherwise TakeOff does stupid things.
inner = ActivityUtils.SequenceActivities(
aircraft.GetResupplyActivities(host).Append(new TakeOff(self)).Append(NextActivity).ToArray());
}
}
else
inner = ActivityUtils.RunActivity(self, inner);
// The inner == NextActivity check is needed here because of the TakeOff issue mentioned in the comment above.
return inner == null || inner == NextActivity ? NextActivity : this;
}
public override void Cancel(Actor self)
{
if (!IsCanceled && inner != null)
inner.Cancel(self);
base.Cancel(self);
} }
} }
} }

View File

@@ -104,13 +104,14 @@ namespace OpenRA.Mods.Common.Traits
UpgradeManager um; UpgradeManager um;
IDisposable reservation; IDisposable reservation;
Actor reservedActor;
IEnumerable<int> speedModifiers; IEnumerable<int> speedModifiers;
[Sync] public int Facing { get; set; } [Sync] public int Facing { get; set; }
[Sync] public WPos CenterPosition { get; private set; } [Sync] public WPos CenterPosition { get; private set; }
public CPos TopLeft { get { return self.World.Map.CellContaining(CenterPosition); } } public CPos TopLeft { get { return self.World.Map.CellContaining(CenterPosition); } }
public int TurnSpeed { get { return Info.TurnSpeed; } } public int TurnSpeed { get { return Info.TurnSpeed; } }
public Actor ReservedActor { get; private set; }
public bool MayYieldReservation;
bool airborne; bool airborne;
bool cruising; bool cruising;
@@ -190,7 +191,7 @@ namespace OpenRA.Mods.Common.Traits
if (reservation != null) if (reservation != null)
{ {
var distanceFromReservationActor = (reservedActor.CenterPosition - self.CenterPosition).HorizontalLength; var distanceFromReservationActor = (ReservedActor.CenterPosition - self.CenterPosition).HorizontalLength;
if (distanceFromReservationActor < Info.WaitDistanceFromResupplyBase.Length) if (distanceFromReservationActor < Info.WaitDistanceFromResupplyBase.Length)
return WVec.Zero; return WVec.Zero;
} }
@@ -277,7 +278,7 @@ namespace OpenRA.Mods.Common.Traits
if (reservable != null) if (reservable != null)
{ {
reservation = reservable.Reserve(target, self, this); reservation = reservable.Reserve(target, self, this);
reservedActor = target; ReservedActor = target;
} }
} }
@@ -288,7 +289,8 @@ namespace OpenRA.Mods.Common.Traits
reservation.Dispose(); reservation.Dispose();
reservation = null; reservation = null;
reservedActor = null; ReservedActor = null;
MayYieldReservation = false;
if (self.World.Map.DistanceAboveTerrain(CenterPosition).Length <= Info.LandAltitude.Length) if (self.World.Map.DistanceAboveTerrain(CenterPosition).Length <= Info.LandAltitude.Length)
self.QueueActivity(new TakeOff(self)); self.QueueActivity(new TakeOff(self));
@@ -614,8 +616,6 @@ namespace OpenRA.Mods.Common.Traits
self.QueueActivity(new ResupplyAircraft(self)); self.QueueActivity(new ResupplyAircraft(self));
} }
else
UnReserve();
} }
#endregion #endregion

View File

@@ -29,11 +29,19 @@ namespace OpenRA.Mods.Common.Traits
return; /* nothing to do */ return; /* nothing to do */
if (!Target.FromActor(reservedFor).IsValidFor(self)) if (!Target.FromActor(reservedFor).IsValidFor(self))
reservedFor = null; /* not likely to arrive now. */ {
/* Not likely to arrive now. */
reservedForAircraft.UnReserve();
reservedFor = null;
reservedForAircraft = null;
}
} }
public IDisposable Reserve(Actor self, Actor forActor, Aircraft forAircraft) public IDisposable Reserve(Actor self, Actor forActor, Aircraft forAircraft)
{ {
if (reservedForAircraft != null && reservedForAircraft.MayYieldReservation)
reservedForAircraft.UnReserve();
reservedFor = forActor; reservedFor = forActor;
reservedForAircraft = forAircraft; reservedForAircraft = forAircraft;
@@ -53,7 +61,7 @@ namespace OpenRA.Mods.Common.Traits
public static bool IsReserved(Actor a) public static bool IsReserved(Actor a)
{ {
var res = a.TraitOrDefault<Reservable>(); var res = a.TraitOrDefault<Reservable>();
return res != null && res.reservedFor != null; return res != null && res.reservedForAircraft != null && !res.reservedForAircraft.MayYieldReservation;
} }
public void Disposing(Actor self) public void Disposing(Actor self)