diff --git a/OpenRA.Mods.Common/Traits/Buildings/FreeActor.cs b/OpenRA.Mods.Common/Traits/Buildings/FreeActor.cs
index 8364dc2961..1d98270c79 100644
--- a/OpenRA.Mods.Common/Traits/Buildings/FreeActor.cs
+++ b/OpenRA.Mods.Common/Traits/Buildings/FreeActor.cs
@@ -19,16 +19,19 @@ namespace OpenRA.Mods.Common.Traits
public class FreeActorInfo : ITraitInfo
{
[ActorReference]
- [Desc("Name of actor (use HARV if this trait is for refineries)")]
+ [Desc("Name of the actor.")]
public readonly string Actor = null;
+
[Desc("What the unit should start doing. Warning: If this is not a harvester", "it will break if you use FindResources.")]
public readonly string InitialActivity = null;
- [Desc("Offset relative to structure-center in 2D (e.g. 1, 2)")]
+
+ [Desc("Offset relative to the top-left cell of the building.")]
public readonly CVec SpawnOffset = CVec.Zero;
+
[Desc("Which direction the unit should face.")]
public readonly int Facing = 0;
- public object Create(ActorInitializer init) { return new FreeActor(init, this); }
+ public virtual object Create(ActorInitializer init) { return new FreeActor(init, this); }
}
public class FreeActor
diff --git a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj
index 6c51e130fd..d4eb67f98e 100644
--- a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj
+++ b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj
@@ -74,6 +74,7 @@
+
diff --git a/OpenRA.Mods.D2k/Traits/Buildings/FreeActorWithDelivery.cs b/OpenRA.Mods.D2k/Traits/Buildings/FreeActorWithDelivery.cs
new file mode 100644
index 0000000000..fd9f57ee65
--- /dev/null
+++ b/OpenRA.Mods.D2k/Traits/Buildings/FreeActorWithDelivery.cs
@@ -0,0 +1,110 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
+ * This file is part of OpenRA, which is free software. It is made
+ * available to you under the terms of the GNU General Public License
+ * as published by the Free Software Foundation. For more information,
+ * see COPYING.
+ */
+#endregion
+
+using System.IO;
+using OpenRA.Activities;
+using OpenRA.Mods.Common.Activities;
+using OpenRA.Mods.Common.Traits;
+using OpenRA.Mods.D2k.Activities;
+using OpenRA.Primitives;
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.D2k.Traits
+{
+ [Desc("Player receives a unit for free once the building is placed.",
+ "If you want more than one unit to be delivered, copy this section and assign IDs like FreeActorWithDelivery@2, ...")]
+ public class FreeActorWithDeliveryInfo : FreeActorInfo
+ {
+ [ActorReference]
+ [Desc("Name of the delivering actor. This actor must have the `Carryall` trait")]
+ public readonly string DeliveringActor = null;
+
+ [Desc("Cell coordinates for spawning the delivering actor. If left blank, the closest edge cell will be chosen.")]
+ public readonly CPos SpawnLocation = CPos.Zero;
+
+ [Desc("Offset relative to the top-left cell of the building.")]
+ public readonly CVec DeliveryOffset = CVec.Zero;
+
+ public override object Create(ActorInitializer init) { return new FreeActorWithDelivery(init, this); }
+ }
+
+ public class FreeActorWithDelivery
+ {
+ public readonly FreeActorWithDeliveryInfo Info;
+
+ readonly Actor self;
+
+ public FreeActorWithDelivery(ActorInitializer init, FreeActorWithDeliveryInfo info)
+ {
+ if (string.IsNullOrEmpty(info.Actor))
+ throw new InvalidDataException("Actor type was not specified!");
+ if (string.IsNullOrEmpty(info.DeliveringActor))
+ throw new InvalidDataException("Delivering actor type was not specified!");
+
+ self = init.Self;
+ Info = info;
+
+ DoDelivery(self.Location + info.DeliveryOffset, info.Actor, info.DeliveringActor, info.InitialActivity);
+ }
+
+ public void DoDelivery(CPos location, string actorName, string carrierActorName, string clientInitialActivity)
+ {
+ Actor cargo;
+ Actor carrier;
+
+ CreateActors(actorName, carrierActorName, out cargo, out carrier);
+
+ if (clientInitialActivity != null)
+ cargo.QueueActivity(Game.CreateObject(clientInitialActivity));
+
+ cargo.Trait().Destination = location;
+
+ carrier.Trait().AttachCarryable(cargo);
+
+ carrier.QueueActivity(new DeliverUnit(carrier));
+ carrier.QueueActivity(new HeliFly(carrier, Target.FromCell(self.World, self.World.Map.ChooseRandomEdgeCell(self.World.SharedRandom))));
+ carrier.QueueActivity(new RemoveSelf());
+
+ self.World.AddFrameEndTask(w => self.World.Add(carrier));
+ }
+
+ void CreateActors(string actorName, string deliveringActorName, out Actor cargo, out Actor carrier)
+ {
+ // Get a carryall spawn location
+ var location = Info.SpawnLocation;
+ if (location == CPos.Zero)
+ location = self.World.Map.ChooseClosestEdgeCell(self.Location);
+
+ var spawn = self.World.Map.CenterOfCell(location);
+
+ var initialFacing = self.World.Map.FacingBetween(location, self.Location, 0);
+
+ // If aircraft, spawn at cruise altitude
+ var aircraftInfo = self.World.Map.Rules.Actors[deliveringActorName.ToLower()].Traits.GetOrDefault();
+ if (aircraftInfo != null)
+ spawn += new WVec(0, 0, aircraftInfo.CruiseAltitude.Range);
+
+ // Create delivery actor
+ carrier = self.World.CreateActor(false, deliveringActorName, new TypeDictionary
+ {
+ new LocationInit(location),
+ new CenterPositionInit(spawn),
+ new OwnerInit(self.Owner),
+ new FacingInit(initialFacing)
+ });
+
+ // Create delivered actor
+ cargo = self.World.CreateActor(false, actorName, new TypeDictionary
+ {
+ new OwnerInit(self.Owner),
+ });
+ }
+ }
+}
diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml
index b7ce2f1bc8..e5180043b1 100644
--- a/mods/d2k/rules/structures.yaml
+++ b/mods/d2k/rules/structures.yaml
@@ -194,10 +194,11 @@ refinery:
Capacity: 2000
CustomSellValue:
Value: 500
- FreeActor:
+ FreeActorWithDelivery:
Actor: harvester
InitialActivity: FindResources
- SpawnOffset: 2,1
+ DeliveryOffset: 2,2
+ DeliveringActor: carryall.reinforce
Facing: 160
-RenderBuilding:
RenderBuildingWarFactory: