diff --git a/OpenRa.DataStructures/DisposableAction.cs b/OpenRa.DataStructures/DisposableAction.cs new file mode 100644 index 0000000000..569e911adb --- /dev/null +++ b/OpenRa.DataStructures/DisposableAction.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa +{ + public class DisposableAction : IDisposable + { + public DisposableAction(Action a) { this.a = a; } + + Action a; + bool disposed; + + public void Dispose() + { + if (disposed) return; + disposed = true; + a(); + GC.SuppressFinalize(this); + } + + ~DisposableAction() + { + Dispose(); + } + } +} diff --git a/OpenRa.DataStructures/OpenRa.DataStructures.csproj b/OpenRa.DataStructures/OpenRa.DataStructures.csproj index f794fd193f..8da1f21edd 100644 --- a/OpenRa.DataStructures/OpenRa.DataStructures.csproj +++ b/OpenRa.DataStructures/OpenRa.DataStructures.csproj @@ -43,6 +43,7 @@ + diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 862d08208e..9d3a831fdb 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -196,6 +196,7 @@ + diff --git a/OpenRa.Game/Traits/Activities/ReturnToBase.cs b/OpenRa.Game/Traits/Activities/ReturnToBase.cs index 20a746fac4..a67fbe21e1 100644 --- a/OpenRa.Game/Traits/Activities/ReturnToBase.cs +++ b/OpenRa.Game/Traits/Activities/ReturnToBase.cs @@ -16,13 +16,18 @@ namespace OpenRa.Game.Traits.Activities float2 w1, w2, w3; /* tangent points to turn circles */ float2 landPoint; + static bool IsReserved(Actor a) + { + var res = a.traits.GetOrDefault(); + return res != null && res.IsReserved; + } + Actor ChooseAirfield(Actor self) { - // todo: handle reservations - var airfield = Game.world.Actors .Where(a => a.Info == Rules.UnitInfo["AFLD"] - && a.Owner == self.Owner) + && a.Owner == self.Owner + && !IsReserved(a)) .FirstOrDefault(); if (airfield == null) @@ -34,6 +39,9 @@ namespace OpenRa.Game.Traits.Activities void Calculate(Actor self) { if (dest == null) dest = ChooseAirfield(self); + var res = dest.traits.GetOrDefault(); + if (res != null) + self.traits.Get().reservation = res.Reserve(self); var landPos = dest.CenterLocation; var unit = self.traits.Get(); diff --git a/OpenRa.Game/Traits/Plane.cs b/OpenRa.Game/Traits/Plane.cs index f0accf7995..c4f7de0772 100644 --- a/OpenRa.Game/Traits/Plane.cs +++ b/OpenRa.Game/Traits/Plane.cs @@ -8,6 +8,8 @@ namespace OpenRa.Game.Traits { class Plane : IOrder, IMovement { + public IDisposable reservation; + public Plane(Actor self) {} public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) @@ -15,16 +17,28 @@ namespace OpenRa.Game.Traits if (mi.Button == MouseButton.Left) return null; if (underCursor == null) return new Order("Move", self, null, xy, null); - - if (underCursor.Info == Rules.UnitInfo["AFLD"] + + if (underCursor.Info == Rules.UnitInfo["AFLD"] && underCursor.Owner == self.Owner) + { + var res = underCursor.traits.GetOrDefault(); + if (res != null && res.IsReserved) + return null; + return new Order("Enter", self, underCursor, int2.Zero, null); + } return null; } public void ResolveOrder(Actor self, Order order) { + if (reservation != null) + { + reservation.Dispose(); + reservation = null; + } + if (order.OrderString == "Move") { self.CancelActivity(); @@ -34,6 +48,13 @@ namespace OpenRa.Game.Traits if (order.OrderString == "Enter") { + var res = order.TargetActor.traits.GetOrDefault(); + if (res != null) + { + if (res.IsReserved) return; + reservation = res.Reserve(self); + } + self.CancelActivity(); self.QueueActivity(new ReturnToBase(self, order.TargetActor)); } diff --git a/OpenRa.Game/Traits/Reservable.cs b/OpenRa.Game/Traits/Reservable.cs new file mode 100644 index 0000000000..ca5e628863 --- /dev/null +++ b/OpenRa.Game/Traits/Reservable.cs @@ -0,0 +1,26 @@ +using System; + +namespace OpenRa.Game.Traits +{ + class Reservable : ITick + { + public Reservable(Actor self) { } + Actor reservedFor; + + public bool IsReserved { get { return reservedFor != null; } } + + public void Tick(Actor self) + { + if (reservedFor == null) + return; /* nothing to do */ + + if (reservedFor.IsDead) reservedFor = null; /* not likely to arrive now. */ + } + + public IDisposable Reserve(Actor forActor) + { + reservedFor = forActor; + return new DisposableAction(() => reservedFor = null); + } + } +} diff --git a/units.ini b/units.ini index 390f224e98..20482cf46b 100644 --- a/units.ini +++ b/units.ini @@ -394,7 +394,7 @@ LongDesc=Stores excess harvested Ore [HPAD] Description=Helipad -Traits=Building, RenderBuilding, Production, BelowUnits +Traits=Building, RenderBuilding, Production, BelowUnits, Reservable Dimensions=2,2 Footprint=xx xx Produces=Plane @@ -410,7 +410,7 @@ SelectionPriority=3 LongDesc=Provides an overview of the battlefield.\n Requires power to operate. [AFLD] Description=Airstrip -Traits=Building, RenderBuilding, Production, BelowUnits +Traits=Building, RenderBuilding, Production, BelowUnits, Reservable Dimensions=3,2 Footprint=xxx xxx Produces=Plane @@ -465,7 +465,7 @@ SelectionPriority=3 LongDesc=Produces attack dogs [FIX] Description=Service Depot -Traits=Building, RenderBuilding, BelowUnits +Traits=Building, RenderBuilding, BelowUnits, Reservable Dimensions=3,3 Footprint=_x_ xxx _x_ SelectionPriority=3