Merge pull request #4761 from ScottNZ/lua-desert-shellmap

Port the desert shellmap to Lua
This commit is contained in:
Matthias Mailänder
2014-03-06 08:11:34 +01:00
20 changed files with 865 additions and 2277 deletions

View File

@@ -45,6 +45,7 @@ NEW:
Added a snow variation of the Allied Barracks by Kilkakon.
Added a desert variation of the Allied Barracks by Kilkakon.
Added a desert variation of the Missile Silo by Kilkakon.
Removed the temperate shellmap and improved the design and performance of the desert shellmap.
Tiberian Dawn:
Commando can now plant C4 on bridges.
Added the Asset Browser to the Extras menu.

View File

@@ -1,72 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 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;
using System.Collections.Generic;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Air;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
class DefaultShellmapScriptInfo : TraitInfo<DefaultShellmapScript> { }
class DefaultShellmapScript: IWorldLoaded, ITick
{
Dictionary<string, Actor> Actors;
static WPos ViewportOrigin;
WorldRenderer worldRenderer;
public void WorldLoaded(World w, WorldRenderer wr)
{
worldRenderer = wr;
var b = w.Map.Bounds;
ViewportOrigin = new CPos(b.Left + b.Width/2, b.Top + b.Height/2).CenterPosition;
worldRenderer.Viewport.Center(ViewportOrigin);
Actors = w.WorldActor.Trait<SpawnMapActors>().Actors;
Sound.SoundVolumeModifier = 0.25f;
}
int ticks = 0;
float speed = 4f;
public void Tick(Actor self)
{
var t = (ticks + 45) % (360f * speed) * (Math.PI / 180) * 1f / speed;
var offset = new float2(15360, 10240) * float2.FromAngle((float)t);
worldRenderer.Viewport.Center(ViewportOrigin + new WVec((int)offset.X, (int)offset.Y, 0));
if (ticks == 50)
{
Scripting.RASpecialPowers.Chronoshift(self.World, new List<Pair<Actor, CPos>>()
{
Pair.New(Actors["ca1"], new CPos(96, 70)),
Pair.New(Actors["ca2"], new CPos(98, 72))
}, Actors["pdox"], -1, false);
}
if (ticks == 100)
Actors["mslo1"].Trait<NukePower>().Activate(Actors["mslo1"], new Order() { TargetLocation = new CPos(98, 52) });
if (ticks == 140)
Actors["mslo2"].Trait<NukePower>().Activate(Actors["mslo2"], new Order() { TargetLocation = new CPos(95, 54) });
if (ticks == 180)
Actors["mslo3"].Trait<NukePower>().Activate(Actors["mslo3"], new Order() { TargetLocation = new CPos(95, 49) });
if (ticks == 430)
{
Actors["mig1"].Trait<AttackPlane>().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true);
Actors["mig2"].Trait<AttackPlane>().AttackTarget(Target.FromActor(Actors["greeceweap"]), false, true);
}
ticks++;
}
}
}

View File

@@ -1,319 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 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.Collections.Generic;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Air;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Move;
using OpenRA.Mods.RA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Missions
{
class DesertShellmapScriptInfo : TraitInfo<DesertShellmapScript>, Requires<SpawnMapActorsInfo> { }
class DesertShellmapScript : ITick, IWorldLoaded
{
World world;
WorldRenderer worldRenderer;
Player allies;
Player soviets;
Player neutral;
WPos[] viewportTargets;
WPos viewportTarget;
int viewportTargetNumber;
WPos viewportOrigin;
int mul;
int div = 400;
int waitTicks = 0;
int nextCivilianMove = 1;
Actor attackLocation;
Actor coastWP1;
Actor coastWP2;
int coastUnitsLeft;
static readonly string[] CoastUnits = { "e1", "e1", "e2", "e3", "e4" };
Actor paradrop1LZ;
Actor paradrop1Entry;
Actor paradrop2LZ;
Actor paradrop2Entry;
static readonly string[] ParadropUnits = { "e1", "e1", "e1", "e2", "e2" };
Actor offmapAttackerSpawn1;
Actor offmapAttackerSpawn2;
Actor offmapAttackerSpawn3;
Actor[] offmapAttackerSpawns;
static readonly string[] OffmapAttackers = { "ftrk", "apc", "ttnk", "1tnk" };
static readonly string[] AttackerCargo = { "e1", "e2", "e3", "e4" };
static readonly string[] HeavyTanks = { "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk" };
Actor heavyTankSpawn;
Actor heavyTankWP;
static readonly string[] MediumTanks = { "2tnk", "2tnk", "2tnk", "2tnk", "2tnk", "2tnk" };
Actor mediumTankChronoSpawn;
static readonly string[] ChinookCargo = { "e1", "e1", "e1", "e1", "e3", "e3" };
static readonly string[] InfantryProductionUnits = { "e1", "e3" };
static readonly string[] VehicleProductionUnits = { "jeep", "1tnk", "2tnk", "arty" };
Actor alliedBarracks;
Actor alliedWarFactory;
Dictionary<string, Actor> actors;
Actor chronosphere;
Actor ironCurtain;
CPos[] mig1Waypoints;
CPos[] mig2Waypoints;
Actor chinook1Entry;
Actor chinook1LZ;
Actor chinook2Entry;
Actor chinook2LZ;
public void Tick(Actor self)
{
if (world.FrameNumber % 100 == 0)
{
var actor = OffmapAttackers.Random(world.SharedRandom);
var spawn = offmapAttackerSpawns.Random(world.SharedRandom);
var u = world.CreateActor(actor, soviets, spawn.Location, Traits.Util.GetFacing(attackLocation.Location - spawn.Location, 0));
var cargo = u.TraitOrDefault<Cargo>();
if (cargo != null)
{
while (cargo.HasSpace(1))
cargo.Load(u, world.CreateActor(false, AttackerCargo.Random(world.SharedRandom), soviets, null, null));
}
u.QueueActivity(new AttackMove.AttackMoveActivity(u, new Move.Move(attackLocation.Location, 0)));
}
if (world.FrameNumber % 25 == 0)
{
foreach (var actor in world.Actors.Where(a => a.IsInWorld && a.IsIdle && !a.IsDead()
&& a.HasTrait<AttackBase>() && a.HasTrait<Mobile>()).Except(actors.Values))
MissionUtils.AttackNearestLandActor(true, actor, actor.Owner == soviets ? allies : soviets);
MissionUtils.StartProduction(world, allies, "Infantry", InfantryProductionUnits.Random(world.SharedRandom));
MissionUtils.StartProduction(world, allies, "Vehicle", VehicleProductionUnits.Random(world.SharedRandom));
}
if (world.FrameNumber % 20 == 0 && coastUnitsLeft-- > 0)
{
var u = world.CreateActor(CoastUnits.Random(world.SharedRandom), soviets, coastWP1.Location, null);
u.QueueActivity(new Move.Move(coastWP2.Location, 0));
u.QueueActivity(new AttackMove.AttackMoveActivity(u, new Move.Move(attackLocation.Location, 0)));
}
if (world.FrameNumber == nextCivilianMove)
{
var civilians = world.Actors.Where(a => !a.IsDead() && a.IsInWorld && a.Owner == neutral && a.HasTrait<Mobile>());
if (civilians.Any())
{
var civilian = civilians.Random(world.SharedRandom);
civilian.Trait<Mobile>().Nudge(civilian, civilian, true);
nextCivilianMove += world.SharedRandom.Next(1, 75);
}
}
if (world.FrameNumber == 1)
{
MissionUtils.Paradrop(world, soviets, ParadropUnits, paradrop1Entry.Location, paradrop1LZ.Location);
MissionUtils.Paradrop(world, soviets, ParadropUnits, paradrop2Entry.Location, paradrop2LZ.Location);
}
if (--waitTicks <= 0)
{
if (++mul <= div)
worldRenderer.Viewport.Center(WPos.Lerp(viewportOrigin, viewportTarget, mul, div));
else
{
mul = 0;
viewportOrigin = viewportTarget;
viewportTarget = viewportTargets[(viewportTargetNumber = (viewportTargetNumber + 1) % viewportTargets.Length)];
waitTicks = 100;
if (viewportTargetNumber == 0)
{
coastUnitsLeft = 15;
SendChinookReinforcements(chinook1Entry.Location, chinook1LZ);
SendChinookReinforcements(chinook2Entry.Location, chinook2LZ);
}
if (viewportTargetNumber == 1)
{
MissionUtils.Paradrop(world, soviets, ParadropUnits, paradrop1Entry.Location, paradrop1LZ.Location);
MissionUtils.Paradrop(world, soviets, ParadropUnits, paradrop2Entry.Location, paradrop2LZ.Location);
}
if (viewportTargetNumber == 2)
{
AttackWithHeavyTanks();
ChronoSpawnMediumTanks();
}
if (viewportTargetNumber == 4)
{
FlyMigs(mig1Waypoints);
FlyMigs(mig2Waypoints);
}
}
}
MissionUtils.CapOre(soviets);
}
void AttackWithHeavyTanks()
{
foreach (var tank in HeavyTanks)
{
var u = world.CreateActor(tank, soviets, heavyTankSpawn.Location, Traits.Util.GetFacing(heavyTankWP.Location - heavyTankSpawn.Location, 0));
u.QueueActivity(new AttackMove.AttackMoveActivity(u, new Move.Move(heavyTankWP.Location, 0)));
}
ironCurtain.Trait<IronCurtainPower>().Activate(ironCurtain, new Order { TargetLocation = heavyTankSpawn.Location });
}
void ChronoSpawnMediumTanks()
{
var chronoInfo = new List<Pair<Actor, CPos>>();
foreach (var tank in MediumTanks.Select((x, i) => new { x, i }))
{
var u = world.CreateActor(tank.x, allies, mediumTankChronoSpawn.Location, Traits.Util.GetFacing(heavyTankWP.Location - mediumTankChronoSpawn.Location, 0));
chronoInfo.Add(Pair.New(u, new CPos(mediumTankChronoSpawn.Location.X + tank.i, mediumTankChronoSpawn.Location.Y)));
}
RASpecialPowers.Chronoshift(world, chronoInfo, chronosphere, -1, false);
foreach (var tank in chronoInfo)
tank.First.QueueActivity(new AttackMove.AttackMoveActivity(tank.First, new Move.Move(heavyTankSpawn.Location, 0)));
}
void FlyMigs(CPos[] waypoints)
{
var m = world.CreateActor("mig", new TypeDictionary
{
new OwnerInit(soviets),
new LocationInit(waypoints[0]),
new FacingInit(Traits.Util.GetFacing(waypoints[1] - waypoints[0], 0))
});
foreach (var waypoint in waypoints)
m.QueueActivity(new Fly(m, Target.FromCell(waypoint)));
m.QueueActivity(new RemoveSelf());
}
void SendChinookReinforcements(CPos entry, Actor lz)
{
var chinook = world.CreateActor("tran", allies, entry, Traits.Util.GetFacing(lz.Location - entry, 0));
var cargo = chinook.Trait<Cargo>();
while (cargo.HasSpace(1))
cargo.Load(chinook, world.CreateActor(false, ChinookCargo.Random(world.SharedRandom), allies, null, null));
var exit = lz.Info.Traits.WithInterface<ExitInfo>().FirstOrDefault();
var offset = (exit != null) ? exit.SpawnOffset : WVec.Zero;
chinook.QueueActivity(new HeliFly(chinook, Target.FromPos(lz.CenterPosition + offset))); // no reservation of hpad but it's not needed
chinook.QueueActivity(new Turn(0));
chinook.QueueActivity(new HeliLand(false));
chinook.QueueActivity(new UnloadCargo(chinook, true));
chinook.QueueActivity(new Wait(150));
chinook.QueueActivity(new HeliFly(chinook, Target.FromCell(entry)));
chinook.QueueActivity(new RemoveSelf());
}
void InitializeAlliedFactories()
{
alliedBarracks.Trait<PrimaryBuilding>().SetPrimaryProducer(alliedBarracks, true);
alliedWarFactory.Trait<PrimaryBuilding>().SetPrimaryProducer(alliedWarFactory, true);
}
public void WorldLoaded(World w, WorldRenderer wr)
{
world = w;
worldRenderer = wr;
allies = w.Players.Single(p => p.InternalName == "Allies");
soviets = w.Players.Single(p => p.InternalName == "Soviets");
neutral = w.Players.Single(p => p.InternalName == "Neutral");
actors = w.WorldActor.Trait<SpawnMapActors>().Actors;
attackLocation = actors["AttackLocation"];
coastWP1 = actors["CoastWP1"];
coastWP2 = actors["CoastWP2"];
paradrop1LZ = actors["Paradrop1LZ"];
paradrop1Entry = actors["Paradrop1Entry"];
paradrop2LZ = actors["Paradrop2LZ"];
paradrop2Entry = actors["Paradrop2Entry"];
var t1 = actors["ViewportTarget1"].CenterPosition;
var t2 = actors["ViewportTarget2"].CenterPosition;
var t3 = actors["ViewportTarget3"].CenterPosition;
var t4 = actors["ViewportTarget4"].CenterPosition;
var t5 = actors["ViewportTarget5"].CenterPosition;
viewportTargets = new[] { t1, t2, t3, t4, t5 };
offmapAttackerSpawn1 = actors["OffmapAttackerSpawn1"];
offmapAttackerSpawn2 = actors["OffmapAttackerSpawn2"];
offmapAttackerSpawn3 = actors["OffmapAttackerSpawn3"];
offmapAttackerSpawns = new[] { offmapAttackerSpawn1, offmapAttackerSpawn2, offmapAttackerSpawn3 };
heavyTankSpawn = actors["HeavyTankSpawn"];
heavyTankWP = actors["HeavyTankWP"];
mediumTankChronoSpawn = actors["MediumTankChronoSpawn"];
chronosphere = actors["Chronosphere"];
ironCurtain = actors["IronCurtain"];
mig1Waypoints = new[] { actors["Mig11"], actors["Mig12"], actors["Mig13"], actors["Mig14"] }.Select(a => a.Location).ToArray();
mig2Waypoints = new[] { actors["Mig21"], actors["Mig22"], actors["Mig23"], actors["Mig24"] }.Select(a => a.Location).ToArray();
chinook1Entry = actors["Chinook1Entry"];
chinook2Entry = actors["Chinook2Entry"];
chinook1LZ = actors["Chinook1LZ"];
chinook2LZ = actors["Chinook2LZ"];
alliedBarracks = actors["AlliedBarracks"];
alliedWarFactory = actors["AlliedWarFactory"];
InitializeAlliedFactories();
foreach (var actor in actors.Values)
{
if (actor.Owner == allies && actor.HasTrait<AutoTarget>())
actor.Trait<AutoTarget>().Stance = UnitStance.Defend;
if (actor.IsInWorld && (actor.HasTrait<Bridge>() || actor.Owner == allies || (actor.Owner == soviets && actor.HasTrait<Building>())))
actor.AddTrait(new Invulnerable());
}
viewportOrigin = viewportTargets[0];
viewportTargetNumber = 1;
viewportTarget = viewportTargets[1];
wr.Viewport.Center(viewportOrigin);
Sound.SoundVolumeModifier = 0.1f;
}
}
class DesertShellmapAutoUnloadInfo : TraitInfo<DesertShellmapAutoUnload>, Requires<CargoInfo> { }
class DesertShellmapAutoUnload : INotifyDamage
{
public void Damaged(Actor self, AttackInfo e)
{
var cargo = self.Trait<Cargo>();
if (!cargo.IsEmpty(self) && !(self.GetCurrentActivity() is UnloadCargo))
self.QueueActivity(false, new UnloadCargo(self, true));
}
}
}

View File

@@ -261,7 +261,6 @@
<Compile Include="Lint\CheckTraitPrerequisites.cs" />
<Compile Include="Lint\LintBuildablePrerequisites.cs" />
<Compile Include="MadTank.cs" />
<Compile Include="Missions\DesertShellmapScript.cs" />
<Compile Include="Missions\FortLonestarScript.cs" />
<Compile Include="Missions\Survival02Script.cs" />
<Compile Include="MPStartLocations.cs" />
@@ -272,7 +271,6 @@
<Compile Include="Missions\Allies03Script.cs" />
<Compile Include="Missions\Allies04Script.cs" />
<Compile Include="Missions\CountdownTimer.cs" />
<Compile Include="Missions\DefaultShellmapScript.cs" />
<Compile Include="Missions\MissionUtils.cs" />
<Compile Include="Missions\MissionWidgets.cs" />
<Compile Include="Missions\MonsterTankMadnessScript.cs" />
@@ -353,7 +351,6 @@
<Compile Include="Scripting\LuaScriptEvents.cs" />
<Compile Include="Scripting\LuaScriptInterface.cs" />
<Compile Include="Scripting\Media.cs" />
<Compile Include="Scripting\RASpecialPowers.cs" />
<Compile Include="Scripting\LuaScriptContext.cs" />
<Compile Include="SeedsResource.cs" />
<Compile Include="SelfHealing.cs" />

View File

@@ -15,13 +15,16 @@ namespace OpenRA.Mods.RA.Scripting
{
public class LuaScriptEventsInfo : TraitInfo<LuaScriptEvents> { }
public class LuaScriptEvents : INotifyKilled, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyCapture, INotifyDamage
public class LuaScriptEvents : INotifyKilled, INotifyAddedToWorld, INotifyRemovedFromWorld,
INotifyCapture, INotifyDamage, INotifyIdle, INotifyProduction
{
public event Action<Actor, AttackInfo> OnKilled = (self, e) => { };
public event Action<Actor> OnAddedToWorld = self => { };
public event Action<Actor> OnRemovedFromWorld = self => { };
public event Action<Actor, Actor, Player, Player> OnCaptured = (self, captor, oldOwner, newOwner) => { };
public event Action<Actor, AttackInfo> OnDamaged = (self, e) => { };
public event Action<Actor> OnIdle = self => { };
public event Action<Actor, Actor, CPos> OnProduced = (self, other, exit) => { };
public void Killed(Actor self, AttackInfo e)
{
@@ -47,5 +50,15 @@ namespace OpenRA.Mods.RA.Scripting
{
OnDamaged(self, e);
}
public void TickIdle(Actor self)
{
OnIdle(self);
}
public void UnitProduced(Actor self, Actor other, CPos exit)
{
OnProduced(self, other, exit);
}
}
}

View File

@@ -35,7 +35,7 @@ namespace OpenRA.Mods.RA.Scripting
public class LuaScriptInterface : IWorldLoaded, ITick
{
World world;
Dictionary<string, Actor> mapActors;
SpawnMapActors sma;
readonly LuaScriptContext context = new LuaScriptContext();
readonly LuaScriptInterfaceInfo info;
@@ -47,7 +47,7 @@ namespace OpenRA.Mods.RA.Scripting
public void WorldLoaded(World w, WorldRenderer wr)
{
world = w;
mapActors = world.WorldActor.Trait<SpawnMapActors>().Actors;
sma = world.WorldActor.Trait<SpawnMapActors>();
context.Lua["World"] = w;
context.Lua["WorldRenderer"] = wr;
@@ -75,7 +75,7 @@ namespace OpenRA.Mods.RA.Scripting
void AddMapActorGlobals()
{
foreach (var kv in mapActors)
foreach (var kv in sma.Actors)
{
if (context.Lua[kv.Key] != null)
context.ShowErrorMessage("{0}: The global name '{1}' is reserved and may not be used by map actor {2}".F(GetType().Name, kv.Key, kv.Value), null);
@@ -328,7 +328,19 @@ namespace OpenRA.Mods.RA.Scripting
[LuaGlobal]
public Actor GetNamedActor(string actorName)
{
return mapActors[actorName];
return sma.Actors[actorName];
}
[LuaGlobal]
public bool IsNamedActor(Actor actor)
{
return actor.ActorID <= sma.LastMapActorID && actor.ActorID > sma.LastMapActorID - sma.Actors.Count;
}
[LuaGlobal]
public IEnumerable<Actor> GetNamedActors()
{
return sma.Actors.Values;
}
[LuaGlobal]
@@ -343,18 +355,28 @@ namespace OpenRA.Mods.RA.Scripting
return world.FindActorsInCircle(location, radius).ToArray();
}
ClassicProductionQueue GetSharedQueueForCategory(Player player, string category)
{
return world.ActorsWithTrait<ClassicProductionQueue>()
.Where(a => a.Actor.Owner == player && a.Trait.Info.Type == category)
.Select(a => a.Trait).FirstOrDefault();
}
ClassicProductionQueue GetSharedQueueForUnit(Player player, string unit)
{
var ri = Rules.Info[unit];
var bi = ri.Traits.GetOrDefault<BuildableInfo>();
if (bi == null)
return null;
return GetSharedQueueForCategory(player, bi.Queue);
}
[LuaGlobal]
public void BuildWithSharedQueue(Player player, string unit, double amount)
{
var ri = Rules.Info[unit];
if (ri == null || !ri.Traits.Contains<BuildableInfo>())
return;
var category = ri.Traits.Get<BuildableInfo>().Queue;
var queue = world.ActorsWithTrait<ClassicProductionQueue>()
.Where(a => a.Actor.Owner == player && a.Trait.Info.Type == category)
.Select(a => a.Trait).FirstOrDefault();
var queue = GetSharedQueueForUnit(player, unit);
if (queue != null)
queue.ResolveOrder(queue.self, Order.StartProduction(queue.self, unit, (int)amount));
@@ -363,14 +385,38 @@ namespace OpenRA.Mods.RA.Scripting
[LuaGlobal]
public void BuildWithPerFactoryQueue(Actor factory, string unit, double amount)
{
if (!factory.HasTrait<ProductionQueue>())
return;
var ri = Rules.Info[unit];
if (ri == null || !ri.Traits.Contains<BuildableInfo>())
var bi = ri.Traits.GetOrDefault<BuildableInfo>();
if (bi == null)
return;
factory.Trait<ProductionQueue>().ResolveOrder(factory, Order.StartProduction(factory, unit, (int)amount));
var queue = factory.TraitOrDefault<ProductionQueue>();
if (queue != null)
queue.ResolveOrder(factory, Order.StartProduction(factory, unit, (int)amount));
}
[LuaGlobal]
public bool SharedQueueIsBusy(Player player, string category)
{
var queue = GetSharedQueueForCategory(player, category);
if (queue == null)
return true;
return queue.CurrentItem() != null;
}
[LuaGlobal]
public bool PerFactoryQueueIsBusy(Actor factory)
{
var queue = factory.TraitOrDefault<ProductionQueue>();
if (queue == null)
return true;
return queue.CurrentItem() != null;
}
[LuaGlobal]
@@ -384,5 +430,11 @@ namespace OpenRA.Mods.RA.Scripting
gt.GuardTarget(guard, Target.FromActor(target));
}
}
[LuaGlobal]
public IEnumerable<CPos> ExpandFootprint(LuaTable cells, bool allowDiagonal)
{
return Util.ExpandFootprint(cells.Values.Cast<CPos>(), allowDiagonal);
}
}
}

View File

@@ -1,30 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 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.Collections.Generic;
using OpenRA.FileFormats;
namespace OpenRA.Mods.RA.Scripting
{
public class RASpecialPowers
{
public static void Chronoshift(World world, List<Pair<Actor, CPos>> units, Actor chronosphere, int duration, bool killCargo)
{
foreach (var kv in units)
{
var target = kv.First;
var targetCell = kv.Second;
var cs = target.Trait<Chronoshiftable>();
if (chronosphere.Owner.Shroud.IsExplored(targetCell) && cs.CanChronoshiftTo(target, targetCell))
cs.Teleport(target, targetCell, duration, killCargo, chronosphere);
}
}
}
}

View File

@@ -20,6 +20,7 @@ namespace OpenRA.Mods.RA
public class SpawnMapActors : IWorldLoaded
{
public Dictionary<string, Actor> Actors = new Dictionary<string, Actor>();
public uint LastMapActorID { get; private set; }
public void WorldLoaded(World world, WorldRenderer wr)
{
@@ -32,7 +33,9 @@ namespace OpenRA.Mods.RA
var initDict = actorReference.Value.InitDict;
initDict.Add(new SkipMakeAnimsInit());
Actors[actorReference.Key] = world.CreateActor(actorReference.Value.Type, initDict);
var actor = world.CreateActor(actorReference.Value.Type, initDict);
Actors[actorReference.Key] = actor;
LastMapActorID = actor.ActorID;
}
}
}

View File

@@ -971,6 +971,7 @@ Tail:
ROF: 30
Range: 1c0
Projectile: Bullet
Speed: 1c682
Warhead:
Spread: 213
Versus:
@@ -986,6 +987,7 @@ Horn:
ROF: 20
Range: 1c0
Projectile: Bullet
Speed: 1c682
Warhead:
Spread: 213
Versus:
@@ -1001,6 +1003,7 @@ Teeth:
ROF: 30
Range: 1c0
Projectile: Bullet
Speed: 1c682
Warhead:
Spread: 213
Versus:
@@ -1016,6 +1019,7 @@ Claw:
ROF: 10
Range: 1c0
Projectile: Bullet
Speed: 1c682
Warhead:
Spread: 213
Versus:

View File

@@ -76,7 +76,14 @@ Actor.FlyOffMap = function(actor)
end
Actor.Hunt = function(actor)
actor:QueueActivity(OpenRA.New("Hunt", { actor }))
if Actor.HasTrait(actor, "AttackBase") and Actor.HasTrait(actor, "IMove") then
actor:QueueActivity(OpenRA.New("Hunt", { actor }))
end
end
Actor.CargoIsEmpty = function(actor)
local cargo = Actor.TraitOrDefault(actor, "Cargo")
return cargo == nil or cargo:IsEmpty(actor)
end
Actor.UnloadCargo = function(actor, unloadAll)
@@ -163,6 +170,14 @@ Actor.OnCaptured = function(actor, eh)
Actor.Trait(actor, "LuaScriptEvents").OnCaptured:Add(eh)
end
Actor.OnIdle = function(actor, eh)
Actor.Trait(actor, "LuaScriptEvents").OnIdle:Add(eh)
end
Actor.OnProduced = function(actor, eh)
Actor.Trait(actor, "LuaScriptEvents").OnProduced:Add(eh)
end
Actor.ActorsWithTrait = function(className)
local ret = { }
for item in Utils.Enumerate(Internal.ActorsWithTrait(className)) do

View File

@@ -12,10 +12,18 @@ Map.GetRandomEdgeCell = function()
return Internal.GetRandomEdgeCell()
end
Map.IsNamedActor = function(actor)
return Internal.IsNamedActor(actor)
end
Map.GetNamedActor = function(actorName)
return Internal.GetNamedActor(actorName)
end
Map.GetNamedActors = function()
return Internal.GetNamedActors()
end
Map.FindActorsInCircle = function(location, radius, func)
local actors = Internal.FindActorsInCircle(location.CenterPosition, WRange.FromCells(radius))
return Utils.EnumerableWhere(actors, func)
@@ -58,6 +66,10 @@ Map.FindIdleUnitsInBox = function(player, topLeft, bottomRight)
return Map.FindActorsInBox(topLeft, bottomRight, function(a) return Map.__FilterByTraitAndIdle(a, player, "Mobile") end)
end
Map.ExpandFootprint = function(cells, allowDiagonal)
return Utils.EnumerableToTable(Internal.ExpandFootprint(cells, allowDiagonal))
end
CPos.New = function(x, y)
return OpenRA.New("CPos", { { x, "Int32" }, { y, "Int32" } })
end
@@ -90,4 +102,4 @@ end
WRange.FromCells = function(cells)
return WRange.New(cells * 1024)
end
end

View File

@@ -8,6 +8,14 @@ Production.BuildWithPerFactoryQueue = function(factory, unit, amount)
Internal.BuildWithPerFactoryQueue(factory, unit, amount or 1)
end
Production.SharedQueueIsBusy = function(player, category)
return Internal.SharedQueueIsBusy(player, category)
end
Production.PerFactoryQueueIsBusy = function(factory)
return Internal.PerFactoryQueueIsBusy(factory)
end
Production.SetRallyPoint = function(factory, location)
Actor.Trait(factory, "RallyPoint").rallyPoint = location.Location
end

View File

@@ -2,8 +2,8 @@ SupportPowers = { }
SupportPowers.Airstrike = function(owner, planeName, enterLocation, bombLocation)
local facing = { Map.GetFacing(CPos.op_Subtraction(bombLocation, enterLocation), 0), "Int32" }
local altitude = { Rules.TraitInfo(planeName, "AircraftInfo").CruiseAltitude, "Int32" }
local plane = Actor.Create(planeName, { Location = enterLocation, Owner = owner, Facing = facing, Altitude = altitude })
local center = WPos.op_Addition(enterLocation.CenterPosition, WVec.New(0, 0, Rules.InitialAltitude(planeName)))
local plane = Actor.Create(planeName, { Location = enterLocation, Owner = owner, Facing = facing, CenterPosition = center })
Actor.Trait(plane, "AttackBomber"):SetTarget(bombLocation.CenterPosition)
Actor.Fly(plane, bombLocation.CenterPosition)
Actor.FlyOffMap(plane)
@@ -13,8 +13,8 @@ end
SupportPowers.Paradrop = function(owner, planeName, passengerNames, enterLocation, dropLocation)
local facing = { Map.GetFacing(CPos.op_Subtraction(dropLocation, enterLocation), 0), "Int32" }
local altitude = { Rules.TraitInfo(planeName, "AircraftInfo").CruiseAltitude, "Int32" }
local plane = Actor.Create(planeName, { Location = enterLocation, Owner = owner, Facing = facing, Altitude = altitude })
local center = WPos.op_Addition(enterLocation.CenterPosition, WVec.New(0, 0, Rules.InitialAltitude(planeName)))
local plane = Actor.Create(planeName, { Location = enterLocation, Owner = owner, Facing = facing, CenterPosition = center })
Actor.FlyAttackCell(plane, dropLocation)
Actor.Trait(plane, "ParaDrop"):SetLZ(dropLocation)
local cargo = Actor.Trait(plane, "Cargo")
@@ -25,4 +25,17 @@ SupportPowers.Paradrop = function(owner, planeName, passengerNames, enterLocatio
cargo:Load(plane, passenger)
end
return plane, passengers
end
SupportPowers.Chronoshift = function(unitLocationPairs, chronosphere, duration, killCargo)
duration = duration or -1
killCargo = killCargo or true
Utils.Do(unitLocationPairs, function(pair)
local unit = pair[1]
local cell = pair[2]
local cs = Actor.TraitOrDefault(unit, "Chronoshiftable")
if cs ~= nil and cs:CanChronoshiftTo(unit, cell) then
cs:Teleport(unit, cell, duration, killCargo, chronosphere)
end
end)
end

View File

@@ -28,6 +28,14 @@ Utils.EnumerableWhere = function(netEnumerable, func)
return ret
end
Utils.EnumerableToTable = function(netEnumerable, func)
local ret = { }
for item in Utils.Enumerate(netEnumerable) do
table.insert(ret, item)
end
return ret
end
Utils.Where = function(array, func)
local ret = { }
for i, item in ipairs(array) do

View File

@@ -0,0 +1,154 @@
local ants = OpenRA.GetRandomInteger(0, 51) == 0
if ants then
UnitTypes = { "ant", "ant", "ant" }
BeachUnitTypes = { "ant", "ant" }
ParadropUnitTypes = { "ant", "ant", "ant", "ant", "ant" }
ProducedUnitTypes =
{
{ AlliedBarracks1, { "e1", "e3" } },
{ AlliedBarracks2, { "e1", "e3" } },
{ SovietBarracks1, { "ant" } },
{ SovietBarracks2, { "ant" } },
{ SovietBarracks3, { "ant" } },
{ AlliedWarFactory1, { "jeep", "1tnk", "2tnk", "arty", "ctnk" } },
{ SovietWarFactory1, { "3tnk", "4tnk", "v2rl", "ttnk", "apc" } }
}
else
UnitTypes = { "3tnk", "ftrk", "ttnk", "apc" }
BeachUnitTypes = { "e1", "e2", "e3", "e4", "e1", "e2", "e3", "e4", "e1", "e2", "e3", "e4", "e1", "e2", "e3", "e4" }
ParadropUnitTypes = { "e1", "e1", "e2", "e3", "e4" }
ProducedUnitTypes =
{
{ AlliedBarracks1, { "e1", "e3" } },
{ AlliedBarracks2, { "e1", "e3" } },
{ SovietBarracks1, { "dog", "e1", "e2", "e3", "e4", "shok" } },
{ SovietBarracks2, { "dog", "e1", "e2", "e3", "e4", "shok" } },
{ SovietBarracks3, { "dog", "e1", "e2", "e3", "e4", "shok" } },
{ AlliedWarFactory1, { "jeep", "1tnk", "2tnk", "arty", "ctnk" } },
{ SovietWarFactory1, { "3tnk", "4tnk", "v2rl", "ttnk", "apc" } }
}
end
ParadropPlaneType = "badr"
ParadropWaypointCount = 8
SendSovietUnits = function(entryCell, unitTypes, interval)
local units = Reinforcements.Reinforce(soviets, unitTypes, entryCell, entryCell, interval)
local team = Team.New(units)
Team.AddEventHandler(team.OnAllKilled, function()
SendSovietUnits(entryCell, unitTypes, interval)
end)
Team.Do(team, function(a)
Actor.OnDamaged(a, function()
if not Actor.CargoIsEmpty(a) then
Actor.Stop(a)
Actor.UnloadCargo(a, true)
end
end)
Actor.OnIdle(a, function() Actor.AttackMove(a, AlliedTechnologyCenter.Location) end)
end)
end
ShipAlliedUnits = function()
local transport, reinforcements = Reinforcements.Insert(allies, "lst", { "1tnk", "1tnk", "jeep", "2tnk", "2tnk" }, { LstEntry.Location, LstUnload.Location }, { LstEntry.Location })
Utils.Do(reinforcements, function(a) Actor.OnIdle(a, Actor.Hunt) end)
OpenRA.RunAfterDelay(60 * 25, ShipAlliedUnits)
end
ParadropSovietUnits = function()
local lz = Map.GetNamedActor("Paradrop" .. OpenRA.GetRandomInteger(1, ParadropWaypointCount - 1)).Location
local plane, passengers = SupportPowers.Paradrop(soviets, ParadropPlaneType, ParadropUnitTypes, Map.GetRandomEdgeCell(), lz)
Utils.Do(passengers, function(a) Actor.OnIdle(a, Actor.Hunt) end)
OpenRA.RunAfterDelay(35 * 25, ParadropSovietUnits)
end
ProduceUnits = function()
Utils.Do(ProducedUnitTypes, function(t)
local factory = t[1]
if not Actor.IsDead(factory) and not Production.PerFactoryQueueIsBusy(factory) then
local unitType = t[2][OpenRA.GetRandomInteger(1, #t[2] + 1)]
Production.BuildWithPerFactoryQueue(factory, unitType)
end
end)
OpenRA.RunAfterDelay(15, ProduceUnits)
end
SetupAlliedUnits = function()
for a in Utils.Enumerate(Map.GetNamedActors()) do
if Actor.Owner(a) == allies then
if Actor.HasTrait(a, "LuaScriptEvents") then
a:AddTrait(OpenRA.New("Invulnerable")) -- todo: replace
end
Actor.SetStance(a, "Defend")
end
end
end
SetupFactories = function()
Utils.Do(ProducedUnitTypes, function(pair)
Actor.OnProduced(pair[1], function(self, other, ex)
Actor.Hunt(other)
Actor.OnDamaged(other, function()
if not Actor.CargoIsEmpty(other) then
Actor.Stop(other)
Actor.UnloadCargo(other, true)
end
end)
end)
end)
end
ChronoshiftAlliedUnits = function()
local cells = Map.ExpandFootprint({ ChronoshiftLocation.Location }, false)
local units = { }
for i = 1, #cells do
local unit = Actor.Create("2tnk", { Owner = allies, Facing = { 0, "Int32" } })
Actor.OnIdle(unit, Actor.Hunt)
table.insert(units, { unit, cells[i] })
end
SupportPowers.Chronoshift(units, Chronosphere)
OpenRA.RunAfterDelay(60 * 25, ChronoshiftAlliedUnits)
end
ticks = 0
speed = 5
Tick = function()
ticks = ticks + 1
local t = (ticks + 45) % (360 * speed) * (math.pi / 180) / speed;
OpenRA.SetViewportCenterPosition(WPos.op_Addition(viewportOrigin, WVec.New(19200 * math.sin(t), 20480 * math.cos(t))))
if ticks % 150 == 0 then
Utils.Do(Actor.ActorsWithTrait("AttackBase"), function(a)
if Actor.IsIdle(a) and not Map.IsNamedActor(a) and not Actor.IsDead(a) and Actor.IsInWorld(a) and (Actor.Owner(a) == soviets or Actor.Owner(a) == allies) then
Actor.Hunt(a)
end
end)
end
end
WorldLoaded = function()
allies = OpenRA.GetPlayer("Allies")
soviets = OpenRA.GetPlayer("Soviets")
viewportOrigin = OpenRA.GetViewportCenterPosition()
SetupAlliedUnits()
SetupFactories()
ProduceUnits()
ShipAlliedUnits()
ParadropSovietUnits()
OpenRA.RunAfterDelay(5 * 25, ChronoshiftAlliedUnits)
OpenRA.GiveCash(allies, 1000000)
OpenRA.GiveCash(soviets, 1000000)
SendSovietUnits(Entry1.Location, UnitTypes, 50)
SendSovietUnits(Entry2.Location, UnitTypes, 50)
SendSovietUnits(Entry3.Location, UnitTypes, 50)
SendSovietUnits(Entry4.Location, UnitTypes, 50)
SendSovietUnits(Entry5.Location, UnitTypes, 50)
SendSovietUnits(Entry6.Location, UnitTypes, 50)
SendSovietUnits(Entry7.Location, BeachUnitTypes, 15)
end

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -1283,6 +1283,7 @@ Claw:
ROF: 30
Range: 1c0
Projectile: Bullet
Speed: 1c682
Warhead:
Spread: 213
Versus:
@@ -1298,6 +1299,7 @@ Mandible:
ROF: 10
Range: 1c0
Projectile: Bullet
Speed: 1c682
Warhead:
Spread: 213
Versus: