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: