Add Lua standard library and supporting C#/yaml

This commit is contained in:
ScottNZ
2013-11-29 23:48:44 +13:00
parent 6a14434cff
commit e4d477b0e0
19 changed files with 787 additions and 5 deletions

View File

@@ -0,0 +1,48 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Move;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Activities
{
public class Hunt : Activity
{
readonly IEnumerable<Actor> targets;
public Hunt(Actor self)
{
var attack = self.Trait<AttackBase>();
targets = self.World.Actors.Where(a => self != a && !a.IsDead() && a.IsInWorld && a.AppearsHostileTo(self)
&& a.HasTrait<Huntable>() && attack.HasAnyValidWeapons(Target.FromActor(a)));
}
public override Activity Tick(Actor self)
{
if (IsCanceled)
return NextActivity;
var target = targets.ClosestTo(self);
if (target == null)
return this;
return Util.SequenceActivities(
new AttackMove.AttackMoveActivity(self, new Move.Move(target.Location, WRange.FromCells(2))),
new Wait(25),
this);
}
}
public class HuntableInfo : TraitInfo<Huntable> { }
public class Huntable { }
}

View File

@@ -81,6 +81,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Activities\CaptureActor.cs" />
<Compile Include="Activities\Hunt.cs" />
<Compile Include="AI\AttackOrFleeFuzzy.cs" />
<Compile Include="AI\BaseBuilder.cs" />
<Compile Include="AI\HackyAI.cs" />
@@ -338,6 +339,7 @@
<Compile Include="RepairsUnits.cs" />
<Compile Include="Reservable.cs" />
<Compile Include="ScaredyCat.cs" />
<Compile Include="Scripting\LuaScriptEvents.cs" />
<Compile Include="Scripting\LuaScriptInterface.cs" />
<Compile Include="Scripting\Media.cs" />
<Compile Include="Scripting\RASpecialPowers.cs" />

View File

@@ -0,0 +1,40 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Traits;
namespace OpenRA.Mods.RA.Scripting
{
public class LuaScriptEventsInfo : TraitInfo<LuaScriptEvents> { }
public class LuaScriptEvents : INotifyKilled, INotifyAddedToWorld, INotifyRemovedFromWorld
{
public event Action<Actor, AttackInfo> OnKilled = (self, e) => { };
public event Action<Actor> OnAddedToWorld = self => { };
public event Action<Actor> OnRemovedFromWorld = self => { };
public void Killed(Actor self, AttackInfo e)
{
OnKilled(self, e);
}
public void AddedToWorld(Actor self)
{
OnAddedToWorld(self);
}
public void RemovedFromWorld(Actor self)
{
OnRemovedFromWorld(self);
}
}
}

View File

@@ -8,12 +8,16 @@
*/
#endregion
using System;
using System.Linq;
using LuaInterface;
using OpenRA.Effects;
using OpenRA.FileFormats;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Air;
using OpenRA.Mods.RA.Missions;
using OpenRA.Scripting;
using OpenRA.Traits;
using System;
using System.Linq;
using WorldRenderer = OpenRA.Graphics.WorldRenderer;
namespace OpenRA.Mods.RA.Scripting
@@ -42,7 +46,7 @@ namespace OpenRA.Mods.RA.Scripting
AddMapActorGlobals();
context.Lua["World"] = w;
context.Lua["WorldRenderer"] = wr;
context.RegisterObject(this, "_OpenRA", false);
context.RegisterObject(this, "Internal", false);
context.RegisterType(typeof(WVec), "WVec", true);
context.RegisterType(typeof(WPos), "WPos", true);
context.RegisterType(typeof(CPos), "CPos", true);
@@ -161,5 +165,101 @@ namespace OpenRA.Mods.RA.Scripting
{
world.AddFrameEndTask(w => w.Add(new DelayedAction((int)delay, func)));
}
[LuaGlobal]
public void PlaySpeechNotification(Player player, string notification)
{
Sound.PlayNotification(player, "Speech", notification, player != null ? player.Country.Race : null);
}
[LuaGlobal]
public void PlaySoundNotification(Player player, string notification)
{
Sound.PlayNotification(player, "Sounds", notification, player != null ? player.Country.Race : null);
}
[LuaGlobal]
public void WaitFor(Actor actor, Func<bool> func)
{
actor.QueueActivity(new WaitFor(func));
}
[LuaGlobal]
public void CallFunc(Actor actor, Action func)
{
actor.QueueActivity(new CallFunc(func));
}
[LuaGlobal]
public int GetFacing(object vec, double currentFacing)
{
if (vec is CVec)
return Util.GetFacing((CVec)vec, (int)currentFacing);
if (vec is WVec)
return Util.GetFacing((WVec)vec, (int)currentFacing);
throw new ArgumentException("Unsupported vector type: {0}".F(vec.GetType()));
}
[LuaGlobal]
public WRange GetWRangeFromCells(double cells)
{
return WRange.FromCells((int)cells);
}
[LuaGlobal]
public void SetWinState(Player player, string winState)
{
player.WinState = Enum<WinState>.Parse(winState);
}
[LuaGlobal]
public void PlayRandomMusic()
{
MissionUtils.PlayMissionMusic();
}
[LuaGlobal]
public bool IsDead(Actor actor)
{
return actor.IsDead();
}
[LuaGlobal]
public void PlayMovieFullscreen(string movie, Action onComplete)
{
Media.PlayFMVFullscreen(world, movie, onComplete);
}
[LuaGlobal]
public void FlyToPos(Actor actor, WPos pos)
{
actor.QueueActivity(Fly.ToPos(pos));
}
[LuaGlobal]
public void FlyAttackActor(Actor actor, Actor targetActor)
{
actor.QueueActivity(new FlyAttack(Target.FromActor(targetActor)));
}
[LuaGlobal]
public void FlyAttackCell(Actor actor, CPos location)
{
actor.QueueActivity(new FlyAttack(Target.FromCell(location)));
}
[LuaGlobal]
public void SetUnitStance(Actor actor, string stance)
{
var at = actor.TraitOrDefault<AutoTarget>();
if (at != null)
at.stance = Enum<UnitStance>.Parse(stance);
}
[LuaGlobal]
public bool RequiredUnitsAreDestroyed(Player player)
{
return world.ActorsWithTrait<MustBeDestroyed>().All(p => p.Actor.Owner != player);
}
}
}

View File

@@ -163,3 +163,12 @@ Fonts:
TinyBold:
Font:FreeSansBold.ttf
Size:10
LuaScripts:
mods/ra/lua/utils.lua
mods/ra/lua/openra.lua
mods/ra/lua/map.lua
mods/ra/lua/actor.lua
mods/ra/lua/team.lua
mods/ra/lua/media.lua
mods/ra/lua/mission.lua

View File

@@ -40,6 +40,8 @@
CloakDelay: 90
CloakSound: trans1.aud
UncloakSound: trans1.aud
Huntable:
LuaScriptEvents:
^Tank:
AppearsOnRadar:
@@ -86,6 +88,8 @@
CloakDelay: 90
CloakSound: trans1.aud
UncloakSound: trans1.aud
Huntable:
LuaScriptEvents:
^Helicopter:
AppearsOnRadar:
@@ -113,6 +117,8 @@
CombatDebugOverlay:
BodyOrientation:
UpdatesPlayerStatistics:
Huntable:
LuaScriptEvents:
^Infantry:
AppearsOnRadar:
@@ -170,6 +176,8 @@
DamageCooldown: 125
RequiresTech: InfantryHealing
UpdatesPlayerStatistics:
Huntable:
LuaScriptEvents:
^CivInfantry:
Inherits: ^Infantry
@@ -247,6 +255,8 @@
AttackMove:
AttackFrontal:
UpdatesPlayerStatistics:
Huntable:
LuaScriptEvents:
^Plane:
AppearsOnRadar:
@@ -263,6 +273,8 @@
ActorLostNotification:
CombatDebugOverlay:
BodyOrientation:
Huntable:
LuaScriptEvents:
^Ship:
AppearsOnRadar:
@@ -286,6 +298,8 @@
Guardable:
BodyOrientation:
UpdatesPlayerStatistics:
Huntable:
LuaScriptEvents:
^Building:
AppearsOnRadar:
@@ -337,6 +351,8 @@
FrozenUnderFog:
UpdatesPlayerStatistics:
EngineerRepairable:
Huntable:
LuaScriptEvents:
^CivBuilding:
Inherits: ^Building
@@ -372,6 +388,7 @@
BodyOrientation:
FrozenUnderFog:
StartsRevealed: true
LuaScriptEvents:
^TechBuilding:
Inherits: ^CivBuilding
@@ -407,6 +424,7 @@
Palette: terrain
FrozenUnderFog:
StartsRevealed: true
LuaScriptEvents:
^Wall:
AppearsOnRadar:
@@ -437,6 +455,7 @@
Guardable:
BodyOrientation:
FrozenUnderFog:
LuaScriptEvents:
^Tree:
Tooltip:
@@ -460,6 +479,7 @@
BodyOrientation:
FrozenUnderFog:
StartsRevealed: true
LuaScriptEvents:
^Rock:
Tooltip:
@@ -477,6 +497,7 @@
BodyOrientation:
FrozenUnderFog:
StartsRevealed: true
LuaScriptEvents:
^Husk:
Health:
@@ -499,6 +520,7 @@
# AllowAllies: true
# AllowNeutral: true
# AllowEnemies: true
LuaScriptEvents:
^HelicopterHusk:
Inherits: ^Husk
@@ -524,3 +546,4 @@
DamagedSound: xplos.aud
DestroyedSound: xplobig4.aud
BodyOrientation:
LuaScriptEvents:

View File

@@ -144,3 +144,12 @@ Fonts:
TinyBold:
Font:FreeSansBold.ttf
Size:10
LuaScripts:
mods/ra/lua/utils.lua
mods/ra/lua/openra.lua
mods/ra/lua/map.lua
mods/ra/lua/actor.lua
mods/ra/lua/team.lua
mods/ra/lua/media.lua
mods/ra/lua/mission.lua

View File

@@ -35,6 +35,8 @@
RenderUnit:
BodyOrientation:
UpdatesPlayerStatistics:
Huntable:
LuaScriptEvents:
^Tank:
AppearsOnRadar:
@@ -73,6 +75,8 @@
RenderUnit:
BodyOrientation:
UpdatesPlayerStatistics:
Huntable:
LuaScriptEvents:
^Husk:
Health:
@@ -90,6 +94,7 @@
Tooltip:
Name: Destroyed Tank
BodyOrientation:
LuaScriptEvents:
^TowerHusk:
Health:
@@ -108,6 +113,7 @@
ProximityCaptor:
Types:Husk
BodyOrientation:
LuaScriptEvents:
^AircraftHusk:
Inherits: ^Husk
@@ -167,6 +173,8 @@
Guardable:
BodyOrientation:
UpdatesPlayerStatistics:
Huntable:
LuaScriptEvents:
^Plane:
AppearsOnRadar:
@@ -188,6 +196,8 @@
CombatDebugOverlay:
BodyOrientation:
UpdatesPlayerStatistics:
Huntable:
LuaScriptEvents:
^Helicopter:
Inherits: ^Plane
@@ -237,3 +247,5 @@
BodyOrientation:
UpdatesPlayerStatistics:
WithCrumbleOverlay:
Huntable:
LuaScriptEvents:

147
mods/ra/lua/actor.lua Normal file
View File

@@ -0,0 +1,147 @@
Actor = { }
Actor.Create = function(name, init)
if name == nil then error("No actor name specified", 2) end
if init.Owner == nil then error("No actor owner specified", 2) end
local td = OpenRA.New("TypeDictionary")
local addToWorld = true
for key, value in pairs(init) do
if key == "AddToWorld" then
addToWorld = value
else
td:Add(OpenRA.New(key .. "Init", { value }))
end
end
return World:CreateActor(addToWorld, name, td)
end
Actor.Turn = function(actor, facing)
actor:QueueActivity(OpenRA.New("Turn", { { facing, "Int32" } }))
end
Actor.Move = function(actor, location)
Actor.MoveNear(actor, location, 0)
end
Actor.MoveNear = function(actor, location, nearEnough)
actor:QueueActivity(OpenRA.New("Move", { location, Map.GetWRangeFromCells(nearEnough) }))
end
Actor.HeliFly = function(actor, position)
actor:QueueActivity(OpenRA.New("HeliFly", { position }))
end
Actor.HeliLand = function(actor, requireSpace)
actor:QueueActivity(OpenRA.New("HeliLand", { requireSpace }))
end
Actor.Fly = function(actor, position)
Internal.FlyToPos(actor, position)
end
Actor.FlyAttackActor = function(actor, targetActor)
Internal.FlyAttackActor(actor, targetActor)
end
Actor.FlyAttackCell = function(actor, location)
Internal.FlyAttackCell(actor, location)
end
Actor.FlyOffMap = function(actor)
actor:QueueActivity(OpenRA.New("FlyOffMap"))
end
Actor.Hunt = function(actor)
actor:QueueActivity(OpenRA.New("Hunt", { actor }))
end
Actor.UnloadCargo = function(actor, unloadAll)
actor:QueueActivity(OpenRA.New("UnloadCargo", { unloadAll }))
end
Actor.Harvest = function(actor)
actor:QueueActivity(OpenRA.New("FindResources"))
end
Actor.Scatter = function(actor)
local mobile = Actor.Trait(actor, "Mobile")
mobile:Nudge(actor, actor, true)
end
Actor.Wait = function(actor, period)
actor:QueueActivity(OpenRA.New("Wait", { { period, "Int32" } }))
end
Actor.WaitFor = function(actor, func)
Internal.WaitFor(actor, func)
end
Actor.CallFunc = function(actor, func)
Internal.CallFunc(actor, func)
end
Actor.DeployTransform = function(actor)
Actor.CallFunc(actor, function()
Actor.Trait(actor, "Transforms"):DeployTransform()
end)
end
Actor.RemoveSelf = function(actor)
actor:QueueActivity(OpenRA.New("RemoveSelf"))
end
Actor.Stop = function(actor)
actor:CancelActivity()
end
Actor.IsDead = function(actor)
return Internal.IsDead(actor)
end
Actor.IsInWorld = function(actor)
return actor.IsInWorld
end
Actor.Owner = function(actor)
return actor.Owner
end
Actor.SetStance = function(actor, stance)
Internal.SetUnitStance(actor, stance)
end
Actor.OnKilled = function(actor, eh)
Actor.Trait(actor, "LuaScriptEvents").OnKilled:Add(eh)
end
Actor.OnAddedToWorld = function(actor, eh)
Actor.Trait(actor, "LuaScriptEvents").OnAddedToWorld:Add(eh)
end
Actor.OnRemovedFromWorld = function(actor, eh)
Actor.Trait(actor, "LuaScriptEvents").OnRemovedFromWorld:Add(eh)
end
Actor.HasTrait = function(actor, className)
return Internal.HasTrait(actor, className)
end
Actor.TraitOrDefault = function(actor, className)
return Internal.TraitOrDefault(actor, className)
end
Actor.Trait = function(actor, className)
return Internal.Trait(actor, className)
end
Actor.HasTraitInfo = function(actorType, className)
return Internal.HasTraitInfo(actorType, className)
end
Actor.TraitInfoOrDefault = function(actorType, className)
return Internal.TraitInfoOrDefault(actorType, className)
end
Actor.TraitInfo = function(actorType, className)
return Internal.TraitInfo(actorType, className)
end

9
mods/ra/lua/map.lua Normal file
View File

@@ -0,0 +1,9 @@
Map = { }
Map.GetFacing = function(vec, currentFacing)
return Internal.GetFacing(vec, currentFacing)
end
Map.GetWRangeFromCells = function(cells)
return Internal.GetWRangeFromCells(cells)
end

20
mods/ra/lua/media.lua Normal file
View File

@@ -0,0 +1,20 @@
Media = { }
Media.PlaySpeechNotification = function(notification, player)
Internal.PlaySpeechNotification(player, notification)
end
Media.PlaySoundNotification = function(notification, player)
Internal.PlaySoundNotification(player, notification)
end
Media.PlayRandomMusic = function()
Internal.PlayRandomMusic()
end
Media.PlayMovieFullscreen = function(movie, onComplete)
if onComplete == nil then
onComplete = function() end
end
Internal.PlayMovieFullscreen(movie, onComplete)
end

119
mods/ra/lua/mission.lua Normal file
View File

@@ -0,0 +1,119 @@
Mission = { }
Mission.PerformHelicopterInsertion = function(owner, helicopterName, passengerNames, enterPosition, unloadPosition, exitPosition)
local facing = { Map.GetFacing(WPos.op_Subtraction(unloadPosition, enterPosition), 0), "Int32" }
local altitude = { Actor.TraitInfo(helicopterName, "AircraftInfo").CruiseAltitude, "Int32" }
local heli = Actor.Create(helicopterName, { Owner = owner, CenterPosition = enterPosition, Facing = facing, Altitude = altitude })
local cargo = Actor.Trait(heli, "Cargo")
local passengers = { }
for i, passengerName in ipairs(passengerNames) do
local passenger = Actor.Create(passengerName, { AddToWorld = false, Owner = owner })
cargo:Load(heli, passenger)
passengers[i] = passenger
end
Actor.HeliFly(heli, unloadPosition)
Actor.Turn(heli, 0)
Actor.HeliLand(heli, true)
Actor.UnloadCargo(heli, true)
Actor.Wait(heli, 125)
Actor.HeliFly(heli, exitPosition)
Actor.RemoveSelf(heli)
return heli, passengers
end
Mission.PerformHelicopterExtraction = function(owner, helicopterName, passengers, enterPosition, loadPosition, exitPosition)
local facing = { Map.GetFacing(WPos.op_Subtraction(loadPosition, enterPosition), 0), "Int32" }
local altitude = { Actor.TraitInfo(helicopterName, "AircraftInfo").CruiseAltitude, "Int32" }
local heli = Actor.Create(helicopterName, { Owner = owner, CenterPosition = enterPosition, Facing = facing, Altitude = altitude })
local cargo = Actor.Trait(heli, "Cargo")
Actor.HeliFly(heli, loadPosition)
Actor.Turn(heli, 0)
Actor.HeliLand(heli, true)
Actor.WaitFor(heli, function()
for i, passenger in ipairs(passengers) do
if not cargo.Passengers:Contains(passenger) then
return false
end
end
return true
end)
Actor.Wait(heli, 125)
Actor.HeliFly(heli, exitPosition)
Actor.RemoveSelf(heli)
return heli
end
Mission.Reinforce = function(owner, reinforcementNames, enterLocation, rallyPointLocation, interval, onCreateFunc)
local facing = { Map.GetFacing(CPos.op_Subtraction(rallyPointLocation, enterLocation), 0), "Int32" }
local ret = { }
for i = 1, #reinforcementNames do
local reinforcement = Actor.Create(reinforcementNames[i], { AddToWorld = false, Owner = owner, Location = enterLocation, Facing = facing })
table.insert(ret, reinforcement)
OpenRA.RunAfterDelay((i - 1) * interval, function()
World:Add(reinforcement)
Actor.MoveNear(reinforcement, rallyPointLocation, 2)
if onCreateFunc ~= nil then
onCreateFunc(reinforcement)
end
end)
end
return ret
end
Mission.Parabomb = function(owner, planeName, enterLocation, bombLocation)
local facing = { Map.GetFacing(CPos.op_Subtraction(bombLocation, enterLocation), 0), "Int32" }
local altitude = { Actor.TraitInfo(planeName, "AircraftInfo").CruiseAltitude, "Int32" }
local plane = Actor.Create(planeName, { Location = enterLocation, Owner = owner, Facing = facing, Altitude = altitude })
Actor.Trait(plane, "AttackBomber"):SetTarget(bombLocation.CenterPosition)
Actor.Fly(plane, bombLocation.CenterPosition)
Actor.FlyOffMap(plane)
Actor.RemoveSelf(plane)
end
Mission.Paradrop = function(owner, planeName, passengerNames, enterLocation, dropLocation)
local facing = { Map.GetFacing(CPos.op_Subtraction(dropLocation, enterLocation), 0), "Int32" }
local altitude = { Actor.TraitInfo(planeName, "AircraftInfo").CruiseAltitude, "Int32" }
local plane = Actor.Create(planeName, { Location = enterLocation, Owner = owner, Facing = facing, Altitude = altitude })
Actor.FlyAttackCell(plane, dropLocation)
Actor.Trait(plane, "ParaDrop"):SetLZ(dropLocation)
local cargo = Actor.Trait(plane, "Cargo")
for i, passengerName in ipairs(passengerNames) do
cargo:Load(plane, Actor.Create(passengerName, { AddToWorld = false, Owner = owner }))
end
end
Mission.MissionOver = function(winners, losers, setWinStates)
World:SetLocalPauseState(true)
World:set_PauseStateLocked(true)
if winners then
for i, player in ipairs(winners) do
Media.PlaySpeechNotification("Win", player)
if setWinStates then
OpenRA.SetWinState(player, "Won")
end
end
end
if losers then
for i, player in ipairs(losers) do
Media.PlaySpeechNotification("Lose", player)
if setWinStates then
OpenRA.SetWinState(player, "Lost")
end
end
end
Mission.MissionIsOver = true
end
Mission.GetGroundAttackersOf = function(player)
return Utils.EnumerableWhere(World.Actors, function(actor)
return not Actor.IsDead(actor) and Actor.IsInWorld(actor) and Actor.Owner(actor) == player and Actor.HasTrait(actor, "AttackBase") and Actor.HasTrait(actor, "Mobile")
end)
end
Mission.TickTakeOre = function(player)
OpenRA.TakeOre(player, 0.01 * OpenRA.GetOreCapacity(player) / 25)
end
Mission.RequiredUnitsAreDestroyed = function(player)
return Internal.RequiredUnitsAreDestroyed(player)
end

69
mods/ra/lua/openra.lua Normal file
View File

@@ -0,0 +1,69 @@
OpenRA = { }
OpenRA.New = function(className, args)
return Internal.New(className, args)
end
OpenRA.RunAfterDelay = function(delay, func)
Internal.RunAfterDelay(delay, func)
end
OpenRA.Debug = function(obj)
Internal.Debug(obj)
end
OpenRA.SetViewportCenterPosition = function(position)
WorldRenderer.Viewport:Center(position)
end
OpenRA.GetViewportCenterPosition = function()
return WorldRenderer.Viewport.CenterPosition
end
OpenRA.GetDifficulty = function()
return World.LobbyInfo.GlobalSettings.Difficulty
end
OpenRA.IsSinglePlayer = function()
return World.LobbyInfo:get_IsSinglePlayer()
end
OpenRA.GetPlayer = function(internalName)
return Utils.EnumerableFirstOrNil(World.Players, function(p) return p.InternalName == internalName end)
end
OpenRA.SetWinState = function(player, winState)
Internal.SetWinState(player, winState)
end
OpenRA.TakeOre = function(player, amount)
Actor.Trait(player.PlayerActor, "PlayerResources"):TakeOre(amount)
end
OpenRA.TakeCash = function(player, amount)
Actor.Trait(player.PlayerActor, "PlayerResources"):TakeCash(amount)
end
OpenRA.GiveOre = function(player, amount)
Actor.Trait(player.PlayerActor, "PlayerResources"):GiveOre(amount)
end
OpenRA.GiveCash = function(player, amount)
Actor.Trait(player.PlayerActor, "PlayerResources"):GiveCash(amount)
end
OpenRA.CanGiveOre = function(player, amount)
return Actor.Trait(player.PlayerActor, "PlayerResources"):CanGiveOre(amount)
end
OpenRA.GetOreCapacity = function(player)
return Actor.Trait(player.PlayerActor, "PlayerResources").OreCapacity
end
OpenRA.GetOre = function(player)
return Actor.Trait(player.PlayerActor, "PlayerResources").Ore
end
OpenRA.GetCash = function(player)
return Actor.Trait(player.PlayerActor, "PlayerResources").Cash
end

61
mods/ra/lua/team.lua Normal file
View File

@@ -0,0 +1,61 @@
Team = { }
Team.Create = function(actors)
local team = { }
team.Actors = actors
team.OnAllKilled = { }
team.OnAnyKilled = { }
team.OnAllRemovedFromWorld = { }
team.OnAnyRemovedFromWorld = { }
Team.AddActorEventHandlers(team)
return team
end
Team.AddActorEventHandlers = function(team)
for i, actor in ipairs(team.Actors) do
Actor.OnKilled(actor, function()
Team.InvokeHandlers(team.OnAnyKilled)
if Team.AllAreDead(team) then Team.InvokeHandlers(team.OnAllKilled) end
end)
Actor.OnRemovedFromWorld(actor, function()
Team.InvokeHandlers(team.OnAnyRemovedFromWorld)
if not Team.AnyAreInWorld(team) then Team.InvokeHandlers(team.OnAllRemovedFromWorld) end
end)
end
end
Team.InvokeHandlers = function(event)
for i, handler in ipairs(event) do
handler()
end
end
Team.AllAreDead = function(team)
return Utils.All(team.Actors, Actor.IsDead)
end
Team.AnyAreDead = function(team)
return Utils.Any(team.Actors, Actor.IsDead)
end
Team.AllAreInWorld = function(team)
return Utils.All(team.Actors, Actor.IsInWorld)
end
Team.AnyAreInWorld = function(team)
return Utils.Any(team.Actors, Actor.IsInWorld)
end
Team.AddEventHandler = function(event, func)
table.insert(event, func)
end
Team.Contains = function(team, actor)
return Utils.Any(team.Actors, function(a) return a == actor end)
end
Team.Do = function(team, func)
Utils.ForEach(team.Actors, func)
end

67
mods/ra/lua/utils.lua Normal file
View File

@@ -0,0 +1,67 @@
Utils = { }
Utils.Enumerate = function(netEnumerable)
local enum = netEnumerable:GetEnumerator()
return function()
if enum:MoveNext() then
return enum:get_Current()
end
end
end
Utils.EnumerableFirstOrNil = function(netEnumerable, func)
for item in Utils.Enumerate(netEnumerable) do
if func(item) then
return item
end
end
return nil
end
Utils.EnumerableWhere = function(netEnumerable, func)
local ret = { }
for item in Utils.Enumerate(netEnumerable) do
if func(item) then
table.insert(ret, item)
end
end
return ret
end
Utils.Where = function(array, func)
local ret = { }
for i, item in ipairs(array) do
if func(item) then
table.insert(ret, item)
end
end
return ret
end
Utils.All = function(array, func)
for i, item in ipairs(array) do
if not func(item) then
return false
end
end
return true
end
Utils.Any = function(array, func)
for i, item in ipairs(array) do
if func(item) then
return true
end
end
return false
end
Utils.ForEach = function(array, func)
for i, item in ipairs(array) do
func(item)
end
end
Utils.TableToArray = function(luaTable)
return Internal.TableToArray(luaTable)
end

View File

@@ -164,3 +164,12 @@ Fonts:
TinyBold:
Font:FreeSansBold.ttf
Size:10
LuaScripts:
mods/ra/lua/utils.lua
mods/ra/lua/openra.lua
mods/ra/lua/map.lua
mods/ra/lua/actor.lua
mods/ra/lua/team.lua
mods/ra/lua/media.lua
mods/ra/lua/mission.lua

View File

@@ -42,6 +42,8 @@
SuccessRate: 20
EjectOnGround: yes
EjectInAir: no
Huntable:
LuaScriptEvents:
^Tank:
AppearsOnRadar:
@@ -87,6 +89,8 @@
SuccessRate: 20
EjectOnGround: yes
EjectInAir: no
Huntable:
LuaScriptEvents:
^Infantry:
AppearsOnRadar:
@@ -142,6 +146,8 @@
HealIfBelow: 1
DamageCooldown: 125
RequiresTech: InfantryHealing
Huntable:
LuaScriptEvents:
^Ship:
AppearsOnRadar:
@@ -174,6 +180,8 @@
Guard:
Guardable:
BodyOrientation:
Huntable:
LuaScriptEvents:
^Plane:
AppearsOnRadar:
@@ -203,6 +211,8 @@
UpdatesPlayerStatistics:
CombatDebugOverlay:
BodyOrientation:
Huntable:
LuaScriptEvents:
^Helicopter:
Inherits: ^Plane
@@ -252,6 +262,8 @@
FrozenUnderFog:
GpsDot:
String:Structure
Huntable:
LuaScriptEvents:
^Wall:
AppearsOnRadar:
@@ -287,6 +299,7 @@
Guardable:
BodyOrientation:
FrozenUnderFog:
LuaScriptEvents:
^TechBuilding:
Inherits: ^Building
@@ -391,6 +404,7 @@
BodyOrientation:
FrozenUnderFog:
StartsRevealed: true
LuaScriptEvents:
^Husk:
Husk:
@@ -408,6 +422,7 @@
BelowUnits:
BodyOrientation:
Chronoshiftable:
LuaScriptEvents:
^HelicopterHusk:
Inherits: ^Husk
@@ -442,6 +457,7 @@
Types:Bridge
AutoTargetIgnore:
BodyOrientation:
LuaScriptEvents:
#Temperate Terrain Expansion
^SVBridge:
@@ -459,6 +475,7 @@
Types:Bridge
AutoTargetIgnore:
BodyOrientation:
LuaScriptEvents:
^SHBridge:
Tooltip:
@@ -475,6 +492,7 @@
Types:Bridge
AutoTargetIgnore:
BodyOrientation:
LuaScriptEvents:
^STDBridge:
Tooltip:
@@ -491,6 +509,7 @@
Types:Bridge
AutoTargetIgnore:
BodyOrientation:
LuaScriptEvents:
#Desert Terrain Expansion:
^Rock:
@@ -512,6 +531,7 @@
BodyOrientation:
FrozenUnderFog:
StartsRevealed: true
LuaScriptEvents:
^DesertCivBuilding:
Inherits: ^CivBuilding

View File

@@ -185,3 +185,12 @@ Fonts:
TinyBold:
Font:FreeSansBold.ttf
Size:10
LuaScripts:
mods/ra/lua/utils.lua
mods/ra/lua/openra.lua
mods/ra/lua/map.lua
mods/ra/lua/actor.lua
mods/ra/lua/team.lua
mods/ra/lua/media.lua
mods/ra/lua/mission.lua

View File

@@ -36,6 +36,8 @@
Guardable:
Range: 3
BodyOrientation:
Huntable:
LuaScriptEvents:
^Infantry:
AppearsOnRadar:
@@ -80,6 +82,8 @@
Guard:
Guardable:
BodyOrientation:
Huntable:
LuaScriptEvents:
^CivilianInfantry:
Inherits: ^Infantry
@@ -145,6 +149,8 @@
Guard:
Guardable:
BodyOrientation:
Huntable:
LuaScriptEvents:
^Wall:
AppearsOnRadar:
@@ -175,6 +181,7 @@
Sellable:
UpdatesPlayerStatistics:
BodyOrientation:
LuaScriptEvents:
^Helicopter:
AppearsOnRadar:
@@ -198,3 +205,5 @@
ActorLostNotification:
CombatDebugOverlay:
BodyOrientation:
Huntable:
LuaScriptEvents: