diff --git a/OpenRA.Mods.Cnc/Render/WithCargo.cs b/OpenRA.Mods.Cnc/Render/WithCargo.cs index cdc489ca56..1604b517f3 100644 --- a/OpenRA.Mods.Cnc/Render/WithCargo.cs +++ b/OpenRA.Mods.Cnc/Render/WithCargo.cs @@ -64,7 +64,8 @@ namespace OpenRA.Mods.Cnc var cargoPassenger = c.Trait(); if (cargoInfo.DisplayTypes.Contains(cargoPassenger.Info.CargoType)) { - var offset = pos - c.CenterPosition + body.LocalToWorld(cargoInfo.LocalOffset[i++ % cargoInfo.LocalOffset.Length].Rotate(bodyOrientation)); + var localOffset = cargo.PassengerCount > 1 ? cargoInfo.LocalOffset[i++ % cargoInfo.LocalOffset.Length] : WVec.Zero; + var offset = pos - c.CenterPosition + body.LocalToWorld(localOffset.Rotate(bodyOrientation)); foreach (var cr in c.Render(wr)) yield return cr.OffsetBy(offset).WithZOffset(1); } diff --git a/OpenRA.Mods.RA/Cargo.cs b/OpenRA.Mods.RA/Cargo.cs index eadf368a71..be8a49002b 100644 --- a/OpenRA.Mods.RA/Cargo.cs +++ b/OpenRA.Mods.RA/Cargo.cs @@ -45,6 +45,7 @@ namespace OpenRA.Mods.RA public IEnumerable CurrentAdjacentCells { get; private set; } public bool Unloading { get; internal set; } public IEnumerable Passengers { get { return cargo; } } + public int PassengerCount { get { return cargo.Count; } } public Cargo(ActorInitializer init, CargoInfo info) { diff --git a/OpenRA.Mods.RA/Scripting/Global/ActorGlobal.cs b/OpenRA.Mods.RA/Scripting/Global/ActorGlobal.cs index c7c3ba6554..178d07a2ef 100644 --- a/OpenRA.Mods.RA/Scripting/Global/ActorGlobal.cs +++ b/OpenRA.Mods.RA/Scripting/Global/ActorGlobal.cs @@ -39,11 +39,12 @@ namespace OpenRA.Scripting var genericType = initType.GetInterfaces() .First(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IActorInit<>)); var innerType = genericType.GetGenericArguments().First(); + var valueType = innerType.IsEnum ? typeof(int) : innerType; // Try and coerce the table value to the required type object value; - if (!kv.Value.TryGetClrValue(innerType, out value)) - throw new LuaException("Invalid data type for '{0}' (expected '{1}')".F(typeName, innerType.Name)); + if (!kv.Value.TryGetClrValue(valueType, out value)) + throw new LuaException("Invalid data type for '{0}' (expected '{1}')".F(typeName, valueType.Name)); // Construct the ActorInit. Phew! var test = initType.GetConstructor(new[] { innerType }).Invoke(new[] { value }); diff --git a/OpenRA.Mods.RA/Scripting/Global/ReinforcementsGlobal.cs b/OpenRA.Mods.RA/Scripting/Global/ReinforcementsGlobal.cs index 5eed25090d..0e9462bd57 100644 --- a/OpenRA.Mods.RA/Scripting/Global/ReinforcementsGlobal.cs +++ b/OpenRA.Mods.RA/Scripting/Global/ReinforcementsGlobal.cs @@ -117,7 +117,7 @@ namespace OpenRA.Mods.RA.Scripting { foreach (var cargoType in cargoTypes) { - var passenger = CreateActor(owner, cargoType, false); + var passenger = CreateActor(owner, cargoType, false, entryPath[0]); passengers.Add(passenger); cargo.Load(transport, passenger); } diff --git a/OpenRA.Mods.RA/Scripting/Properties/MobileProperties.cs b/OpenRA.Mods.RA/Scripting/Properties/MobileProperties.cs index 0af7444f78..e04f39c820 100644 --- a/OpenRA.Mods.RA/Scripting/Properties/MobileProperties.cs +++ b/OpenRA.Mods.RA/Scripting/Properties/MobileProperties.cs @@ -17,8 +17,13 @@ namespace OpenRA.Mods.RA.Scripting [ScriptPropertyGroup("Movement")] public class MobileProperties : ScriptActorProperties, Requires { + readonly Mobile mobile; + public MobileProperties(ScriptContext context, Actor self) - : base(context, self) { } + : base(context, self) + { + mobile = self.Trait(); + } [ScriptActorPropertyActivity] [Desc("Moves within the cell grid. closeEnough defines an optional range " + @@ -35,6 +40,13 @@ namespace OpenRA.Mods.RA.Scripting self.QueueActivity(new Move.Move(self, cell)); } + [ScriptActorPropertyActivity] + [Desc("Moves from outside the world into the cell grid")] + public void MoveIntoWorld(CPos cell) + { + self.QueueActivity(mobile.MoveIntoWorld(self, cell, mobile.toSubCell)); + } + [ScriptActorPropertyActivity] [Desc("Leave the current position in a random direction.")] public void Scatter() diff --git a/OpenRA.Mods.RA/Scripting/Properties/TransportProperties.cs b/OpenRA.Mods.RA/Scripting/Properties/TransportProperties.cs index ff826ed717..670ffbb266 100644 --- a/OpenRA.Mods.RA/Scripting/Properties/TransportProperties.cs +++ b/OpenRA.Mods.RA/Scripting/Properties/TransportProperties.cs @@ -33,6 +33,9 @@ namespace OpenRA.Mods.RA.Scripting [Desc("Teleport an existing actor inside this transport.")] public void LoadPassenger(Actor a) { cargo.Load(self, a); } + [Desc("Remove the first actor from the transport. This actor is not added to the world.")] + public Actor UnloadPassenger() { return cargo.Unload(self); } + [ScriptActorPropertyActivity] [Desc("Command transport to unload passengers.")] public void UnloadPassengers() diff --git a/mods/cnc/maps/gdi01/gdi01.lua b/mods/cnc/maps/gdi01/gdi01.lua index 63203f3e74..a72f09d2d5 100644 --- a/mods/cnc/maps/gdi01/gdi01.lua +++ b/mods/cnc/maps/gdi01/gdi01.lua @@ -1,3 +1,4 @@ +MCVReinforcements = { "mcv" } InfantryReinforcements = { "e1", "e1", "e1" } VehicleReinforcements = { "jeep" } NodPatrol = { "e1", "e1" } @@ -15,9 +16,36 @@ SetGunboatPath = function(gunboat) gunboat.AttackMove(gunboatRight.Location) end +ReinforceWithLandingCraft = function(units, transportStart, transportUnload, rallypoint) + local transport = Actor.Create("oldlst", true, { Owner = player, Facing = 0, Location = transportStart }) + local subcell = 0 + Utils.Do(units, function(a) + transport.LoadPassenger(Actor.Create(a, false, { Owner = transport.Owner, Facing = transport.Facing, Location = transportUnload, SubCell = subcell })) + subcell = subcell + 1 + end) + + transport.ScriptedMove(transportUnload) + + transport.CallFunc(function() + Utils.Do(units, function() + local a = transport.UnloadPassenger() + a.IsInWorld = true + a.MoveIntoWorld(transport.Location - CVec.New(0, 1)) + + if rallypoint ~= nil then + a.Move(rallypoint) + end + end) + end) + + transport.Wait(5) + transport.ScriptedMove(transportStart) + transport.Destroy() +end + Reinforce = function(units) Media.PlaySpeechNotification(player, "Reinforce") - Reinforcements.ReinforceWithTransport(player, "oldlst", units, { lstStart.Location, lstEnd.Location }, { lstStart.Location }) + ReinforceWithLandingCraft(units, lstStart.Location, lstEnd.Location, reinforcementsTarget.Location) end triggerAdded = false @@ -39,7 +67,6 @@ CheckForBase = function() end WorldLoaded = function() - Media.PlayMovieFullscreen("landing.vqa") player = Player.GetPlayer("GDI") enemy = Player.GetPlayer("Nod") @@ -68,17 +95,20 @@ WorldLoaded = function() end) end) - nodObjective = enemy.AddPrimaryObjective("Destroy all GDI troops") - gdiObjective1 = player.AddPrimaryObjective("Eliminate all Nod forces in the area") - gdiObjective2 = player.AddSecondaryObjective("Establish a beachhead") + Media.PlayMovieFullscreen("landing.vqa", function() + nodObjective = enemy.AddPrimaryObjective("Destroy all GDI troops") + gdiObjective1 = player.AddPrimaryObjective("Eliminate all Nod forces in the area") + gdiObjective2 = player.AddSecondaryObjective("Establish a beachhead") + + ReinforceWithLandingCraft(MCVReinforcements, lstStart.Location + CVec.New(2, 0), lstEnd.Location + CVec.New(2, 0), mcvTarget.Location) + Reinforce(InfantryReinforcements) + end) Trigger.OnIdle(Gunboat, function() SetGunboatPath(Gunboat) end) SendNodPatrol() - Trigger.AfterDelay(DateTime.Seconds(5), function() Reinforce(InfantryReinforcements) end) - Trigger.AfterDelay(DateTime.Seconds(15), function() Reinforce(InfantryReinforcements) end) - Trigger.AfterDelay(DateTime.Seconds(30), function() Reinforce(VehicleReinforcements) end) + Trigger.AfterDelay(DateTime.Seconds(10), function() Reinforce(InfantryReinforcements) end) Trigger.AfterDelay(DateTime.Seconds(60), function() Reinforce(VehicleReinforcements) end) end @@ -90,7 +120,7 @@ Tick = function() player.MarkCompletedObjective(gdiObjective1) end - if player.HasNoRequiredUnits() then + if tick > DateTime.Seconds(5) and player.HasNoRequiredUnits() then enemy.MarkCompletedObjective(nodObjective) end diff --git a/mods/cnc/maps/gdi01/map.yaml b/mods/cnc/maps/gdi01/map.yaml index 5dcf266b5c..8fc60d9c8c 100644 --- a/mods/cnc/maps/gdi01/map.yaml +++ b/mods/cnc/maps/gdi01/map.yaml @@ -327,40 +327,11 @@ Actors: Owner: Nod Health: 0.1875 Facing: 160 - mcv: mcv - Location: 56,53 - Owner: GDI - Health: 1 - Facing: 0 Gunboat: boat - Location: 53,59 + Location: 51,59 Owner: GDI Health: 1 Facing: 64 - Actor88: e1 - Location: 56,55 - Owner: GDI - Health: 1 - Facing: 0 - SubCell: 2 - Actor89: e1 - Location: 56,55 - Owner: GDI - Health: 1 - Facing: 0 - SubCell: 4 - Actor90: e1 - Location: 56,55 - Owner: GDI - Health: 1 - Facing: 0 - SubCell: 3 - Actor91: e1 - Location: 56,55 - Owner: GDI - Health: 1 - Facing: 0 - SubCell: 1 Actor92: e1 Location: 57,45 Owner: Nod @@ -448,6 +419,12 @@ Actors: lstEnd: waypoint Location: 54,57 Owner: Neutral + mcvTarget: waypoint + Location: 56,53 + Owner: Neutral + reinforcementsTarget: waypoint + Location: 54,53 + Owner: Neutral Smudges: @@ -545,6 +522,9 @@ Rules: ATWR: Buildable: Prerequisites: ~disabled + BRIK: + Buildable: + Prerequisites: ~disabled E2: Buildable: Prerequisites: ~disabled @@ -575,9 +555,7 @@ Sequences: idle: lst Start: 0 Facings: 1 - unload: lst - Start: 0 - Facings: 1 + ZOffset: -1024 VoxelSequences: diff --git a/mods/cnc/maps/gdi02/gdi02.lua b/mods/cnc/maps/gdi02/gdi02.lua index 3229f25725..dd58233f75 100644 --- a/mods/cnc/maps/gdi02/gdi02.lua +++ b/mods/cnc/maps/gdi02/gdi02.lua @@ -5,9 +5,36 @@ VehicleReinforcements = { "jeep" } AttackerSquadSize = 3 -Reinforce = function(passengers) - Reinforcements.ReinforceWithTransport(player, "oldlst", passengers, { lstStart.Location, lstEnd.Location }, { lstStart.Location }) +ReinforceWithLandingCraft = function(units, transportStart, transportUnload, rallypoint) + local transport = Actor.Create("oldlst", true, { Owner = player, Facing = 0, Location = transportStart }) + local subcell = 0 + Utils.Do(units, function(a) + transport.LoadPassenger(Actor.Create(a, false, { Owner = transport.Owner, Facing = transport.Facing, Location = transportUnload, SubCell = subcell })) + subcell = subcell + 1 + end) + + transport.ScriptedMove(transportUnload) + + transport.CallFunc(function() + Utils.Do(units, function() + local a = transport.UnloadPassenger() + a.IsInWorld = true + a.MoveIntoWorld(transport.Location - CVec.New(0, 1)) + + if rallypoint ~= nil then + a.Move(rallypoint) + end + end) + end) + + transport.Wait(5) + transport.ScriptedMove(transportStart) + transport.Destroy() +end + +Reinforce = function(units) Media.PlaySpeechNotification(player, "Reinforce") + ReinforceWithLandingCraft(units, lstStart.Location, lstEnd.Location) end BridgeheadSecured = function() @@ -61,6 +88,15 @@ WorldLoaded = function() gdiObjective1 = player.AddPrimaryObjective("Eliminate all Nod forces in the area") gdiObjective2 = player.AddSecondaryObjective("Capture the Tiberium Refinery") + -- Work around limitations with the yaml merger that prevent MustBeDestroyed from working on the silos + siloARemoved = false + Trigger.OnCapture(SiloA, function() siloARemoved = true end) + Trigger.OnKilled(SiloA, function() siloARemoved = true end) + + siloBRemoved = false + Trigger.OnCapture(SiloB, function() siloBRemoved = true end) + Trigger.OnKilled(SiloB, function() siloBRemoved = true end) + Trigger.OnCapture(NodRefinery, function() player.MarkCompletedObjective(gdiObjective2) end) Trigger.OnKilled(NodRefinery, function() player.MarkFailedObjective(gdiObjective2) end) @@ -71,7 +107,7 @@ Tick = function() if player.HasNoRequiredUnits() then enemy.MarkCompletedObjective(nodObjective) end - if enemy.HasNoRequiredUnits() then + if enemy.HasNoRequiredUnits() and siloARemoved and siloBRemoved then player.MarkCompletedObjective(gdiObjective1) end end diff --git a/mods/cnc/maps/gdi02/map.yaml b/mods/cnc/maps/gdi02/map.yaml index ddd554fdbd..9baef5d6c2 100644 --- a/mods/cnc/maps/gdi02/map.yaml +++ b/mods/cnc/maps/gdi02/map.yaml @@ -302,12 +302,12 @@ Actors: Owner: GDI Health: 0.34375 Facing: 0 - Actor79: silo + SiloA: silo Location: 57,32 Owner: Nod Health: 1 Facing: 0 - Actor80: silo + SiloB: silo Location: 59,32 Owner: Nod Health: 1 @@ -800,6 +800,7 @@ Rules: Buildable: Prerequisites: ~disabled SILO: + MustBeDestroyed: Buildable: Prerequisites: ~disabled WEAP: @@ -873,9 +874,7 @@ Sequences: idle: lst Start: 0 Facings: 1 - unload: lst - Start: 0 - Facings: 1 + ZOffset: -1024 VoxelSequences: diff --git a/mods/cnc/rules/ships.yaml b/mods/cnc/rules/ships.yaml index 727d24cbc1..6e919293cb 100644 --- a/mods/cnc/rules/ships.yaml +++ b/mods/cnc/rules/ships.yaml @@ -64,7 +64,7 @@ LST: WithRoof: WithCargo: DisplayTypes: Infantry, Vehicle - LocalOffset: 0,0,0, -390,-256,0, 390,-256,0, -390,256,0, 390,256,0 + LocalOffset: 390,-256,0, 390,256,0, 0,0,0, -390,-256,0, -390,256,0 Cargo: Types: Infantry, Vehicle MaxWeight: 5