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,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);
}
}
}