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

@@ -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;
}
}
}