Add initial standard library, and port shellmaps.

This commit is contained in:
Paul Chote
2014-04-14 21:14:52 +12:00
parent d73af0190f
commit 06f162ad57
29 changed files with 1403 additions and 158 deletions

View File

@@ -502,6 +502,24 @@
<Compile Include="StartGameNotification.cs" />
<Compile Include="Widgets\ConfirmationDialogs.cs" />
<Compile Include="Scripting\LuaScript.cs" />
<Compile Include="Scripting\CallLuaFunc.cs" />
<Compile Include="Scripting\Global\ActorGlobal.cs" />
<Compile Include="Scripting\Global\CoordinateGlobals.cs" />
<Compile Include="Scripting\Properties\ResourceProperties.cs" />
<Compile Include="Scripting\Properties\ProductionProperties.cs" />
<Compile Include="Scripting\Properties\MobileProperties.cs" />
<Compile Include="Scripting\Properties\GeneralProperties.cs" />
<Compile Include="Scripting\Properties\HealthProperties.cs" />
<Compile Include="Scripting\Properties\CombatProperties.cs" />
<Compile Include="Scripting\Global\MapGlobal.cs" />
<Compile Include="Scripting\Global\PlayerGlobal.cs" />
<Compile Include="Scripting\Global\UtilsGlobal.cs" />
<Compile Include="Scripting\Global\TriggerGlobal.cs" />
<Compile Include="Scripting\ScriptTriggers.cs" />
<Compile Include="Scripting\Properties\TransportProperties.cs" />
<Compile Include="Scripting\Global\CameraGlobal.cs" />
<Compile Include="Scripting\Properties\ChronosphereProperties.cs" />
<Compile Include="Scripting\ScriptInvulnerable.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">
@@ -547,4 +565,8 @@ copy "FuzzyLogicLibrary.dll" "$(SolutionDir)"
cd "$(SolutionDir)"</PostBuildEvent>
</PropertyGroup>
<ItemGroup />
<ItemGroup>
<Folder Include="Scripting\Global\" />
<Folder Include="Scripting\Properties\" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,57 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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 Eluant;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Activities
{
public class CallLuaFunc : Activity
{
LuaFunction function;
public CallLuaFunc(LuaFunction func)
{
function = func.CopyReference() as LuaFunction;
}
public override Activity Tick(Actor self)
{
if (function != null)
function.Call().Dispose();
Dispose();
return NextActivity;
}
public override void Cancel(Actor self)
{
Dispose();
base.Cancel(self);
}
public void Dispose()
{
if (function == null)
return;
GC.SuppressFinalize(this);
function.Dispose();
function = null;
}
~CallLuaFunc()
{
if (function != null)
Game.RunAfterTick(Dispose);
}
}
}

View File

@@ -0,0 +1,87 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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;
using System.Collections.Generic;
using System.Linq;
using Eluant;
using OpenRA.FileFormats;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Air;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Scripting
{
[ScriptGlobal("Actor")]
public class ActorGlobal : ScriptGlobal
{
public ActorGlobal(ScriptContext context) : base(context) { }
[Desc("Create a new actor. initTable specifies a list of key-value pairs that definite initial parameters for the actor's traits.")]
public Actor Create(string type, bool addToWorld, LuaTable initTable)
{
var initDict = new TypeDictionary();
// Convert table entries into ActorInits
foreach (var kv in initTable)
{
// Find the requested type
var typeName = kv.Key.ToString();
var initType = Game.modData.ObjectCreator.FindType(typeName + "Init");
if (initType == null)
throw new LuaException("Unknown initializer type '{0}'".F(typeName));
// Cast it up to an IActorInit<T>
var genericType = initType.GetInterfaces()
.First(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IActorInit<>));
var innerType = genericType.GetGenericArguments().First();
// 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));
// Construct the ActorInit. Phew!
var test = initType.GetConstructor(new[] { innerType }).Invoke(new[] { value });
initDict.Add(test);
}
// The actor must be added to the world at the end of the tick
var a = context.World.CreateActor(false, type, initDict);
if (addToWorld)
context.World.AddFrameEndTask(w => w.Add(a));
return a;
}
[Desc("Returns the build time (in ticks) of the requested unit type")]
public int BuildTime(string type)
{
ActorInfo ai;
if (!Rules.Info.TryGetValue(type, out ai))
throw new LuaException("Unknown actor type '{0}'".F(type));
return ai.GetBuildTime();
}
[Desc("Returns the cruise altitude of the requested unit type (zero if it ground-based).")]
public int CruiseAltitude(string type)
{
ActorInfo ai;
if (!Rules.Info.TryGetValue(type, out ai))
throw new LuaException("Unknown actor type '{0}'".F(type));
var pi = ai.Traits.GetOrDefault<PlaneInfo>();
return pi != null ? pi.CruiseAltitude.Range : 0;
}
}
}

View File

@@ -0,0 +1,33 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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 System.Linq;
using Eluant;
using OpenRA.Effects;
using OpenRA.Scripting;
namespace OpenRA.Mods.RA.Scripting
{
[ScriptGlobal("Camera")]
public class CameraGlobal : ScriptGlobal
{
public CameraGlobal(ScriptContext context)
: base(context) { }
[Desc("The center of the visible viewport.")]
public WPos Position
{
get { return context.WorldRenderer.Viewport.CenterPosition; }
set { context.WorldRenderer.Viewport.Center(value); }
}
}
}

View File

@@ -0,0 +1,60 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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
namespace OpenRA.Scripting
{
[ScriptGlobal("CPos")]
public class CPosGlobal : ScriptGlobal
{
public CPosGlobal(ScriptContext context) : base(context) { }
[Desc("Create a new CPos with the specified coordinates.")]
public CPos New(int x, int y) { return new CPos(x, y); }
[Desc("The cell coordinate origin.")]
public CPos Zero { get { return CPos.Zero; } }
}
[ScriptGlobal("CVec")]
public class CVecGlobal : ScriptGlobal
{
public CVecGlobal(ScriptContext context) : base(context) { }
[Desc("Create a new CVec with the specified coordinates.")]
public CVec New(int x, int y) { return new CVec(x, y); }
[Desc("The cell zero-vector.")]
public CVec Zero { get { return CVec.Zero; } }
}
[ScriptGlobal("WPos")]
public class WPosGlobal : ScriptGlobal
{
public WPosGlobal(ScriptContext context) : base(context) { }
[Desc("Create a new WPos with the specified coordinates.")]
public WPos New(int x, int y, int z) { return new WPos(x, y, z); }
[Desc("The world coordinate origin.")]
public WPos Zero { get { return WPos.Zero; } }
}
[ScriptGlobal("WVec")]
public class WVecGlobal : ScriptGlobal
{
public WVecGlobal(ScriptContext context) : base(context) { }
[Desc("Create a new WVec with the specified coordinates.")]
public WVec New(int x, int y, int z) { return new WVec(x, y, z); }
[Desc("The world zero-vector.")]
public WVec Zero { get { return WVec.Zero; } }
}
}

View File

@@ -0,0 +1,90 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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 System.Linq;
using Eluant;
using OpenRA.Effects;
using OpenRA.Scripting;
namespace OpenRA.Mods.RA.Scripting
{
[ScriptGlobal("Map")]
public class MapGlobal : ScriptGlobal
{
SpawnMapActors sma;
public MapGlobal(ScriptContext context) : base(context)
{
sma = context.World.WorldActor.Trait<SpawnMapActors>();
// Register map actors as globals (yuck!)
foreach (var kv in sma.Actors)
context.RegisterMapActor(kv.Key, kv.Value);
}
[Desc("Returns a table of all actors within the requested region, filtered using the specified function.")]
public LuaTable ActorsInCircle(WPos location, WRange radius, LuaFunction filter)
{
var actors = context.World.FindActorsInCircle(location, radius)
.Select(a => a.ToLuaValue(context))
.Where(a =>
{
using (var f = filter.Call(a))
return f.First().ToBoolean();
});
return actors.ToLuaTable(context);
}
[Desc("Returns a random cell inside the visible region of the map.")]
public CPos RandomCell()
{
return context.World.ChooseRandomCell(context.World.SharedRandom);
}
[Desc("Returns a random cell on the visible border of the map.")]
public CPos RandomEdgeCell()
{
return context.World.ChooseRandomEdgeCell();
}
[Desc("Returns true if there is only one human player.")]
public bool IsSinglePlayer { get { return context.World.LobbyInfo.IsSinglePlayer; } }
[Desc("Returns the difficulty selected by the player before starting the mission.")]
public string Difficulty { get { return context.World.LobbyInfo.GlobalSettings.Difficulty; } }
[Desc("Returns a table of all the actors that were specified in the map file.")]
public LuaTable NamedActors
{
get
{
return sma.Actors.Values.ToLuaTable(context);
}
}
[Desc("Returns the actor that was specified with a given name in " +
"the map file (or nil, if the actor is dead or not found")]
public Actor NamedActor(string actorName)
{
Actor ret;
if (!sma.Actors.TryGetValue(actorName, out ret))
return null;
return ret;
}
[Desc("Returns true if actor was originally specified in the map file.")]
public bool IsNamedActor(Actor actor)
{
return actor.ActorID <= sma.LastMapActorID && actor.ActorID > sma.LastMapActorID - sma.Actors.Count;
}
}
}

View File

@@ -0,0 +1,46 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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;
using System.Collections.Generic;
using System.Linq;
using Eluant;
using OpenRA.FileFormats;
using OpenRA.Traits;
namespace OpenRA.Scripting
{
[ScriptGlobal("Player")]
public class PlayerGlobal : ScriptGlobal
{
public PlayerGlobal(ScriptContext context) : base(context) { }
[Desc("Returns the player with the specified internal name, or nil if a match is not found.")]
public Player GetPlayer(string name)
{
return context.World.Players.FirstOrDefault(p => p.InternalName == name);
}
[Desc("Returns a table of players filtered by the specified function.")]
public LuaTable GetPlayers(LuaFunction filter)
{
var players = context.World.Players
.Select(p => p.ToLuaValue(context))
.Where(a =>
{
using (var f = filter.Call(a))
return f.First().ToBoolean();
});
return players.ToLuaTable(context);
}
}
}

View File

@@ -0,0 +1,112 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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 System.Linq;
using Eluant;
using OpenRA.Effects;
using OpenRA.Scripting;
namespace OpenRA.Mods.RA.Scripting
{
[ScriptGlobal("Trigger")]
public class TriggerGlobal : ScriptGlobal
{
public TriggerGlobal(ScriptContext context) : base(context) { }
ScriptTriggers GetScriptTriggers(Actor a)
{
var events = a.TraitOrDefault<ScriptTriggers>();
if (events == null)
throw new LuaException("Actor '{0}' requires the ScriptTriggers trait before attaching a trigger".F(a.Info.Name));
return events;
}
[Desc("Call a function after a specified delay. The callback function will be called as func().")]
public void AfterDelay(int delay, LuaFunction func)
{
var f = func.CopyReference() as LuaFunction;
Action doCall = () =>
{
try
{
using (f)
f.Call();
}
catch (LuaException e)
{
context.FatalError(e.Message);
}
};
context.World.AddFrameEndTask(w => w.Add(new DelayedAction(delay, doCall)));
}
[Desc("Call a function each tick that the actor is idle. " +
"The callback function will be called as func(Actor self).")]
public void OnIdle(Actor a, LuaFunction func)
{
GetScriptTriggers(a).RegisterIdleCallback(func, context);
}
[Desc("Call a function when the actor is damaged. The callback " +
"function will be called as func(Actor self, Actor attacker).")]
public void OnDamaged(Actor a, LuaFunction func)
{
GetScriptTriggers(a).RegisterDamagedCallback(func, context);
}
[Desc("Call a function when the actor is killed. The callback " +
"function will be called as func(Actor self, Actor killer).")]
public void OnKilled(Actor a, LuaFunction func)
{
GetScriptTriggers(a).RegisterKilledCallback(func, context);
}
[Desc("Call a function when all of the actors in a group are killed. The callback " +
"function will be called as func().")]
public void OnAllKilled(LuaTable actors, LuaFunction func)
{
List<Actor> group = new List<Actor>();
foreach (var kv in actors)
{
Actor actor;
if (!kv.Value.TryGetClrValue<Actor>(out actor))
throw new LuaException("OnAllKilled requires a table of int,Actor pairs. Recieved {0},{1}".F(kv.Key.GetType().Name, kv.Value.GetType().Name));
group.Add(actor);
}
var copy = (LuaFunction)func.CopyReference();
Action<Actor> OnMemberKilled = m =>
{
group.Remove(m);
if (!group.Any())
{
copy.Call();
copy.Dispose();
}
};
foreach (var a in group)
GetScriptTriggers(a).OnKilledInternal += OnMemberKilled;
}
[Desc("Call a function when this actor produces another actor. " +
"The callback function will be called as func(Actor producer, Actor produced).")]
public void OnProduction(Actor a, LuaFunction func)
{
GetScriptTriggers(a).RegisterProductionCallback(func, context);
}
}
}

View File

@@ -0,0 +1,100 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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.Linq;
using Eluant;
using OpenRA.Effects;
using OpenRA.Scripting;
namespace OpenRA.Mods.RA.Scripting
{
[ScriptGlobal("Utils")]
public class UtilsGlobal : ScriptGlobal
{
public UtilsGlobal(ScriptContext context) : base(context) { }
[Desc("Calls a function on every value in table.")]
public void Do(LuaTable table, LuaFunction func)
{
foreach (var kv in table)
func.Call(kv.Value).Dispose();
}
[Desc("Returns true if func returns true for any value in table.")]
public bool Any(LuaTable table, LuaFunction func)
{
foreach (var kv in table)
{
using (var ret = func.Call(kv.Value))
{
var result = ret.FirstOrDefault();
if (result != null && result.ToBoolean())
return true;
}
}
return false;
}
[Desc("Returns true if func returns true for all values in table.")]
public bool All(LuaTable table, LuaFunction func)
{
foreach (var kv in table)
{
using (var ret = func.Call(kv.Value))
{
var result = ret.FirstOrDefault();
if (result == null || !result.ToBoolean())
return false;
}
}
return true;
}
[Desc("Returns a random value from table.")]
public LuaValue Random(LuaTable table)
{
return table.Values.Random<LuaValue>(context.World.SharedRandom);
}
[Desc("Expands the given footprint one step along the coordinate axes, and (if requested) diagonals")]
public LuaTable ExpandFootprint(LuaTable cells, bool allowDiagonal)
{
var footprint = cells.Values.Select(c =>
{
CPos cell;
if (!c.TryGetClrValue<CPos>(out cell))
throw new LuaException("ExpandFootprint only accepts a table of CPos");
return cell;
});
var expanded = Traits.Util.ExpandFootprint(footprint, allowDiagonal);
return expanded.ToLuaTable(context);
}
[Desc("Returns a random integer x in the range low &lt;= x &lt; high.")]
public int RandomInteger(int low, int high)
{
if (high <= low)
return low;
return context.World.SharedRandom.Next(low, high);
}
[Desc("Returns the center of a cell in world coordinates.")]
public WPos CenterOfCell(CPos cell)
{
return cell.CenterPosition;
}
}
}

View File

@@ -0,0 +1,43 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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.Linq;
using Eluant;
using OpenRA;
using OpenRA.Mods.RA;
using OpenRA.Mods.RA.Activities;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Scripting
{
[ScriptPropertyGroup("Support Powers")]
public class ChronsphereProperties : ScriptActorProperties, Requires<ChronoshiftPowerInfo>
{
public ChronsphereProperties(Actor self)
: base(self) { }
[Desc("Chronoshift a group of actors. A duration of 0 will teleport the actors permanently.")]
public void Chronoshift(LuaTable unitLocationPairs, int duration = 0, bool killCargo = false)
{
foreach (var kv in unitLocationPairs)
{
Actor actor;
CPos cell;
if (!kv.Key.TryGetClrValue<Actor>(out actor) || !kv.Value.TryGetClrValue<CPos>(out cell))
throw new LuaException("Chronoshift requires a table of Actor,CPos pairs. Received {0},{1}".F(kv.Key.WrappedClrType().Name, kv.Value.WrappedClrType().Name));
var cs = actor.TraitOrDefault<Chronoshiftable>();
if (cs != null && cs.CanChronoshiftTo(actor, cell))
cs.Teleport(actor, cell, duration, killCargo, self);
}
}
}
}

View File

@@ -0,0 +1,42 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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 OpenRA;
using OpenRA.FileFormats;
using OpenRA.Mods.RA;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Move;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Scripting
{
[ScriptPropertyGroup("Combat")]
public class CombatProperties : ScriptActorProperties, Requires<AttackBaseInfo>, Requires<IMoveInfo>
{
public CombatProperties(Actor self) : base(self) { }
[ScriptActorPropertyActivity]
[Desc("Seek out and attack nearby targets.")]
public void Hunt()
{
self.QueueActivity(new Hunt(self));
}
[ScriptActorPropertyActivity]
[Desc("Move to a cell, but stop and attack anything within range on the way. " +
"closeEnough defines an optional range (in cells) that will be considered " +
"close enough to complete the activity.")]
public void AttackMove(CPos cell, int closeEnough = 0)
{
self.QueueActivity(new AttackMove.AttackMoveActivity(self, new Move.Move(cell, WRange.FromCells(closeEnough))));
}
}
}

View File

@@ -0,0 +1,139 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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 Eluant;
using OpenRA;
using OpenRA.FileFormats;
using OpenRA.Mods.RA;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Move;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Scripting
{
[ScriptPropertyGroup("General")]
public class GeneralProperties : ScriptActorProperties
{
readonly IFacing facing;
readonly AutoTarget autotarget;
public GeneralProperties(Actor self) : base(self)
{
facing = self.TraitOrDefault<IFacing>();
autotarget = self.TraitOrDefault<AutoTarget>();
}
[Desc("Specifies whether the actor is in the world.")]
public bool IsInWorld
{
get
{
return self.IsInWorld;
}
set
{
if (value)
self.World.AddFrameEndTask(w => w.Add(self));
else
self.World.AddFrameEndTask(w => w.Remove(self));
}
}
[Desc("Specifies whether the actor is idle (not performing any activities).")]
public bool IsIdle { get { return self.IsIdle; } }
[Desc("The actor position in cell coordinates.")]
public CPos Location { get { return self.Location; } }
[Desc("The actor position in world coordinates.")]
public WPos CenterPosition { get { return self.CenterPosition; } }
[Desc("The player that owns the actor.")]
public Player Owner { get { return self.Owner; } }
[Desc("The direction that the actor is facing.")]
public int Facing
{
get
{
if (facing == null)
throw new LuaException("Actor '{0}' doesn't define a facing".F(self));
return facing.Facing;
}
}
[ScriptActorPropertyActivity]
[Desc("Instantly moves the actor to the specified cell.")]
public void Teleport(CPos cell)
{
self.QueueActivity(new SimpleTeleport(cell));
}
[ScriptActorPropertyActivity]
[Desc("Run an arbitrary lua function.")]
public void CallFunc(LuaFunction func)
{
self.QueueActivity(new CallLuaFunc(func));
}
[ScriptActorPropertyActivity]
[Desc("Wait for a specified number of game ticks (25 ticks = 1 second).")]
public void Wait(int ticks)
{
self.QueueActivity(new Wait(ticks));
}
[ScriptActorPropertyActivity]
[Desc("Remove the actor from the game, without triggering any death notification.")]
public void Destroy()
{
self.QueueActivity(new RemoveSelf());
}
[Desc("Attempt to cancel any active activities.")]
public void Stop()
{
self.CancelActivity();
}
[Desc("Current actor stance. Returns nil if this actor doesn't support stances.")]
public string Stance
{
get
{
if (autotarget == null)
return null;
return autotarget.Stance.ToString();
}
set
{
if (autotarget == null)
return;
UnitStance stance;
if (!Enum<UnitStance>.TryParse(value, true, out stance))
throw new LuaException("Unknown stance type '{0}'".F(value));
autotarget.Stance = stance;
}
}
[Desc("Test whether an actor has a specific property.")]
public bool HasProperty(string name)
{
return self.HasScriptProperty(name);
}
}
}

View File

@@ -0,0 +1,63 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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 Eluant;
using OpenRA;
using OpenRA.FileFormats;
using OpenRA.Mods.RA;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Move;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Scripting
{
[ScriptPropertyGroup("General")]
public class HealthProperties : ScriptActorProperties, Requires<HealthInfo>
{
Health health;
public HealthProperties(Actor self)
: base(self)
{
health = self.Trait<Health>();
}
[Desc("Current health of the actor.")]
public int Health
{
get { return health.HP; }
set { health.InflictDamage(self, self, health.HP - value, null, true); }
}
[Desc("Maximum health of the actor.")]
public int MaxHealth { get { return health.MaxHP; } }
[Desc("Specifies whether the actor is alive or dead.")]
public bool IsDead { get { return health.IsDead; } }
}
[ScriptPropertyGroup("General")]
public class InvulnerableProperties : ScriptActorProperties, Requires<ScriptInvulnerableInfo>
{
ScriptInvulnerable invulnerable;
public InvulnerableProperties(Actor self)
: base(self)
{
invulnerable = self.Trait<ScriptInvulnerable>();
}
[Desc("Set or query unit invulnerablility.")]
public bool Invulnerable
{
get { return invulnerable.Invulnerable; }
set { invulnerable.Invulnerable = value; }
}
}
}

View File

@@ -0,0 +1,40 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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 OpenRA;
using OpenRA.FileFormats;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Move;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Scripting
{
[ScriptPropertyGroup("Movement")]
public class MobileProperties : ScriptActorProperties, Requires<MobileInfo>
{
public MobileProperties(Actor self) : base(self) { }
[ScriptActorPropertyActivity]
[Desc("Moves within the cell grid. closeEnough defines an optional range " +
"(in cells) that will be considered close enough to complete the activity.")]
public void Move(CPos cell, int closeEnough = 0)
{
self.QueueActivity(new Move.Move(cell, WRange.FromCells(closeEnough)));
}
[ScriptActorPropertyActivity]
[Desc("Moves within the cell grid, ignoring lane biases.")]
public void ScriptedMove(CPos cell)
{
self.QueueActivity(new Move.Move(cell));
}
}
}

View File

@@ -0,0 +1,43 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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.Linq;
using Eluant;
using OpenRA;
using OpenRA.Mods.RA;
using OpenRA.Mods.RA.Activities;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Scripting
{
[ScriptPropertyGroup("Production")]
public class ProductionProperties : ScriptActorProperties, Requires<ProductionInfo>
{
readonly Production p;
public ProductionProperties(Actor self)
: base(self)
{
p = self.Trait<Production>();
}
[ScriptActorPropertyActivity]
[Desc("Build a unit, ignoring the production queue. The activity will wait if the exit is blocked")]
public void Produce(string actorType)
{
ActorInfo actorInfo;
if (!Rules.Info.TryGetValue(actorType, out actorInfo))
throw new LuaException("Unknown actor type '{0}'".F(actorType));
self.QueueActivity(new WaitFor(() => p.Produce(self, actorInfo)));
}
}
}

View File

@@ -0,0 +1,46 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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 OpenRA;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Scripting
{
[ScriptPropertyGroup("Resources")]
public class ResourceProperties : ScriptPlayerProperties, Requires<PlayerResourcesInfo>
{
readonly PlayerResources pr;
public ResourceProperties(Player player)
: base(player)
{
pr = player.PlayerActor.Trait<PlayerResources>();
}
[Desc("The amount of harvestable resources held by the player.")]
public int Resources
{
get { return pr.Ore; }
set { pr.Ore = value.Clamp(0, pr.OreCapacity); }
}
[Desc("The maximum resource storage of the player.")]
public int ResourceCapacity { get { return pr.OreCapacity; } }
[Desc("The amount of cash held by the player.")]
public int Cash
{
get { return pr.Cash; }
set { pr.Cash = Math.Max(0, value); }
}
}
}

View File

@@ -0,0 +1,66 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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.Linq;
using Eluant;
using OpenRA;
using OpenRA.Mods.RA;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Air;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Scripting
{
[ScriptPropertyGroup("Transports")]
public class TransportProperties : ScriptActorProperties, Requires<CargoInfo>
{
readonly Cargo cargo;
public TransportProperties(Actor self)
: base(self)
{
cargo = self.Trait<Cargo>();
}
[Desc("Specifies whether transport has any passengers.")]
public bool HasPassengers { get { return cargo.Passengers.Any(); } }
[Desc("Teleport an existing actor inside this transport.")]
public void LoadPassenger(Actor a) { cargo.Load(self, a); }
[ScriptActorPropertyActivity]
[Desc("Command transport to unload passengers.")]
public void UnloadPassengers()
{
self.QueueActivity(new UnloadCargo(self, true));
}
}
[ScriptPropertyGroup("Transports")]
public class ParadropPowers : ScriptActorProperties, Requires<CargoInfo>, Requires<ParaDropInfo>
{
readonly ParaDrop paradrop;
public ParadropPowers(Actor self)
: base(self)
{
paradrop = self.Trait<ParaDrop>();
}
[ScriptActorPropertyActivity]
[Desc("Command transport to paradrop passengers near the target cell.")]
public void Paradrop(CPos cell)
{
paradrop.SetLZ(cell);
self.QueueActivity(new FlyAttack(Target.FromCell(cell)));
}
}
}

View File

@@ -0,0 +1,28 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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 OpenRA.GameRules;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
[Desc("Allows map scripts to make this actor invulnerable via actor.Invulnerable = true.")]
class ScriptInvulnerableInfo : TraitInfo<ScriptInvulnerable> {}
class ScriptInvulnerable : IDamageModifier
{
public bool Invulnerable = false;
public float GetDamageModifier(Actor attacker, WarheadInfo warhead)
{
return Invulnerable ? 0.0f : 1.0f;
}
}
}

View File

@@ -0,0 +1,121 @@
#region Copyright & License Information
/*
* Copyright 2007-2014 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 System.Linq;
using Eluant;
using OpenRA.Primitives;
using OpenRA.Scripting;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Scripting
{
[Desc("Allows map scripts to attach triggers to this actor via the Triggers global.")]
public class ScriptTriggersInfo : TraitInfo<ScriptTriggers> { }
public class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction
{
public event Action<Actor> OnKilledInternal = _ => {};
List<Pair<LuaFunction, ScriptContext>> onIdle = new List<Pair<LuaFunction, ScriptContext>>();
List<Pair<LuaFunction, ScriptContext>> onDamaged = new List<Pair<LuaFunction, ScriptContext>>();
List<Pair<LuaFunction, ScriptContext>> onKilled = new List<Pair<LuaFunction, ScriptContext>>();
List<Pair<LuaFunction, ScriptContext>> onProduction = new List<Pair<LuaFunction, ScriptContext>>();
public void RegisterIdleCallback(LuaFunction func, ScriptContext context)
{
onIdle.Add(Pair.New((LuaFunction)func.CopyReference(), context));
}
public void RegisterDamagedCallback(LuaFunction func, ScriptContext context)
{
onDamaged.Add(Pair.New((LuaFunction)func.CopyReference(), context));
}
public void RegisterKilledCallback(LuaFunction func, ScriptContext context)
{
onKilled.Add(Pair.New((LuaFunction)func.CopyReference(), context));
}
public void RegisterProductionCallback(LuaFunction func, ScriptContext context)
{
onProduction.Add(Pair.New((LuaFunction)func.CopyReference(), context));
}
public void TickIdle(Actor self)
{
foreach (var f in onIdle)
{
var a = self.ToLuaValue(f.Second);
f.First.Call(a).Dispose();
a.Dispose();
}
}
public void Damaged(Actor self, AttackInfo e)
{
foreach (var f in onDamaged)
{
var a = self.ToLuaValue(f.Second);
var b = e.Attacker.ToLuaValue(f.Second);
f.First.Call(a, b).Dispose();
a.Dispose();
b.Dispose();
}
}
public void Killed(Actor self, AttackInfo e)
{
// Run lua callbacks
foreach (var f in onKilled)
{
var a = self.ToLuaValue(f.Second);
var b = e.Attacker.ToLuaValue(f.Second);
f.First.Call(a, b).Dispose();
a.Dispose();
b.Dispose();
}
// Run any internally bound callbacks
OnKilledInternal(self);
}
public void UnitProduced(Actor self, Actor other, CPos exit)
{
foreach (var f in onProduction)
{
var a = self.ToLuaValue(f.Second);
var b = other.ToLuaValue(f.Second);
f.First.Call(a, b).Dispose();
a.Dispose();
b.Dispose();
}
}
bool disposed;
public void Dispose()
{
disposed = true;
var toDispose = new [] { onIdle, onDamaged, onKilled, onProduction };
foreach (var f in toDispose.SelectMany(f => f))
f.First.Dispose();
GC.SuppressFinalize(this);
}
~ScriptTriggers()
{
if (!disposed)
Game.RunAfterTick(Dispose);
}
}
}

View File

@@ -242,6 +242,13 @@ namespace OpenRA.Utility
node.Key = "MaxDistance";
}
// Added new Lua API
if (engineVersion < 20140421)
{
if (depth == 0 && node.Value.Nodes.Any(n => n.Key == "LuaScriptEvents"))
node.Value.Nodes.Add(new MiniYamlNode("ScriptTriggers", ""));
}
UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1);
}
}

View File

@@ -520,10 +520,10 @@ Actors:
Location: 11,52
Owner: Neutral
GDIReinforcementsEntry: waypoint
Location: 7, 50
Location: 7,50
Owner: Neutral
Auto1Trigger: waypoint
Location: 52, 47
Location: 52,47
Owner: Neutral
NodHeliEntry: waypoint
Location: 41,23
@@ -561,6 +561,7 @@ Rules:
-GiveCashCrateAction:
-ExplodeCrateAction@fire:
-CloakCrateAction:
ScriptTriggers:
Sequences:

View File

@@ -993,8 +993,8 @@ Rules:
PlayMusicOnMapLoad:
Music: map1
Loop: true
LuaScriptInterface:
LuaScripts: shellmap.lua
LuaScript:
Scripts: shellmap.lua
LoadWidgetAtGameStart:
Widget: MENU_BACKGROUND
LST:

View File

@@ -5,15 +5,14 @@ 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(-15360 * math.sin(t), 4096 * math.cos(t))))
Camera.Position = viewportOrigin + WVec.New(-15360 * math.sin(t), 4096 * math.cos(t), 0)
end
WorldLoaded = function()
viewportOrigin = OpenRA.GetViewportCenterPosition()
CreateUnitsInTransport(lst1, { "htnk" });
CreateUnitsInTransport(lst2, { "mcv" });
CreateUnitsInTransport(lst3, { "htnk" });
viewportOrigin = Camera.Position
LoadTransport(lst1, "htnk")
LoadTransport(lst2, "mcv")
LoadTransport(lst3, "htnk")
local units = { boat1, boat2, boat3, boat4, lst1, lst2, lst3}
for i, unit in ipairs(units) do
LoopTrack(unit, CPos.New(8, unit.Location.Y), CPos.New(87, unit.Location.Y))
@@ -21,17 +20,11 @@ WorldLoaded = function()
end
LoopTrack = function(actor, left, right)
Actor.ScriptedMove(actor, left)
Actor.Teleport(actor, right)
Actor.CallFunc(actor, function() LoopTrack(actor, left, right) end)
actor.ScriptedMove(left)
actor.Teleport(right)
actor.CallFunc(function() LoopTrack(actor, left, right) end)
end
CreateUnitsInTransport = function(transport, passengerNames)
local cargo = Actor.Trait(transport, "Cargo")
local owner = Actor.Owner(transport)
local facing = Actor.Facing(transport)
for i, passengerName in ipairs(passengerNames) do
cargo:Load(transport, Actor.Create(passengerName, { AddToWorld = false, Owner = owner, Facing = { facing, "Int32" } }))
end
LoadTransport = function(transport, passenger)
transport.LoadPassenger(Actor.Create(passenger, false, { Owner = transport.Owner, Facing = transport.Facing }))
end

View File

@@ -42,6 +42,7 @@
UncloakSound: trans1.aud
Huntable:
LuaScriptEvents:
ScriptTriggers:
^Tank:
AppearsOnRadar:
@@ -90,6 +91,7 @@
UncloakSound: trans1.aud
Huntable:
LuaScriptEvents:
ScriptTriggers:
^Helicopter:
AppearsOnRadar:
@@ -122,6 +124,7 @@
UpdatesPlayerStatistics:
Huntable:
LuaScriptEvents:
ScriptTriggers:
^Infantry:
AppearsOnRadar:
@@ -183,6 +186,7 @@
LuaScriptEvents:
DetectCloaked:
Range: 1
ScriptTriggers:
^CivInfantry:
Inherits: ^Infantry
@@ -261,6 +265,7 @@
UpdatesPlayerStatistics:
Huntable:
LuaScriptEvents:
ScriptTriggers:
^Plane:
AppearsOnRadar:
@@ -280,6 +285,7 @@
Huntable:
AttackMove:
LuaScriptEvents:
ScriptTriggers:
^Ship:
AppearsOnRadar:
@@ -305,6 +311,7 @@
UpdatesPlayerStatistics:
Huntable:
LuaScriptEvents:
ScriptTriggers:
^Building:
AppearsOnRadar:
@@ -348,6 +355,7 @@
Huntable:
LuaScriptEvents:
Demolishable:
ScriptTriggers:
^BaseBuilding:
Inherits: ^Building
@@ -389,6 +397,7 @@
FrozenUnderFog:
StartsRevealed: true
LuaScriptEvents:
ScriptTriggers:
^TechBuilding:
Inherits: ^CivBuilding
@@ -429,6 +438,7 @@
FrozenUnderFog:
StartsRevealed: true
LuaScriptEvents:
ScriptTriggers:
^Wall:
AppearsOnRadar:
@@ -460,6 +470,7 @@
BodyOrientation:
FrozenUnderFog:
LuaScriptEvents:
ScriptTriggers:
^Tree:
Tooltip:
@@ -484,6 +495,7 @@
FrozenUnderFog:
StartsRevealed: true
LuaScriptEvents:
ScriptTriggers:
^TibTree:
Tooltip:
@@ -520,6 +532,7 @@
FrozenUnderFog:
StartsRevealed: true
LuaScriptEvents:
ScriptTriggers:
^Husk:
Health:
@@ -545,6 +558,7 @@
BodyOrientation:
LuaScriptEvents:
DisabledOverlay:
ScriptTriggers:
^HelicopterHusk:
Inherits: ^Husk
@@ -573,4 +587,5 @@
DestroyedSound: xplobig4.aud
BodyOrientation:
LuaScriptEvents:
ScriptTriggers:

View File

@@ -38,6 +38,7 @@
Huntable:
LuaScriptEvents:
Demolishable:
ScriptTriggers:
^Tank:
AppearsOnRadar:
@@ -79,6 +80,7 @@
Huntable:
LuaScriptEvents:
Demolishable:
ScriptTriggers:
^Husk:
Health:
@@ -107,6 +109,7 @@
TransformOnCapture:
ForceHealthPercentage: 25
DisabledOverlay:
ScriptTriggers:
^TowerHusk:
Health:
@@ -126,6 +129,7 @@
Types: Husk
BodyOrientation:
LuaScriptEvents:
ScriptTriggers:
^AircraftHusk:
Inherits: ^Husk
@@ -190,6 +194,7 @@
UpdatesPlayerStatistics:
Huntable:
LuaScriptEvents:
ScriptTriggers:
^Plane:
AppearsOnRadar:
@@ -214,6 +219,7 @@
Huntable:
AttackMove:
LuaScriptEvents:
ScriptTriggers:
^Helicopter:
Inherits: ^Plane
@@ -270,3 +276,5 @@
Weapons: shrapnel
Pieces: 3, 7
Range: 2c0, 5c0
ScriptTriggers:

View File

@@ -1,4 +1,4 @@
local ants = OpenRA.GetRandomInteger(0, 51) == 0
local ants = Utils.RandomInteger(0, 51) == 0
if ants then
UnitTypes = { "ant", "ant", "ant" }
@@ -29,85 +29,110 @@ else
{ 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)
ParadropWaypoints = { Paradrop1, Paradrop2, Paradrop3, Paradrop4, Paradrop5, Paradrop6, Paradrop7, Paradrop8 }
BindActorTriggers = function(a)
if a.HasProperty("Hunt") then
if a.Owner == allies then
Trigger.OnIdle(a, a.Hunt)
else
Trigger.OnIdle(a, function(a) a.AttackMove(AlliedTechnologyCenter.Location) end)
end
end
if a.HasProperty("HasPassengers") then
Trigger.OnDamaged(a, function()
if a.HasPassengers then
a.Stop()
a.UnloadPassengers()
end
end)
Actor.OnIdle(a, function() Actor.AttackMove(a, AlliedTechnologyCenter.Location) end)
end
end
SendSovietUnits = function(entryCell, unitTypes, interval)
local i = 0
team = {}
Utils.Do(unitTypes, function(type)
local a = Actor.Create(type, false, { Owner = soviets, Location = entryCell })
BindActorTriggers(a)
Trigger.AfterDelay(i * interval, function() a.IsInWorld = true end)
table.insert(team, a)
i = i + 1
end)
Trigger.OnAllKilled(team, function() SendSovietUnits(entryCell, unitTypes, interval) 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)
local transport = Actor.Create("lst", true, { Location = LstEntry.Location, Owner = allies })
Utils.Do({ "1tnk", "1tnk", "jeep", "2tnk", "2tnk" }, function(type)
local a = Actor.Create(type, false, { Owner = allies })
BindActorTriggers(a)
transport.LoadPassenger(a)
end)
transport.Move(LstUnload.Location)
transport.UnloadPassengers()
transport.Wait(50)
transport.Move(LstEntry.Location)
transport.Destroy()
Trigger.AfterDelay(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)
local lz = Utils.Random(ParadropWaypoints).Location
local start = Utils.CenterOfCell(Map.RandomEdgeCell()) + WVec.New(0, 0, Actor.CruiseAltitude("badr"))
local transport = Actor.Create("badr", true, { CenterPosition = start, Owner = soviets, Facing = (Utils.CenterOfCell(lz) - start).Facing })
Utils.Do(ParadropUnitTypes, function(type)
local a = Actor.Create(type, false, { Owner = soviets })
BindActorTriggers(a)
transport.LoadPassenger(a)
end)
transport.Paradrop(lz)
Trigger.AfterDelay(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)
ProduceUnits = function(t)
local factory = t[1]
if not factory.IsDead then
local unitType = t[2][Utils.RandomInteger(1, #t[2] + 1)]
factory.Wait(Actor.BuildTime(unitType))
factory.Produce(unitType)
factory.CallFunc(function() ProduceUnits(t) end)
end
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")
Utils.Do(Map.NamedActors, function(a)
if a.Owner == allies and a.HasProperty("Invulnerable") then
a.Invulnerable = true
a.Stance = "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
SetupFactories = function()
Utils.Do(ProducedUnitTypes, function(pair)
Trigger.OnProduction(pair[1], function(_, a) BindActorTriggers(a) end)
end)
end
ChronoshiftAlliedUnits = function()
local cells = Map.ExpandFootprint({ ChronoshiftLocation.Location }, false)
local cells = Utils.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)
local unit = Actor.Create("2tnk", true, { Owner = allies, Facing = 0 })
BindActorTriggers(unit)
units[unit] = cells[i]
end
Chronosphere.Chronoshift(units)
Trigger.AfterDelay(60 * 25, ChronoshiftAlliedUnits)
end
ticks = 0
@@ -117,33 +142,21 @@ 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
Camera.Position = viewportOrigin + WVec.New(19200 * math.sin(t), 20480 * math.cos(t), 0)
end
WorldLoaded = function()
allies = OpenRA.GetPlayer("Allies")
soviets = OpenRA.GetPlayer("Soviets")
viewportOrigin = OpenRA.GetViewportCenterPosition()
allies = Player.GetPlayer("Allies")
soviets = Player.GetPlayer("Soviets")
viewportOrigin = Camera.Position
SetupAlliedUnits()
SetupFactories()
ProduceUnits()
ShipAlliedUnits()
ParadropSovietUnits()
OpenRA.RunAfterDelay(5 * 25, ChronoshiftAlliedUnits)
OpenRA.GiveCash(allies, 1000000)
OpenRA.GiveCash(soviets, 1000000)
Trigger.AfterDelay(5 * 25, ChronoshiftAlliedUnits)
Utils.Do(ProducedUnitTypes, ProduceUnits)
SendSovietUnits(Entry1.Location, UnitTypes, 50)
SendSovietUnits(Entry2.Location, UnitTypes, 50)
SendSovietUnits(Entry3.Location, UnitTypes, 50)

View File

@@ -315,9 +315,6 @@ Actors:
Actor110: fcom
Location: 106,44
Owner: Soviets
Actor111: silo
Location: 96,28
Owner: Soviets
Actor106: fact
Location: 114,43
Owner: Soviets
@@ -477,9 +474,6 @@ Actors:
Actor105: brik
Location: 94,70
Owner: Allies
Actor154: silo
Location: 82,86
Owner: Allies
SovietBarracks1: barr
Location: 109,48
Owner: Soviets
@@ -956,30 +950,6 @@ Actors:
Actor195: hpad
Location: 70,75
Owner: Allies
Actor75: oilb
Location: 4,126
Owner: Allies
Actor334: oilb
Location: 6,126
Owner: Allies
Actor335: oilb
Location: 8,126
Owner: Allies
Actor336: oilb
Location: 10,126
Owner: Allies
Actor337: oilb
Location: 12,126
Owner: Allies
Actor338: oilb
Location: 14,126
Owner: Allies
Actor339: oilb
Location: 2,126
Owner: Allies
Actor340: oilb
Location: 0,126
Owner: Allies
Actor341: dome
Location: 63,73
Owner: Allies
@@ -1034,15 +1004,6 @@ Actors:
Actor361: pbox.e1
Location: 71,96
Owner: Allies
Actor55: silo
Location: 81,85
Owner: Allies
Actor76: silo
Location: 81,86
Owner: Allies
Actor159: silo
Location: 82,85
Owner: Allies
Actor365: hpad
Location: 64,78
Owner: Allies
@@ -1303,11 +1264,16 @@ Rules:
-CrateSpawner:
-SpawnMPUnits:
-MPStartLocations:
LuaScriptInterface:
LuaScripts: desert-shellmap.lua
ResourceType@ore:
ValuePerUnit: 0
LuaScript:
Scripts: desert-shellmap.lua
LoadWidgetAtGameStart:
Widget: MAINMENU
-StartGameNotification:
OILB:
CashTrickler:
ShowTicks: false
TRAN.Husk2:
Burns:
Damage: 0
@@ -1316,24 +1282,6 @@ Rules:
APC:
Cargo:
InitialUnits: e1, e1, e2, e3, e4
TENT:
ProductionQueue:
Type: Infantry
Group: Infantry
BuildSpeed: .4
LowPowerSlowdown: 3
BARR:
ProductionQueue:
Type: Infantry
Group: Infantry
BuildSpeed: .4
LowPowerSlowdown: 3
WEAP:
ProductionQueue:
Type: Vehicle
Group: Vehicle
BuildSpeed: .4
LowPowerSlowdown: 3
Ant:
Buildable:
Owner: soviet
@@ -1341,6 +1289,7 @@ Rules:
Health:
HP: 200
^Vehicle:
ScriptInvulnerable:
GivesBounty:
Percentage: 0
GainsExperience:
@@ -1349,6 +1298,7 @@ Rules:
ArmorModifier:
SpeedModifier:
^Tank:
ScriptInvulnerable:
GivesBounty:
Percentage: 0
GainsExperience:
@@ -1357,6 +1307,7 @@ Rules:
ArmorModifier:
SpeedModifier:
^Infantry:
ScriptInvulnerable:
-Selectable: # short-term hack to make infantry not play die sounds until we fix RenderInfantry
GivesBounty:
Percentage: 0
@@ -1366,12 +1317,15 @@ Rules:
ArmorModifier:
SpeedModifier:
^Ship:
ScriptInvulnerable:
GivesBounty:
Percentage: 0
^Plane:
ScriptInvulnerable:
GivesBounty:
Percentage: 0
^Building:
ScriptInvulnerable:
GivesBounty:
Percentage: 0

View File

@@ -52,6 +52,7 @@
CancelActivity: True
CaptureNotification:
Notification: UnitStolen
ScriptTriggers:
^Tank:
AppearsOnRadar:
@@ -107,6 +108,7 @@
CancelActivity: True
CaptureNotification:
Notification: UnitStolen
ScriptTriggers:
^Infantry:
AppearsOnRadar:
@@ -165,6 +167,7 @@
RequiresTech: InfantryHealing
Huntable:
LuaScriptEvents:
ScriptTriggers:
^Ship:
AppearsOnRadar:
@@ -197,6 +200,7 @@
BodyOrientation:
Huntable:
LuaScriptEvents:
ScriptTriggers:
^Plane:
AppearsOnRadar:
@@ -231,6 +235,7 @@
BodyOrientation:
Huntable:
LuaScriptEvents:
ScriptTriggers:
^Helicopter:
Inherits: ^Plane
@@ -283,6 +288,7 @@
Huntable:
LuaScriptEvents:
Demolishable:
ScriptTriggers:
^Wall:
AppearsOnRadar:
@@ -319,6 +325,7 @@
BodyOrientation:
FrozenUnderFog:
LuaScriptEvents:
ScriptTriggers:
^TechBuilding:
Inherits: ^Building
@@ -426,6 +433,7 @@
FrozenUnderFog:
StartsRevealed: true
LuaScriptEvents:
ScriptTriggers:
^Husk:
Husk:
@@ -455,6 +463,7 @@
TransformOnCapture:
ForceHealthPercentage: 25
DisabledOverlay:
ScriptTriggers:
^HelicopterHusk:
Inherits: ^Husk
@@ -499,6 +508,7 @@
AutoTargetIgnore:
BodyOrientation:
LuaScriptEvents:
ScriptTriggers:
^Rock:
Tooltip:
@@ -520,6 +530,7 @@
FrozenUnderFog:
StartsRevealed: true
LuaScriptEvents:
ScriptTriggers:
^DesertCivBuilding:
Inherits: ^CivBuilding

View File

@@ -39,6 +39,7 @@
Huntable:
LuaScriptEvents:
Demolishable:
ScriptTriggers:
^Wall:
AppearsOnRadar:
@@ -77,6 +78,7 @@
BodyOrientation:
LuaScriptEvents:
Demolishable:
ScriptTriggers:
^Infantry:
AppearsOnRadar:
@@ -129,6 +131,7 @@
BodyOrientation:
Huntable:
LuaScriptEvents:
ScriptTriggers:
^CivilianInfantry:
Inherits: ^Infantry
@@ -199,6 +202,7 @@
CameraPitch: 90
Huntable:
LuaScriptEvents:
ScriptTriggers:
^Helicopter:
AppearsOnRadar:
@@ -232,4 +236,5 @@
CameraPitch: 90
Huntable:
LuaScriptEvents:
ScriptTriggers: