diff --git a/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs b/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs index 56b8671d15..1861c770cb 100644 --- a/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs +++ b/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs @@ -299,12 +299,12 @@ namespace OpenRA.Mods.RA.Scripting } [LuaGlobal] - public void AttackMove(Actor actor, CPos location) + public void AttackMove(Actor actor, CPos location, double nearEnough) { if (actor.HasTrait()) - actor.QueueActivity(new AttackMove.AttackMoveActivity(actor, new Move.Move(location, 0))); + actor.QueueActivity(new AttackMove.AttackMoveActivity(actor, new Move.Move(location, (int)nearEnough))); else - actor.QueueActivity(new Move.Move(location, 0)); + actor.QueueActivity(new Move.Move(location, (int)nearEnough)); } [LuaGlobal] @@ -330,5 +330,47 @@ namespace OpenRA.Mods.RA.Scripting { return mapActors[actorName]; } + + [LuaGlobal] + public Actor[] FindActorsInBox(WPos topLeft, WPos bottomRight) + { + return world.FindActorsInBox(topLeft, bottomRight).ToArray(); + } + + [LuaGlobal] + public Actor[] FindActorsInCircle(WPos location, WRange radius) + { + return world.FindActorsInCircle(location, radius).ToArray(); + } + + [LuaGlobal] + public void BuildWithSharedQueue(Player player, string unit, double amount) + { + var ri = Rules.Info[unit]; + if (ri == null || !ri.Traits.Contains()) + return; + + var category = ri.Traits.Get().Queue; + + var queue = world.ActorsWithTrait() + .Where(a => a.Actor.Owner == player && a.Trait.Info.Type == category) + .Select(a => a.Trait).FirstOrDefault(); + + if (queue != null) + queue.ResolveOrder(queue.self, Order.StartProduction(queue.self, unit, (int)amount)); + } + + [LuaGlobal] + public void BuildWithPerFactoryQueue(Actor factory, string unit, double amount) + { + if (!factory.HasTrait()) + return; + + var ri = Rules.Info[unit]; + if (ri == null || !ri.Traits.Contains()) + return; + + factory.Trait().ResolveOrder(factory, Order.StartProduction(factory, unit, (int)amount)); + } } } diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index d8deb3b629..82a28d7449 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -180,3 +180,4 @@ LuaScripts: mods/common/lua/reinforcements.lua mods/common/lua/supportpowers.lua mods/common/lua/rules.lua + mods/common/lua/production.lua diff --git a/mods/common/lua/actor.lua b/mods/common/lua/actor.lua index a676f16db2..7eb9e650c7 100644 --- a/mods/common/lua/actor.lua +++ b/mods/common/lua/actor.lua @@ -47,8 +47,8 @@ Actor.Teleport = function(actor, location) actor:QueueActivity(OpenRA.New("SimpleTeleport", { location })) end -Actor.AttackMove = function(actor, location) - Internal.AttackMove(actor, location) +Actor.AttackMove = function(actor, location, nearEnough) + Internal.AttackMove(actor, location, nearEnough or 0) end Actor.HeliFly = function(actor, position) @@ -178,3 +178,25 @@ end Actor.Trait = function(actor, className) return Internal.Trait(actor, className) end + +Actor.ReturnToBase = function(actor, airfield) + actor:QueueActivity(OpenRA.New("ReturnToBase", { actor, airfield })) +end + +Actor.Patrol = function(actor, waypoints, wait, loop) + Utils.Do(waypoints, function(wpt) + Actor.AttackMove(actor, wpt.Location, 3) + Actor.Wait(actor, wait or 0) + end) + if loop or loop == nil then + Actor.CallFunc(actor, function() Actor.Patrol(actor, waypoints, wait, loop) end) + end +end + +Actor.PatrolUntil = function(actor, waypoints, wait, func) + if func == nil then error("No function specified", 2) end + Actor.Patrol(actor, waypoints, wait, false) + if not func(actor) then + Actor.CallFunc(actor, function() Actor.PatrolUntil(actor, waypoints, wait, func) end) + end +end diff --git a/mods/common/lua/map.lua b/mods/common/lua/map.lua index 1b587cf780..48f4194540 100644 --- a/mods/common/lua/map.lua +++ b/mods/common/lua/map.lua @@ -16,6 +16,48 @@ Map.GetNamedActor = function(actorName) return Internal.GetNamedActor(actorName) end +Map.FindActorsInCircle = function(location, radius, func) + local actors = Internal.FindActorsInCircle(location.CenterPosition, WRange.FromCells(radius)) + return Utils.EnumerableWhere(actors, func) +end + +Map.FindActorsInBox = function(topLeft, bottomRight, func) + local actors = Internal.FindActorsInBox(topLeft.CenterPosition, bottomRight.CenterPosition) + return Utils.EnumerableWhere(actors, func) +end + +Map.__FilterByTrait = function(a, player, trait) + return Actor.Owner(a) == player and Actor.HasTrait(a, trait) +end + +Map.__FilterByTraitAndIdle = function(a, player, trait) + return Map.__FilterByTrait(a, player, trait) and Actor.IsIdle(a) +end + +Map.FindUnitsInCircle = function(player, location, radius) + return Map.FindActorsInCircle(location, radius, function(a) return Map.__FilterByTrait(a, player, "Mobile") end) +end + +Map.FindUnitsInBox = function(player, topLeft, bottomRight) + return Map.FindActorsInBox(topLeft, bottomRight, function(a) return Map.__FilterByTrait(a, player, "Mobile") end) +end + +Map.FindStructuresInCircle = function(player, location, radius) + return Map.FindActorsInCircle(location, radius, function(a) return Map.__FilterByTrait(a, player, "Building") end) +end + +Map.FindStructuresInBox = function(player, topLeft, bottomRight) + return Map.FindActorsInBox(topLeft, bottomRight, function(a) return Map.__FilterByTrait(a, player, "Building") end) +end + +Map.FindIdleUnitsInCircle = function(player, location, radius) + return Map.FindActorsInCircle(location, radius, function(a) return Map.__FilterByTraitAndIdle(a, player, "Mobile") end) +end + +Map.FindIdleUnitsInBox = function(player, topLeft, bottomRight) + return Map.FindActorsInBox(topLeft, bottomRight, function(a) return Map.__FilterByTraitAndIdle(a, player, "Mobile") end) +end + CPos.New = function(x, y) return OpenRA.New("CPos", { { x, "Int32" }, { y, "Int32" } }) end diff --git a/mods/common/lua/openra.lua b/mods/common/lua/openra.lua index 16f1e02671..1b8b9d9bab 100644 --- a/mods/common/lua/openra.lua +++ b/mods/common/lua/openra.lua @@ -10,6 +10,7 @@ OpenRA.New = function(className, args) end OpenRA.RunAfterDelay = function(delay, func) + if func == nil then error("No function specified", 2) end Internal.RunAfterDelay(delay, func) end @@ -42,7 +43,11 @@ OpenRA.SetWinState = function(player, winState) end OpenRA.GetRandomInteger = function(low, high) - return Internal.GetRandomInteger(low, high) + if high <= low then + return low + else + return Internal.GetRandomInteger(low, high) + end end OpenRA.TakeOre = function(player, amount) diff --git a/mods/common/lua/production.lua b/mods/common/lua/production.lua new file mode 100644 index 0000000000..9acef2b6c5 --- /dev/null +++ b/mods/common/lua/production.lua @@ -0,0 +1,17 @@ +Production = { } + +Production.BuildWithSharedQueue = function(player, unit, amount) + Internal.BuildWithSharedQueue(player, unit, amount or 1) +end + +Production.BuildWithPerFactoryQueue = function(factory, unit, amount) + Internal.BuildWithPerFactoryQueue(factory, unit, amount or 1) +end + +Production.SetRallyPoint = function(factory, location) + Actor.Trait(factory, "RallyPoint").rallyPoint = location.Location +end + +Production.SetPrimaryBuilding = function(factory) + Actor.Trait(factory, "PrimaryBuilding"):SetPrimaryProducer(factory, true) +end diff --git a/mods/common/lua/team.lua b/mods/common/lua/team.lua index 6d41af2d23..f0f9da15c8 100644 --- a/mods/common/lua/team.lua +++ b/mods/common/lua/team.lua @@ -12,24 +12,22 @@ Team.New = function(actors) end Team.AddActorEventHandlers = function(team) - for i, actor in ipairs(team.Actors) do + Team.Do(team, function(actor) 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) end Team.InvokeHandlers = function(event) - for i, handler in ipairs(event) do - handler() - end + Utils.Do(event, function(handler) handler() end) end Team.AllAreDead = function(team) @@ -58,4 +56,12 @@ end Team.Do = function(team, func) Utils.Do(team.Actors, func) -end \ No newline at end of file +end + +Team.Patrol = function(team, waypoints, wait, loop) + Team.Do(team, function(a) Actor.Patrol(a, waypoints, wait, loop) end) +end + +Team.PatrolUntil = function(team, waypoints, wait, func) + Team.Do(team, function(a) Actor.PatrolUntil(a, waypoints, wait, func) end) +end diff --git a/mods/common/lua/utils.lua b/mods/common/lua/utils.lua index eab8cbe6d7..15c376da1c 100644 --- a/mods/common/lua/utils.lua +++ b/mods/common/lua/utils.lua @@ -74,4 +74,13 @@ end Utils.TableToArray = function(luaTable) return Internal.TableToArray(luaTable) -end \ No newline at end of file +end + +Utils.Seconds = function(seconds) + local TicksPerSecond = 25 + return seconds * TicksPerSecond +end + +Utils.Minutes = function(minutes) + return Utils.Seconds(minutes * 60) +end diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index 3615116d7e..2173f2b60a 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -161,3 +161,4 @@ LuaScripts: mods/common/lua/reinforcements.lua mods/common/lua/supportpowers.lua mods/common/lua/rules.lua + mods/common/lua/production.lua diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index 99105ce6fe..acf490c4e3 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -177,3 +177,4 @@ LuaScripts: mods/common/lua/reinforcements.lua mods/common/lua/supportpowers.lua mods/common/lua/rules.lua + mods/common/lua/production.lua diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml index 09bc97b964..6d339fdc35 100644 --- a/mods/ts/mod.yaml +++ b/mods/ts/mod.yaml @@ -199,3 +199,4 @@ LuaScripts: mods/common/lua/reinforcements.lua mods/common/lua/supportpowers.lua mods/common/lua/rules.lua + mods/common/lua/production.lua