Merge pull request #6762 from obrakmann/lua-production

Add production support to Lua API, port gdi04a, gdi04b and intervention missions
This commit is contained in:
Matthias Mailänder
2014-10-18 20:56:24 +02:00
19 changed files with 1008 additions and 533 deletions

View File

@@ -515,7 +515,7 @@
<Compile Include="Warheads\PerCellDamageWarhead.cs" />
<Compile Include="Warheads\SpreadDamageWarhead.cs" />
<Compile Include="Scripting\Global\ReinforcementsGlobal.cs" />
<Compile Include="Scripting\Global\DateGlobal.cs" />
<Compile Include="Scripting\Global\DateTimeGlobal.cs" />
<Compile Include="Scripting\Properties\HarvesterProperties.cs" />
<Compile Include="Scripting\Properties\HelicopterProperties.cs" />
<Compile Include="Scripting\Properties\PlaneProperties.cs" />
@@ -586,4 +586,4 @@ copy "FuzzyLogicLibrary.dll" "$(SolutionDir)"
cd "$(SolutionDir)"</PostBuildEvent>
</PropertyGroup>
<ItemGroup />
</Project>
</Project>

View File

@@ -16,7 +16,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
[Desc("Attach this to the world actor (not a building!) to define a new shared build queue.",
[Desc("Attach this to the player actor (not a building!) to define a new shared build queue.",
"Will only work together with the Production: trait on the actor that actually does the production.",
"You will also want to add PrimaryBuildings: to let the user choose where new units should exit.")]
public class ClassicProductionQueueInfo : ProductionQueueInfo, Requires<TechTreeInfo>, Requires<PowerManagerInfo>, Requires<PlayerResourcesInfo>

View File

@@ -17,7 +17,8 @@ namespace OpenRA.Mods.RA.Scripting
[ScriptGlobal("Date")]
public class DateGlobal : ScriptGlobal
{
public DateGlobal(ScriptContext context) : base(context) { }
public DateGlobal(ScriptContext context)
: base(context) { }
[Desc("True on the 31st of October.")]
public bool IsHalloween
@@ -25,4 +26,17 @@ namespace OpenRA.Mods.RA.Scripting
get { return DateTime.Today.Month == 10 && DateTime.Today.Day == 31; }
}
}
[ScriptGlobal("Time")]
public class TimeGlobal : ScriptGlobal
{
public TimeGlobal(ScriptContext context)
: base(context) { }
[Desc("Get the current game time (in ticks)")]
public int GameTime
{
get { return context.World.WorldTick; }
}
}
}

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Mods.RA.Scripting
{
public TriggerGlobal(ScriptContext context) : base(context) { }
static ScriptTriggers GetScriptTriggers(Actor a)
public static ScriptTriggers GetScriptTriggers(Actor a)
{
var events = a.TraitOrDefault<ScriptTriggers>();
if (events == null)

View File

@@ -8,6 +8,9 @@
*/
#endregion
using Eluant;
using System;
using System.Linq;
using OpenRA.Mods.RA.Activities;
using OpenRA.Scripting;
using OpenRA.Traits;
@@ -17,8 +20,13 @@ namespace OpenRA.Mods.RA.Scripting
[ScriptPropertyGroup("Combat")]
public class CombatProperties : ScriptActorProperties, Requires<AttackBaseInfo>, Requires<IMoveInfo>
{
readonly IMove move;
public CombatProperties(ScriptContext context, Actor self)
: base(context, self) { }
: base(context, self)
{
move = self.Trait<IMove>();
}
[ScriptActorPropertyActivity]
[Desc("Seek out and attack nearby targets.")]
@@ -33,11 +41,35 @@ namespace OpenRA.Mods.RA.Scripting
"close enough to complete the activity.")]
public void AttackMove(CPos cell, int closeEnough = 0)
{
var move = self.TraitOrDefault<IMove>();
if (move == null)
return;
self.QueueActivity(new AttackMove.AttackMoveActivity(self, move.MoveTo(cell, closeEnough)));
}
[ScriptActorPropertyActivity]
[Desc("Patrol along a set of given waypoints. The action is repeated by default, " +
"and the actor will wait for `wait` ticks at each waypoint.")]
public void Patrol(CPos[] waypoints, bool loop = true, int wait = 0)
{
foreach (var wpt in waypoints)
{
self.QueueActivity(new AttackMove.AttackMoveActivity(self, move.MoveTo(wpt, 2)));
self.QueueActivity(new Wait(wait));
}
if (loop)
self.QueueActivity(new CallFunc(() => Patrol(waypoints, loop, wait)));
}
[ScriptActorPropertyActivity]
[Desc("Patrol along a set of given waypoints until a condition becomes true. " +
"The actor will wait for `wait` ticks at each waypoint.")]
public void PatrolUntil(CPos[] waypoints, LuaFunction func, int wait = 0)
{
Patrol(waypoints, false, wait);
var repeat = func.Call(self.ToLuaValue(context)).First().ToBoolean();
if (repeat)
using (var f = func.CopyReference() as LuaFunction)
self.QueueActivity(new CallFunc(() => PatrolUntil(waypoints, f, wait)));
}
}
}

View File

@@ -8,6 +8,7 @@
*/
#endregion
using OpenRA.Mods.RA.Buildings;
using OpenRA.Scripting;
using OpenRA.Traits;
@@ -33,4 +34,34 @@ namespace OpenRA.Mods.RA.Scripting
[Desc("Maximum health of the actor.")]
public int MaxHealth { get { return health.MaxHP; } }
}
[ScriptPropertyGroup("General")]
public class RepairableBuildingProperties : ScriptActorProperties, Requires<RepairableBuildingInfo>
{
readonly RepairableBuilding rb;
public RepairableBuildingProperties(ScriptContext context, Actor self)
: base(context, self)
{
rb = self.Trait<RepairableBuilding>();
}
[Desc("Start repairs on this building. `repairer` can be an allied player.")]
public void StartBuildingRepairs(Player repairer = null)
{
repairer = repairer ?? self.Owner;
if (!rb.Repairers.Contains(repairer))
rb.RepairBuilding(self, repairer);
}
[Desc("Stop repairs on this building. `repairer` can be an allied player.")]
public void StopBuildingRepairs(Player repairer = null)
{
repairer = repairer ?? self.Owner;
if (rb.RepairActive && rb.Repairers.Contains(repairer))
rb.RepairBuilding(self, repairer);
}
}
}

View File

@@ -27,4 +27,17 @@ namespace OpenRA.Mods.RA.Scripting
self.QueueActivity(new Fly(self, Target.FromCell(self.World, cell)));
}
}
[ScriptPropertyGroup("Combat")]
public class PlaneCombatProperties : ScriptActorProperties, Requires<AttackPlaneInfo>
{
public PlaneCombatProperties(ScriptContext context, Actor self)
: base(context, self) { }
[Desc("Fly an attack against the target actor.")]
public void Attack(Actor target)
{
self.QueueActivity(new FlyAttack(Target.FromActor(target)));
}
}
}

View File

@@ -9,6 +9,10 @@
#endregion
using Eluant;
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.Common;
using OpenRA.Mods.RA.Activities;
using OpenRA.Scripting;
using OpenRA.Traits;
@@ -37,4 +41,234 @@ namespace OpenRA.Mods.RA.Scripting
self.QueueActivity(new WaitFor(() => p.Produce(self, actorInfo, raceVariant)));
}
}
[ScriptPropertyGroup("Production")]
public class RallyPointProperties : ScriptActorProperties, Requires<RallyPointInfo>
{
readonly RallyPoint rp;
public RallyPointProperties(ScriptContext context, Actor self)
: base(context, self)
{
rp = self.Trait<RallyPoint>();
}
[Desc("Query or set a factory's rally point")]
public CPos RallyPoint
{
get { return rp.Location; }
set { rp.Location = value; }
}
}
[ScriptPropertyGroup("Production")]
public class PrimaryBuildingProperties : ScriptActorProperties, Requires<PrimaryBuildingInfo>
{
readonly PrimaryBuilding pb;
public PrimaryBuildingProperties(ScriptContext context, Actor self)
: base(context, self)
{
pb = self.Trait<PrimaryBuilding>();
}
[Desc("Query or set the factory's primary building status")]
public bool IsPrimaryBuilding
{
get { return pb.IsPrimary; }
set { pb.SetPrimaryProducer(self, value); }
}
}
[ScriptPropertyGroup("Production")]
public class ProductionQueueProperties : ScriptActorProperties, Requires<ProductionQueueInfo>, Requires<ScriptTriggersInfo>
{
readonly List<ProductionQueue> queues;
readonly ScriptTriggers triggers;
public ProductionQueueProperties(ScriptContext context, Actor self)
: base(context, self)
{
queues = self.TraitsImplementing<ProductionQueue>().Where(q => q.Enabled).ToList();
triggers = TriggerGlobal.GetScriptTriggers(self);
}
[Desc("Build the specified set of actors using a TD-style (per building) production queue. " +
"The function will return true if production could be started, false otherwise. " +
"If an actionFunc is given, it will be called as actionFunc(Actor[] actors) once " +
"production of all actors has been completed. The actors array is guaranteed to " +
"only contain alive actors.")]
public bool Build(string[] actorTypes, LuaFunction actionFunc = null)
{
if (triggers.Triggers[Trigger.OnProduction].Any())
return false;
var queue = queues.Where(q => actorTypes.All(t => GetBuildableInfo(t).Queue.Contains(q.Info.Type)))
.FirstOrDefault(q => q.CurrentItem() == null);
if (queue == null)
return false;
if (actionFunc != null)
{
var playerIndex = self.Owner.ClientIndex;
var squadSize = actorTypes.Length;
var squad = new List<Actor>();
var func = actionFunc.CopyReference() as LuaFunction;
Action<Actor, Actor> productionHandler = (_, __) => { };
productionHandler = (factory, unit) =>
{
if (playerIndex != factory.Owner.ClientIndex)
{
triggers.OnProducedInternal -= productionHandler;
return;
}
squad.Add(unit);
if (squad.Count >= squadSize)
{
using (func)
using (var luaSquad = squad.Where(u => !u.IsDead()).ToArray().ToLuaValue(context))
func.Call(luaSquad).Dispose();
triggers.OnProducedInternal -= productionHandler;
}
};
triggers.OnProducedInternal += productionHandler;
}
foreach (var actorType in actorTypes)
queue.ResolveOrder(self, Order.StartProduction(self, actorType, 1));
return true;
}
[Desc("Checks whether the factory is currently producing anything on the queue that produces this type of actor.")]
public bool IsProducing(string actorType)
{
if (triggers.Triggers[Trigger.OnProduction].Any())
return true;
return queues.Where(q => GetBuildableInfo(actorType).Queue.Contains(q.Info.Type))
.Any(q => q.CurrentItem() != null);
}
BuildableInfo GetBuildableInfo(string actorType)
{
var ri = self.World.Map.Rules.Actors[actorType];
var bi = ri.Traits.GetOrDefault<BuildableInfo>();
if (bi == null)
throw new LuaException("Actor of type {0} cannot be produced".F(actorType));
else
return bi;
}
}
[ScriptPropertyGroup("Production")]
public class ClassicProductionQueueProperties : ScriptPlayerProperties, Requires<ClassicProductionQueueInfo>, Requires<ScriptTriggersInfo>
{
readonly Dictionary<string, Action<Actor, Actor>> productionHandlers;
readonly Dictionary<string, ClassicProductionQueue> queues;
public ClassicProductionQueueProperties(ScriptContext context, Player player)
: base(context, player)
{
productionHandlers = new Dictionary<string, Action<Actor, Actor>>();
queues = new Dictionary<string, ClassicProductionQueue>();
foreach (var q in player.PlayerActor.TraitsImplementing<ClassicProductionQueue>().Where(q => q.Enabled))
queues.Add(q.Info.Type, q);
Action<Actor, Actor> globalProductionHandler = (factory, unit) =>
{
if (factory.Owner != player)
return;
var queue = GetBuildableInfo(unit.Info.Name).Queue.First();
if (productionHandlers.ContainsKey(queue))
productionHandlers[queue](factory, unit);
};
var triggers = TriggerGlobal.GetScriptTriggers(player.PlayerActor);
triggers.OnOtherProducedInternal += globalProductionHandler;
}
[Desc("Build the specified set of actors using classic (RA-style) production queues. " +
"The function will return true if production could be started, false otherwise. " +
"If an actionFunc is given, it will be called as actionFunc(Actor[] actors) once " +
"production of all actors has been completed. The actors array is guaranteed to " +
"only contain alive actors.")]
public bool Build(string[] actorTypes, LuaFunction actionFunc = null)
{
var typeToQueueMap = new Dictionary<string, string>();
foreach (var actorType in actorTypes.Distinct())
typeToQueueMap.Add(actorType, GetBuildableInfo(actorType).Queue.First());
var queueTypes = typeToQueueMap.Values.Distinct();
if (queueTypes.Any(t => !queues.ContainsKey(t) || productionHandlers.ContainsKey(t)))
return false;
if (queueTypes.Any(t => queues[t].CurrentItem() != null))
return false;
if (actionFunc != null)
{
var squadSize = actorTypes.Length;
var squad = new List<Actor>();
var func = actionFunc.CopyReference() as LuaFunction;
Action<Actor, Actor> productionHandler = (factory, unit) =>
{
squad.Add(unit);
if (squad.Count >= squadSize)
{
using (func)
using (var luaSquad = squad.Where(u => !u.IsDead()).ToArray().ToLuaValue(context))
func.Call(luaSquad).Dispose();
foreach (var q in queueTypes)
productionHandlers.Remove(q);
}
};
foreach (var q in queueTypes)
productionHandlers.Add(q, productionHandler);
}
foreach (var actorType in actorTypes)
{
var queue = queues[typeToQueueMap[actorType]];
queue.ResolveOrder(queue.Actor, Order.StartProduction(queue.Actor, actorType, 1));
}
return true;
}
[Desc("Checks whether the player is currently producing anything on the queue that produces this type of actor.")]
public bool IsProducing(string actorType)
{
var queue = GetBuildableInfo(actorType).Queue.First();
if (!queues.ContainsKey(queue))
return true;
return productionHandlers.ContainsKey(queue) || queues[queue].CurrentItem() != null;
}
BuildableInfo GetBuildableInfo(string actorType)
{
var ri = player.World.Map.Rules.Actors[actorType];
var bi = ri.Traits.GetOrDefault<BuildableInfo>();
if (bi == null)
throw new LuaException("Actor of type {0} cannot be produced".F(actorType));
else
return bi;
}
}
}

View File

@@ -18,22 +18,31 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA.Scripting
{
public enum Trigger { OnIdle, OnDamaged, OnKilled, OnProduction, OnPlayerWon, OnPlayerLost, OnObjectiveAdded,
OnObjectiveCompleted, OnObjectiveFailed, OnCapture, OnAddedToWorld, OnRemovedFromWorld };
public enum Trigger { OnIdle, OnDamaged, OnKilled, OnProduction, OnOtherProduction, OnPlayerWon, OnPlayerLost,
OnObjectiveAdded, OnObjectiveCompleted, OnObjectiveFailed, OnCapture, OnAddedToWorld, OnRemovedFromWorld };
[Desc("Allows map scripts to attach triggers to this actor via the Triggers global.")]
public class ScriptTriggersInfo : TraitInfo<ScriptTriggers> { }
public sealed class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction, INotifyObjectivesUpdated, INotifyCapture, INotifyAddedToWorld, INotifyRemovedFromWorld, IDisposable
public class ScriptTriggersInfo : ITraitInfo
{
public object Create(ActorInitializer init) { return new ScriptTriggers(init.world); }
}
public sealed class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction, INotifyOtherProduction, INotifyObjectivesUpdated, INotifyCapture, INotifyAddedToWorld, INotifyRemovedFromWorld, IDisposable
{
readonly World world;
public event Action<Actor> OnKilledInternal = _ => { };
public event Action<Actor> OnRemovedInternal = _ => { };
public event Action<Actor, Actor> OnProducedInternal = (a, b) => { };
public event Action<Actor, Actor> OnOtherProducedInternal = (a, b) => { };
public Dictionary<Trigger, List<Pair<LuaFunction, ScriptContext>>> Triggers = new Dictionary<Trigger, List<Pair<LuaFunction, ScriptContext>>>();
public ScriptTriggers()
public ScriptTriggers(World world)
{
foreach (var t in Enum.GetValues(typeof(Trigger)).Cast<Trigger>())
this.world = world;
foreach (Trigger t in Enum.GetValues(typeof(Trigger)))
Triggers.Add(t, new List<Pair<LuaFunction, ScriptContext>>());
}
@@ -101,6 +110,7 @@ namespace OpenRA.Mods.RA.Scripting
public void UnitProduced(Actor self, Actor other, CPos exit)
{
// Run Lua callbacks
foreach (var f in Triggers[Trigger.OnProduction])
{
try
@@ -115,6 +125,9 @@ namespace OpenRA.Mods.RA.Scripting
return;
}
}
// Run any internally bound callbacks
OnProducedInternal(self, other);
}
public void OnPlayerWon(Player player)
@@ -263,22 +276,46 @@ namespace OpenRA.Mods.RA.Scripting
OnRemovedInternal(self);
}
public void UnitProducedByOther(Actor self, Actor producee, Actor produced)
{
// Run Lua callbacks
foreach (var f in Triggers[Trigger.OnOtherProduction])
{
try
{
using (var a = producee.ToLuaValue(f.Second))
using (var b = produced.ToLuaValue(f.Second))
f.First.Call(a, b).Dispose();
}
catch (Exception ex)
{
f.Second.FatalError(ex.Message);
return;
}
}
// Run any internally bound callbacks
OnOtherProducedInternal(producee, produced);
}
public void Clear(Trigger trigger)
{
Triggers[trigger].Clear();
world.AddFrameEndTask(w =>
{
Triggers[trigger].Select(p => p.First).Do(f => f.Dispose());
Triggers[trigger].Clear();
});
}
public void ClearAll()
{
foreach (var trigger in Triggers)
trigger.Value.Clear();
foreach (Trigger t in Enum.GetValues(typeof(Trigger)))
Clear(t);
}
public void Dispose()
{
var pairs = Triggers.Values;
pairs.SelectMany(l => l).Select(p => p.First).Do(f => f.Dispose());
pairs.Do(l => l.Clear());
ClearAll();
}
}
}

View File

@@ -62,6 +62,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Red Alert Lua scripts", "Re
mods\ra\maps\allies-01-classic\allies01.lua = mods\ra\maps\allies-01-classic\allies01.lua
mods\ra\maps\allies-02-classic\allies02.lua = mods\ra\maps\allies-02-classic\allies02.lua
mods\ra\maps\desert-shellmap\desert-shellmap.lua = mods\ra\maps\desert-shellmap\desert-shellmap.lua
mods\ra\maps\intervention\intervention.lua = mods\ra\maps\intervention\intervention.lua
mods\ra\maps\fort-lonestar\fort-lonestar.lua = mods\ra\maps\fort-lonestar\fort-lonestar.lua
EndProjectSection
EndProject

View File

@@ -1,137 +1,166 @@
Nod1Template = { {HandOfNod, {"e1", "e1", "e3", "e3"}} }
Auto1Template = { {HandOfNod, {"e1", "e1", "e3"}} }
AutoTrigger = { CPos.New(51, 47), CPos.New(52, 47), CPos.New(53, 47), CPos.New(54, 47) }
GDIHeliTrigger = { CPos.New(27, 55), CPos.New(27, 56), CPos.New(28, 56), CPos.New(28, 57), CPos.New(28, 58), CPos.New(28, 59)}
Nod1Units = { "e1", "e1", "e3", "e3" }
Auto1Units = { "e1", "e1", "e3" }
KillsUntilReinforcements = 12
HeliDelay = {83, 137, 211}
HeliDelay = { 83, 137, 211 }
GDIReinforcements = {"e2", "e2", "e2", "e2"}
GDIReinforcementsWaypoints = {GDIReinforcementsEntry, GDIReinforcementsWP1}
GDIReinforcements = { "e2", "e2", "e2", "e2", "e2" }
GDIReinforcementsWaypoints = { GDIReinforcementsEntry.Location, GDIReinforcementsWP1.Location }
NodHelis = {
{Utils.Seconds(HeliDelay[1]), {NodHeliEntry, NodHeliLZ1}, {"e1", "e1", "e3"}},
{Utils.Seconds(HeliDelay[2]), {NodHeliEntry, NodHeliLZ2}, {"e1", "e1", "e1", "e1"}},
{Utils.Seconds(HeliDelay[3]), {NodHeliEntry, NodHeliLZ3}, {"e1", "e1", "e3"}}
{ Utils.Seconds(HeliDelay[1]), { NodHeliEntry.Location, NodHeliLZ1.Location }, { "e1", "e1", "e3" } },
{ Utils.Seconds(HeliDelay[2]), { NodHeliEntry.Location, NodHeliLZ2.Location }, { "e1", "e1", "e1", "e1" } },
{ Utils.Seconds(HeliDelay[3]), { NodHeliEntry.Location, NodHeliLZ3.Location }, { "e1", "e1", "e3" } }
}
SendHeli = function(heli, func)
Reinforcements.ReinforceWithCargo(nod, "tran", heli[2], heli[3], func)
OpenRA.RunAfterDelay(heli[1], function() SendHeli(heli, func) end)
end
HeliAction = function(heliActor, team)
Actor.AfterMove(heliActor)
Actor.UnloadCargo(heliActor, true)
Actor.Wait(heliActor, Utils.Seconds(2))
Actor.ScriptedMove(heliActor, NodHeliEntry.Location)
Actor.RemoveSelf(heliActor)
Team.Do(team, function(actor)
Actor.Hunt(actor)
Actor.OnIdle(actor, Actor.Hunt)
Actor.OnKilled(actor, KillCounter)
SendHeli = function(heli)
units = Reinforcements.ReinforceWithTransport(nod, "tran", heli[3], heli[2], { heli[2][1] })
Utils.Do(units[2], function(actor)
actor.Hunt()
Trigger.OnIdle(actor, actor.Hunt)
Trigger.OnKilled(actor, KillCounter)
end)
Trigger.AfterDelay(heli[1], function() SendHeli(heli) end)
end
SendGDIReinforcements = function()
Reinforcements.ReinforceWithCargo(player, "apc", GDIReinforcementsWaypoints, GDIReinforcements, function(apc, team)
Team.Add(team, apc)
Actor.OnKilled(apc, SendGDIReinforcements)
Team.Do(team, function(unit) Actor.SetStance(unit, "Defend") end)
Media.PlaySpeechNotification(gdi, "Reinforce")
Reinforcements.ReinforceWithTransport(gdi, "apc", GDIReinforcements, GDIReinforcementsWaypoints, nil, function(apc, team)
table.insert(team, apc)
Trigger.OnAllKilled(team, function() Trigger.AfterDelay(Utils.Seconds(5), SendGDIReinforcements) end)
Utils.Do(team, function(unit) unit.Stance = "Defend" end)
end)
end
BuildNod1 = function()
Production.BuildTeamFromTemplate(nod, Nod1Template, function(team)
Team.Do(team, function(actor)
Actor.OnIdle(actor, Actor.Hunt)
Actor.OnKilled(actor, KillCounter)
if HandOfNod.IsDead then
return
end
local func = function(team)
Utils.Do(team, function(actor)
Trigger.OnIdle(actor, actor.Hunt)
Trigger.OnKilled(actor, KillCounter)
end)
Team.AddEventHandler(team.OnAllKilled, BuildNod1)
end)
Trigger.OnAllKilled(team, BuildNod1)
end
if not HandOfNod.Build(Nod1Units, func) then
Trigger.AfterDelay(Utils.Seconds(5), BuildNod1)
end
end
BuildAuto1 = function()
Production.BuildTeamFromTemplate(nod, Auto1Template, function(team)
Team.Do(team, function(actor)
Actor.OnIdle(actor, Actor.Hunt)
Actor.OnKilled(actor, KillCounter)
if HandOfNod.IsDead then
return
end
local func = function(team)
Utils.Do(team, function(actor)
Trigger.OnIdle(actor, actor.Hunt)
Trigger.OnKilled(actor, KillCounter)
end)
end)
end
if not HandOfNod.IsDead and HandOfNod.Build(Auto1Units, func) then
Trigger.AfterDelay(Utils.Seconds(5), BuildAuto1)
end
end
kills = 0
KillCounter = function() kills = kills + 1 end
Auto1Triggered = false
GDIHeliTriggered = false
ReinforcementsSent = false
Tick = function()
nod.Cash = 1000
if not ReinforcementsSent and kills >= KillsUntilReinforcements then
ReinforcementsSent = true
gdi.MarkCompletedObjective(reinforcementsObjective)
SendGDIReinforcements()
end
if Mission.RequiredUnitsAreDestroyed(player) then
OpenRA.RunAfterDelay(Utils.Seconds(1), MissionFailed)
end
if not Auto1Triggered then
-- FIXME: replace with cell trigger when available
local units = Map.FindUnitsInCircle(player, Auto1Trigger, 2)
if #units > 0 then
Auto1Triggered = true
BuildAuto1()
end
elseif not GDIHeliTriggered then
-- FIXME: replace with cell trigger when available
local units = Map.FindUnitsInCircle(player, GDIHeliLZ, 2)
if #units > 0 then
GDIHeliTriggered = true
Reinforcements.ReinforceWithCargo(player, "tran", {GDIHeliEntry, GDIHeliLZ}, nil, Actor.AfterMove)
end
if gdi.HasNoRequiredUnits() then
Trigger.AfterDelay(Utils.Seconds(1), function() gdi.MarkFailedObjective(gdiObjective) end)
end
end
SetupWorld = function()
OpenRA.GiveCash(nod, 10000)
Production.EventHandlers.Setup(nod)
Utils.Do(Mission.GetGroundAttackersOf(nod), function(unit)
Actor.OnKilled(unit, KillCounter)
Utils.Do(nod.GetGroundAttackers(nod), function(unit)
Trigger.OnKilled(unit, KillCounter)
end)
Utils.Do(Mission.GetGroundAttackersOf(player), function(unit)
Actor.SetStance(unit, "Defend")
Utils.Do(gdi.GetGroundAttackers(), function(unit)
unit.Stance = "Defend"
end)
Actor.Hunt(Hunter1)
Actor.Hunt(Hunter2)
Hunter1.Hunt()
Hunter2.Hunt()
Actor.OnRemovedFromWorld(crate, MissionAccomplished)
Trigger.OnRemovedFromWorld(crate, function() gdi.MarkCompletedObjective(gdiObjective) end)
end
WorldLoaded = function()
Media.PlayMovieFullscreen("bkground.vqa", function() Media.PlayMovieFullscreen("nitejump.vqa") end)
player = OpenRA.GetPlayer("GDI")
nod = OpenRA.GetPlayer("Nod")
gdi = Player.GetPlayer("GDI")
nod = Player.GetPlayer("Nod")
SetupWorld()
OpenRA.RunAfterDelay(1, BuildNod1)
Utils.Do(NodHelis, function(heli)
OpenRA.RunAfterDelay(heli[1], function() SendHeli(heli, HeliAction) end)
Trigger.OnObjectiveAdded(gdi, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
end)
Trigger.OnObjectiveCompleted(gdi, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed")
end)
Trigger.OnObjectiveFailed(gdi, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed")
end)
OpenRA.SetViewportCenterPosition(Actor56.CenterPosition)
end
Trigger.OnPlayerWon(gdi, function()
Media.PlaySpeechNotification(gdi, "Win")
Trigger.AfterDelay(Utils.Seconds(1), function()
Media.PlayMovieFullscreen("burdet1.vqa")
end)
end)
MissionAccomplished = function()
Mission.MissionOver({ player }, nil, true)
Media.PlayMovieFullscreen("burdet1.vqa")
end
Trigger.OnPlayerLost(gdi, function()
Media.PlaySpeechNotification(gdi, "Lose")
Trigger.AfterDelay(Utils.Seconds(1), function()
Media.PlayMovieFullscreen("gameover.vqa")
end)
end)
MissionFailed = function()
Mission.MissionOver(nil, { player }, true)
Media.PlayMovieFullscreen("gameover.vqa")
gdiObjective = gdi.AddPrimaryObjective("Retrieve the crate with the stolen rods.")
reinforcementsObjective = gdi.AddSecondaryObjective("Eliminate " .. KillsUntilReinforcements .. " Nod units for reinforcements.")
nod.AddPrimaryObjective("Defend against the GDI forces.")
BuildNod1()
Utils.Do(NodHelis, function(heli)
Trigger.AfterDelay(heli[1], function() SendHeli(heli) end)
end)
autoTrigger = false
Trigger.OnEnteredFootprint(AutoTrigger, function(a, id)
if not autoTrigger and a.Owner == gdi then
autoTrigger = true
Trigger.RemoveFootprintTrigger(id)
BuildAuto1()
end
end)
gdiHeliTrigger = false
Trigger.OnEnteredFootprint(GDIHeliTrigger, function(a, id)
if not gdiHeliTrigger and a.Owner == gdi then
gdiHeliTrigger = true
Trigger.RemoveFootprintTrigger(id)
Reinforcements.ReinforceWithTransport(gdi, "tran", nil, { GDIHeliEntry.Location, GDIHeliLZ.Location })
end
end)
Camera.Position = Actor56.CenterPosition
Media.PlayMovieFullscreen("bkground.vqa", function() Media.PlayMovieFullscreen("nitejump.vqa") end)
end

View File

@@ -326,6 +326,12 @@ Actors:
Health: 1
Facing: 0
SubCell: 3
Actor710: e1
Location: 12,54
Owner: GDI
Health: 1
Facing: 0
SubCell: 5
Actor71: e1
Location: 12,54
Owner: GDI
@@ -416,6 +422,12 @@ Actors:
Health: 1
Facing: 64
SubCell: 4
Actor860: e2
Location: 14,54
Owner: GDI
Health: 1
Facing: 0
SubCell: 5
Actor86: e2
Location: 14,54
Owner: GDI
@@ -524,9 +536,6 @@ Actors:
GDIReinforcementsEntry: waypoint
Location: 7,50
Owner: Neutral
Auto1Trigger: waypoint
Location: 52,47
Owner: Neutral
NodHeliEntry: waypoint
Location: 41,23
Owner: Neutral
@@ -547,8 +556,8 @@ Rules:
-SpawnMPUnits:
-MPStartLocations:
-CrateSpawner:
LuaScriptInterface:
LuaScripts: gdi04a.lua
LuaScript:
Scripts: gdi04a.lua
ObjectivesPanel:
PanelName: MISSION_OBJECTIVES
Player:
@@ -595,18 +604,16 @@ Rules:
GenericVisibility: Enemy, Ally, Neutral
GenericStancePrefix: false
ShowOwnerRow: false
HARV:
-MustBeDestroyed:
CRATE:
Crate:
Lifetime: 9999
LuaScriptEvents:
HealUnitsCrateAction:
-RevealMapCrateAction:
-GiveMcvCrateAction:
-GiveCashCrateAction:
-ExplodeCrateAction@fire:
-GrantUpgradeCrateAction@cloak:
-DuplicateUnitCrateAction:
ScriptTriggers:
Sequences:
@@ -615,7 +622,7 @@ VoxelSequences:
Weapons:
Tiberium:
Warhead: SpreadDamage
Warhead@1Dam: SpreadDamage
Damage: 6
Voices:

View File

@@ -1,172 +1,198 @@
NodxTemplate = { {HandOfNod, {"e1", "e1", "e3", "e3"}} }
AutoTemplate = { {HandOfNod, {"e1", "e1", "e1", "e3", "e3"}} }
BhndTrigger = { CPos.New(39, 21), CPos.New(40, 21), CPos.New(41, 21) }
Atk1Trigger = { CPos.New(35, 37) }
Atk2Trigger = { CPos.New(9, 44), CPos.New(10, 44), CPos.New(11, 44), CPos.New(12, 44), CPos.New(13, 44) }
AutoTrigger = { CPos.New(5, 30), CPos.New(6, 30), CPos.New(7, 30), CPos.New(8, 30), CPos.New(9, 30), CPos.New(10, 30), CPos.New(11, 30), CPos.New(12, 30), CPos.New(13, 30) }
GDIHeliTrigger = { CPos.New(11, 11), CPos.New(11, 12), CPos.New(11, 13), CPos.New(11, 14), CPos.New(11, 15), CPos.New(12, 15), CPos.New(13, 15), CPos.New(14, 15), CPos.New(15, 15), CPos.New(16, 15) }
Hunters = { Hunter1, Hunter2, Hunter3, Hunter4, Hunter5 }
NodxUnits = { "e1", "e1", "e3", "e3" }
AutoUnits = { "e1", "e1", "e1", "e3", "e3" }
KillsUntilReinforcements = 12
kills = 0
KillCounter = function() kills = kills + 1 end
GDIReinforcements = {"e2", "e2", "e2", "e2"}
GDIReinforcementsWaypoints = {GDIReinforcementsEntry, GDIReinforcementsWP1}
GDIReinforcements = { "e2", "e2", "e2", "e2", "e2" }
GDIReinforcementsWaypoints = { GDIReinforcementsEntry.Location, GDIReinforcementsWP1.Location }
NodHeli = {{HeliEntry, NodHeliLZ}, {"e1", "e1", "e3", "e3"}}
NodHeli = { { HeliEntry.Location, NodHeliLZ.Location }, { "e1", "e1", "e3", "e3" } }
SendHeli = function(heli, func)
Reinforcements.ReinforceWithCargo(nod, "tran", heli[1], heli[2], func)
end
HeliAction = function(heliActor, team)
Actor.AfterMove(heliActor)
Actor.UnloadCargo(heliActor, true)
Actor.Wait(heliActor, Utils.Seconds(2))
Actor.ScriptedMove(heliActor, HeliEntry.Location)
Actor.RemoveSelf(heliActor)
Team.Do(team, function(actor)
Actor.Hunt(actor)
Actor.OnIdle(actor, Actor.Hunt)
Actor.OnKilled(actor, KillCounter)
SendHeli = function(heli)
units = Reinforcements.ReinforceWithTransport(nod, "tran", heli[2], heli[1], { heli[1][1] })
Utils.Do(units[2], function(actor)
actor.Hunt()
Trigger.OnIdle(actor, actor.Hunt)
Trigger.OnKilled(actor, KillCounter)
end)
end
SendGDIReinforcements = function()
Reinforcements.ReinforceWithCargo(player, "apc", GDIReinforcementsWaypoints, GDIReinforcements, function(apc, team)
Team.Add(team, apc)
Actor.OnKilled(apc, SendGDIReinforcements)
Team.Do(team, function(unit) Actor.SetStance(unit, "Defend") end)
Media.PlaySpeechNotification(gdi, "Reinforce")
Reinforcements.ReinforceWithTransport(gdi, "apc", GDIReinforcements, GDIReinforcementsWaypoints, nil, function(apc, team)
table.insert(team, apc)
Trigger.OnAllKilled(team, function() Trigger.AfterDelay(Utils.Seconds(5), SendGDIReinforcements) end)
Utils.Do(team, function(unit) unit.Stance = "Defend" end)
end)
end
Build = function(template, repeats, func)
Production.BuildTeamFromTemplate(nod, template, function(team)
Team.Do(team, func)
Build = function(unitTypes, repeats, func)
if HandOfNod.IsDead then
return
end
local innerFunc = function(units)
Utils.Do(units, func)
if repeats then
Team.AddEventHandler(team.OnAllKilled, function()
Build(template, repeats, func)
Trigger.OnAllKilled(units, function()
Build(unitTypes, repeats, func)
end)
end
end)
end
if not HandOfNod.Build(unitTypes, innerFunc) then
Trigger.AfterDelay(Utils.Seconds(5), function()
Build(unitTypes, repeats, func)
end)
end
end
BuildNod1 = function()
Build(NodxTemplate, false, function(actor)
Actor.OnKilled(actor, KillCounter)
Actor.Patrol(actor, {waypoint1, waypoint2, waypoint3, waypoint4}, 0, false)
Actor.OnIdle(actor, Actor.Hunt)
Build(NodxUnits, false, function(actor)
Trigger.OnKilled(actor, KillCounter)
actor.Patrol({ waypoint1.Location, waypoint2.Location, waypoint3.Location, waypoint4.Location }, false)
Trigger.OnIdle(actor, actor.Hunt)
end)
end
BuildNod2 = function()
Build(NodxTemplate, false, function(actor)
Actor.OnKilled(actor, KillCounter)
Actor.Patrol(actor, {waypoint1, waypoint2}, 0, false)
Actor.OnIdle(actor, Actor.Hunt)
Build(NodxUnits, false, function(actor)
Trigger.OnKilled(actor, KillCounter)
actor.Patrol({ waypoint1.Location, waypoint2.Location }, false)
Trigger.OnIdle(actor, actor.Hunt)
end)
end
BuildAuto = function()
Build(AutoTemplate, true, function(actor)
Actor.OnKilled(actor, KillCounter)
Actor.OnIdle(actor, Actor.Hunt)
Build(AutoUnits, true, function(actor)
Trigger.OnKilled(actor, KillCounter)
Trigger.OnIdle(actor, actor.Hunt)
end)
end
-- FIXME: replace with real cell trigger when available
CellTrigger = function(player, trigger, radius, func)
local units = Map.FindUnitsInCircle(player, trigger, radius)
if #units > 0 then
func()
end
end
BhndTriggered = false
Atk1Triggered = false
Atk2Triggered = false
AutoTriggered = false
GDIHeliTriggered = false
ReinforcementsSent = false
kills = 0
KillCounter = function() kills = kills + 1 end
Tick = function()
nod.Cash = 1000
if not ReinforcementsSent and kills >= KillsUntilReinforcements then
ReinforcementsSent = true
gdi.MarkCompletedObjective(reinforcementsObjective)
SendGDIReinforcements()
end
if Mission.RequiredUnitsAreDestroyed(player) then
OpenRA.RunAfterDelay(Utils.Seconds(1), MissionFailed)
end
if not BhndTriggered then
CellTrigger(player, BhndTrigger, 2, function()
BhndTriggered = true
SendHeli(NodHeli, HeliAction)
end)
end
if not Atk1Triggered then
CellTrigger(player, Atk1Trigger, 2, function()
Atk1Triggered = true
BuildNod1()
end)
elseif not Atk2Triggered then
CellTrigger(player, Atk2Trigger, 2, function()
Atk2Triggered = true
BuildNod2()
end)
elseif not AutoTriggered then
CellTrigger(player, AutoTrigger, 2, function()
AutoTriggered = true
BuildAuto()
OpenRA.RunAfterDelay(Utils.Seconds(5), function()
Actor.Hunt(tank)
end)
end)
elseif not GDIHeliTriggered then
CellTrigger(player, HeliTrigger, 2, function()
GDIHeliTriggered = true
Reinforcements.ReinforceWithCargo(player, "tran", {HeliEntry, GDIHeliLZ}, nil, Actor.AfterMove)
if gdi.HasNoRequiredUnits() then
Trigger.AfterDelay(Utils.Seconds(1), function()
gdi.MarkFailedObjective(gdiObjective)
end)
end
end
SetupWorld = function()
OpenRA.GiveCash(nod, 10000)
Production.EventHandlers.Setup(nod)
Utils.Do(Mission.GetGroundAttackersOf(nod), function(unit)
Actor.OnKilled(unit, KillCounter)
Utils.Do(nod.GetGroundAttackers(), function(unit)
Trigger.OnKilled(unit, KillCounter)
end)
Utils.Do(Mission.GetGroundAttackersOf(player), function(unit)
Actor.SetStance(unit, "Defend")
Utils.Do(gdi.GetGroundAttackers(), function(unit)
unit.Stance = "Defend"
end)
hunters1 = Team.New({Hunter1, Hunter2})
hunters2 = Team.New({Hunter3, Hunter4, Hunter5})
Utils.Do(Hunters, function(actor) actor.Hunt() end)
OpenRA.RunAfterDelay(1, function() Team.Do(hunters1, Actor.Hunt) end)
OpenRA.RunAfterDelay(1, function() Team.Do(hunters2, Actor.Hunt) end)
Actor.OnRemovedFromWorld(crate, MissionAccomplished)
Trigger.OnRemovedFromWorld(crate, function() gdi.MarkCompletedObjective(gdiObjective) end)
end
WorldLoaded = function()
Media.PlayMovieFullscreen("bkground.vqa", function() Media.PlayMovieFullscreen("nitejump.vqa") end)
gdi = Player.GetPlayer("GDI")
nod = Player.GetPlayer("Nod")
player = OpenRA.GetPlayer("GDI")
nod = OpenRA.GetPlayer("Nod")
Trigger.OnObjectiveAdded(gdi, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
end)
Trigger.OnObjectiveCompleted(gdi, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed")
end)
Trigger.OnObjectiveFailed(gdi, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed")
end)
Trigger.OnPlayerWon(gdi, function()
Media.PlaySpeechNotification(gdi, "Win")
Trigger.AfterDelay(Utils.Seconds(1), function()
Media.PlayMovieFullscreen("burdet1.vqa")
end)
end)
Trigger.OnPlayerLost(gdi, function()
Media.PlaySpeechNotification(gdi, "Lose")
Trigger.AfterDelay(Utils.Seconds(1), function()
Media.PlayMovieFullscreen("gameover.vqa")
end)
end)
gdiObjective = gdi.AddPrimaryObjective("Retrieve the crate with the stolen rods.")
reinforcementsObjective = gdi.AddSecondaryObjective("Eliminate " .. KillsUntilReinforcements .. " Nod units for reinforcements.")
nod.AddPrimaryObjective("Defend against the GDI forces.")
SetupWorld()
OpenRA.SetViewportCenterPosition(GDIReinforcementsWP1.CenterPosition)
end
bhndTrigger = false
Trigger.OnExitedFootprint(BhndTrigger, function(a, id)
if not bhndTrigger and a.Owner == gdi then
bhndTrigger = true
Trigger.RemoveFootprintTrigger(id)
SendHeli(NodHeli)
end
end)
MissionAccomplished = function()
Mission.MissionOver({ player }, nil, true)
Media.PlayMovieFullscreen("burdet1.vqa")
end
atk1Trigger = false
Trigger.OnExitedFootprint(Atk1Trigger, function(a, id)
if not atk1Trigger and a.Owner == gdi then
atk1Trigger = true
Trigger.RemoveFootprintTrigger(id)
BuildNod1()
end
end)
MissionFailed = function()
Mission.MissionOver(nil, { player }, true)
Media.PlayMovieFullscreen("gameover.vqa")
atk2Trigger = false
Trigger.OnEnteredFootprint(Atk2Trigger, function(a, id)
if not atk2Trigger and a.Owner == gdi then
atk2Trigger = true
Trigger.RemoveFootprintTrigger(id)
BuildNod2()
end
end)
autoTrigger = false
Trigger.OnEnteredFootprint(AutoTrigger, function(a, id)
if not autoTrigger and a.Owner == gdi then
autoTrigger = true
Trigger.RemoveFootprintTrigger(id)
BuildAuto()
Trigger.AfterDelay(Utils.Seconds(4), function()
tank.Hunt()
end)
end
end)
gdiHeliTrigger = false
Trigger.OnEnteredFootprint(GDIHeliTrigger, function(a, id)
if not gdiHeliTrigger and a.Owner == gdi then
gdiHeliTrigger = true
Trigger.RemoveFootprintTrigger(id)
Reinforcements.ReinforceWithTransport(gdi, "tran", nil, { HeliEntry.Location, GDIHeliLZ.Location })
end
end)
Camera.Position = GDIReinforcementsWP1.CenterPosition
Media.PlayMovieFullscreen("bkground.vqa", function() Media.PlayMovieFullscreen("nitejump.vqa") end)
end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -597,21 +597,6 @@ Actors:
crate: CRATE
Location: 14,13
Owner: Neutral
BhndTrigger: waypoint
Location: 40,21
Owner: Neutral
Atk1Trigger: waypoint
Location: 35,37
Owner: Neutral
Atk2Trigger: waypoint
Location: 11,44
Owner: Neutral
AutoTrigger: waypoint
Location: 12,30
Owner: Neutral
HeliTrigger: waypoint
Location: 13,15
Owner: Neutral
HeliEntry: waypoint
Location: 4,26
Owner: Neutral
@@ -626,8 +611,8 @@ Rules:
-SpawnMPUnits:
-MPStartLocations:
-CrateSpawner:
LuaScriptInterface:
LuaScripts: gdi04b.lua
LuaScript:
Scripts: gdi04b.lua
ObjectivesPanel:
PanelName: MISSION_OBJECTIVES
Player:
@@ -674,21 +659,20 @@ Rules:
GenericVisibility: Enemy, Ally, Neutral
GenericStancePrefix: false
ShowOwnerRow: false
HARV:
-MustBeDestroyed:
E3:
AutoTarget:
ScanRadius: 5
CRATE:
Crate:
Lifetime: 9999
LuaScriptEvents:
HealUnitsCrateAction:
-RevealMapCrateAction:
-GiveMcvCrateAction:
-GiveCashCrateAction:
-ExplodeCrateAction@fire:
-GrantUpgradeCrateAction@cloak:
-DuplicateUnitCrateAction:
ScriptTriggers:
Sequences:
@@ -696,7 +680,7 @@ VoxelSequences:
Weapons:
Tiberium:
Warhead: SpreadDamage
Warhead@1Dam: SpreadDamage
Damage: 4
Voices:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -0,0 +1,279 @@
BeachheadTrigger =
{
CPos.New(120, 90), CPos.New(120, 89), CPos.New(120, 88), CPos.New(121, 88), CPos.New(122, 88), CPos.New(123, 88), CPos.New(124, 88),
CPos.New(125, 88), CPos.New(126, 88), CPos.New(126, 89), CPos.New(127, 89), CPos.New(128, 89), CPos.New(128, 90), CPos.New(129, 90),
CPos.New(130, 90), CPos.New(130, 91), CPos.New(131, 91), CPos.New(132, 91), CPos.New(133, 91), CPos.New(134, 91), CPos.New(134, 92),
CPos.New(135, 92), CPos.New(136, 92), CPos.New(137, 92), CPos.New(137, 93), CPos.New(138, 93), CPos.New(139, 93), CPos.New(140, 93),
CPos.New(140, 94), CPos.New(140, 95), CPos.New(140, 96), CPos.New(140, 97), CPos.New(140, 98), CPos.New(140, 99), CPos.New(140, 100),
CPos.New(139, 100), CPos.New(139, 101), CPos.New(139, 102), CPos.New(138, 102), CPos.New(138, 103), CPos.New(138, 104),
CPos.New(137, 104), CPos.New(137, 105), CPos.New(137, 106), CPos.New(136, 106), CPos.New(136, 107)
}
BaseRaidInterval = Utils.Minutes(3)
BaseFrontAttackInterval = Utils.Minutes(3) + Utils.Seconds(30)
BaseRearAttackInterval = Utils.Minutes(8)
UBoatPatrolDelay = Utils.Minutes(2) + Utils.Seconds(30)
BaseFrontAttackWpts = { PatrolWpt1.Location, BaseRaidWpt1.Location }
Village = { FarmHouse1, FarmHouse2, FarmHouse3, FarmHouse4, FarmHouse5, FarmHouse6, FarmHouse7, FarmHouse8, FarmHouse9, Church }
VillageRaidInterval = Utils.Minutes(3)
VillageRaidAircraft = { "mig", "mig" }
VillageRaidWpts = { VillageRaidEntrypoint.Location, VillageRaidWpt1.Location, VillageRaidWpt2.Location }
BaseRaidAircraft = { "mig", "mig" }
BaseRaidWpts = { BaseRaidEntrypoint.Location, UboatPatrolWpt1.Location, BaseRaidWpt2.Location }
BaseFrontAttackUnits = { "e3", "e3", "e1", "e1", "e1", "3tnk", "3tnk", "apc" }
BaseRearAttackUnits = { "e3", "e3", "e1", "e1", "3tnk", "3tnk", "v2rl" }
BaseRearAttackWpts = { GroundAttackWpt1.Location, BaseRearAttackWpt1.Location, BaseRearAttackWpt2.Location, BaseRearAttackWpt3.Location }
SovietHarvesters = { Harvester1, Harvester2, Harvester3 }
HarvesterGuard = { HarvGuard1, HarvGuard2, HarvGuard3 }
UBoats = { Uboat1, Uboat2, Uboat3, Uboat4, Uboat5, Uboat6 }
UboatPatrolWpts1 = { UboatPatrolWpt1.Location, UboatPatrolWpt2.Location, UboatPatrolWpt3.Location, UboatPatrolWpt4.Location }
UboatPatrolWpts2 = { UboatPatrolWpt4.Location, UboatPatrolWpt2.Location, UboatPatrolWpt1.Location }
UBoatPatrolUnits = { "ss" }
HunterSubs = { "ss", "ss" }
GroundPatrolWpts = { PatrolWpt1.Location, PatrolWpt2.Location }
GroundPatrolUnits =
{
{ "e1", "e1", "e1", "e3", "e3", "dog" },
{ "apc", "apc", "ftrk" },
{ "3tnk", "3tnk" }
}
Paratroopers = { "e1", "e1", "e1", "e3", "e3" }
ParadropSovietUnits = function()
local start = BaseRaidEntrypoint.CenterPosition + WVec.New(0, 0, Actor.CruiseAltitude("badr"))
local transport = Actor.Create("badr", true, { CenterPosition = start, Owner = soviets, Facing = (Utils.CenterOfCell(MCVDeployLocation.Location) - start).Facing })
Utils.Do(Paratroopers, function(type)
local a = Actor.Create(type, false, { Owner = soviets })
transport.LoadPassenger(a)
Trigger.OnIdle(a, function(b) b.Hunt() end)
end)
transport.Paradrop(MCVDeployLocation.Location)
end
AirRaid = function(planeTypes, ingress, egress, target)
if target == nil then
return
end
for i = 1, #planeTypes do
Trigger.AfterDelay((i - 1) * Utils.Seconds(1), function()
local start = Utils.CenterOfCell(ingress[1]) + WVec.New(0, 0, Actor.CruiseAltitude(planeTypes[i]))
local plane = Actor.Create(planeTypes[i], true, { CenterPosition = start, Owner = soviets, Facing = (Utils.CenterOfCell(ingress[2]) - start).Facing })
Utils.Do(ingress, function(wpt) plane.Move(wpt) end)
plane.Attack(target)
Utils.Do(egress, function(wpt) plane.Move(wpt) end)
plane.Destroy()
end)
end
end
BaseRaid = function()
local targets = Map.ActorsInBox(AlliedAreaTopLeft.CenterPosition, AlliedAreaBottomRight.CenterPosition, function(actor)
return actor.Owner == player and actor.HasProperty("StartBuildingRepairs")
end)
if #targets == 0 then
return
end
local target = Utils.Random(targets)
AirRaid(BaseRaidAircraft, BaseRaidWpts, { VillageRaidEntrypoint.Location }, target)
Trigger.AfterDelay(BaseRaidInterval, BaseRaid)
end
VillageRaid = function()
local target = nil
Utils.Do(Village, function(tgt)
if target == nil and not tgt.IsDead then
target = tgt
return
end
end)
if target == nil then
return
end
AirRaid(VillageRaidAircraft, VillageRaidWpts, { BaseRaidEntrypoint.Location }, target)
Trigger.AfterDelay(VillageRaidInterval, VillageRaid)
end
SendUboatPatrol = function(team)
Trigger.AfterDelay(UBoatPatrolDelay, function()
Utils.Do(team, function(uboat)
if not uboat.IsDead then
uboat.PatrolUntil(UboatPatrolWpts1, function()
return Time.GameTime > Utils.Minutes(2) + UBoatPatrolDelay
end)
uboat.Patrol(UboatPatrolWpts2)
end
end)
end)
end
SendGroundPatrol = function(team)
Utils.Do(team, function(unit) unit.Patrol(GroundPatrolWpts, true, Utils.Seconds(3)) end)
Utils.Do(team, function(unit)
Trigger.OnIdle(unit, function(actor) actor.Hunt() end)
end)
Trigger.OnAllKilled(team, function()
Build(Utils.Random(GroundPatrolUnits), SendGroundPatrol)
end)
end
BaseFrontAttack = function(team)
Utils.Do(team, function(unit) unit.Patrol(BaseFrontAttackWpts, false) end)
Utils.Do(team, function(unit)
Trigger.OnIdle(unit, function(actor) actor.Hunt() end)
end)
Trigger.AfterDelay(BaseFrontAttackInterval, function() Build(BaseFrontAttackUnits, BaseFrontAttack) end)
end
BaseRearAttack = function(team)
Utils.Do(team, function(unit) unit.Patrol(BaseRearAttackWpts, false) end)
Utils.Do(team, function(unit)
Trigger.OnIdle(unit, function(actor) actor.Hunt() end)
end)
Trigger.AfterDelay(BaseRearAttackInterval, function() Build(BaseRearAttackUnits, BaseRearAttack) end)
end
Build = function(units, action)
if not soviets.Build(units, action) then
Trigger.AfterDelay(Utils.Seconds(15), function()
Build(units, action)
end)
end
end
SetupWorld = function()
Utils.Do(SovietHarvesters, function(a) a.FindResources() end)
Utils.Do(SovietHarvesters, function(harvester)
Trigger.OnDamaged(harvester, function(h)
Utils.Do(HarvesterGuard, function(g)
if not g.IsDead then
g.Stop()
g.AttackMove(h.Location, 3)
end
end)
end)
end)
Utils.Do(UBoats, function(a) a.Stance = "Defend" end)
Utils.Do(Map.NamedActors, function(actor)
if actor.Owner == soviets and actor.HasProperty("StartBuildingRepairs") then
Trigger.OnDamaged(actor, function(building)
if building.Owner == soviets then
building.StartBuildingRepairs()
end
end)
end
end)
WarFactory.RallyPoint = Rallypoint.Location
WarFactory.IsPrimaryBuilding = true
Barracks.IsPrimaryBuilding = true
SubPen.IsPrimaryBuilding = true
end
Tick = function()
if soviets.Resources > soviets.ResourceCapacity * 0.75 then
soviets.Resources = soviets.Resources - ((soviets.ResourceCapacity * 0.01) / 25)
end
if player.HasNoRequiredUnits() then
player.MarkFailedObjective(villageObjective)
end
end
WorldLoaded = function()
player = Player.GetPlayer("Allies")
soviets = Player.GetPlayer("Soviets")
Trigger.OnObjectiveAdded(player, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
end)
Trigger.OnObjectiveCompleted(player, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed")
end)
Trigger.OnObjectiveFailed(player, function(p, id)
Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed")
end)
Trigger.OnPlayerWon(player, function()
Media.PlaySpeechNotification(player, "Win")
end)
Trigger.OnPlayerLost(player, function()
Media.PlaySpeechNotification(player, "Lose")
end)
sovietObjective = soviets.AddPrimaryObjective("Destroy the village.")
villageObjective = player.AddPrimaryObjective("Save the village.")
beachheadObjective = player.AddSecondaryObjective("Get your MCV to the main island.")
beachheadTrigger = false
Trigger.OnExitedFootprint(BeachheadTrigger, function(a, id)
if not beachheadTrigger and a.Owner == player and a.Type == "mcv" then
beachheadTrigger = true
Trigger.RemoveFootprintTrigger(id)
player.MarkCompletedObjective(beachheadObjective)
captureObjective = player.AddPrimaryObjective("Locate and capture the enemy's Air Force HQ.")
Trigger.OnCapture(AirForceHQ, function()
Trigger.AfterDelay(Utils.Seconds(3), function()
player.MarkCompletedObjective(captureObjective)
player.MarkCompletedObjective(villageObjective)
end)
end)
Trigger.OnKilled(AirForceHQ, function() player.MarkFailedObjective(captureObjective) end)
Trigger.AfterDelay(BaseFrontAttackInterval, function()
Build(BaseFrontAttackUnits, BaseFrontAttack)
ParadropSovietUnits()
end)
Trigger.AfterDelay(BaseRearAttackInterval, function()
Build(BaseRearAttackUnits, BaseRearAttack)
end)
Trigger.AfterDelay(BaseRaidInterval, BaseRaid)
Trigger.AfterDelay(UBoatPatrolDelay, function()
Build(HunterSubs, function(subs)
Utils.Do(subs, function(sub)
Trigger.OnIdle(sub, function(s) s.Hunt() end)
end)
end)
end)
end
end)
Trigger.OnAllKilled(Village, function() player.MarkFailedObjective(villageObjective) end)
SetupWorld()
Trigger.AfterDelay(VillageRaidInterval, VillageRaid)
Trigger.AfterDelay(1, function() Build(UBoatPatrolUnits, SendUboatPatrol) end)
Trigger.AfterDelay(1, function() Build(Utils.Random(GroundPatrolUnits), SendGroundPatrol) end)
Reinforcements.Reinforce(player, { "mcv" }, { MCVInsertLocation.Location, MCVDeployLocation.Location }, 0, function(mcv)
mcv.Deploy()
end)
Camera.Position = CameraSpot.CenterPosition
Trigger.AfterDelay(Utils.Seconds(5), function() CameraSpot.Destroy() end)
end

View File

@@ -2205,7 +2205,7 @@ Actors:
Actor14: wood
Location: 23,57
Owner: Neutral
Camera: CAMERA
CameraSpot: CAMERA
Location: 79,137
Owner: Allies
@@ -2220,8 +2220,8 @@ Rules:
-CrateSpawner:
-SpawnMPUnits:
-MPStartLocations:
LuaScriptInterface:
LuaScripts: mission.lua
LuaScript:
Scripts: intervention.lua
ObjectivesPanel:
PanelName: MISSION_OBJECTIVES
CAMERA:
@@ -2229,17 +2229,26 @@ Rules:
Range: 18c0
MISS:
Tooltip:
Name: Air Force HQ
Name: Soviet Air Force HQ
Capturable:
Type: building
AllowAllies: False
AllowNeutral: False
AllowEnemies: True
CaptureThreshold: 1.0
E6:
E6.MOD:
Inherits: E6
Buildable:
Prerequisites: ~barracks
-RepairsBridges:
Captures:
CaptureTypes: building
Sabotage: False
RenderInfantry:
Image: e6
E6:
Buildable:
Prerequisites: ~disabled
HPAD:
ProvidesCustomPrerequisite:
Prerequisite: givefix
@@ -2254,12 +2263,12 @@ Rules:
Name: Weapons Factory or Helipad
MIG:
Buildable:
Prerequisites: afld
Prerequisites: ~afld
LimitedAmmo:
Ammo: 2
HELI:
Buildable:
Prerequisites: hpad
Prerequisites: ~hpad
Valued:
Cost: 1500
SAM:
@@ -2270,19 +2279,49 @@ Rules:
TSLA:
Power:
Amount: -50
^Vehicles:
^Building:
Tooltip:
GenericVisibility: Enemy
ShowOwnerRow: false
^Vehicle:
MustBeDestroyed:
Tooltip:
GenericVisibility: Enemy
ShowOwnerRow: false
^Tank:
MustBeDestroyed:
Tooltip:
GenericVisibility: Enemy
ShowOwnerRow: false
^Infantry:
MustBeDestroyed:
Tooltip:
GenericVisibility: Enemy
ShowOwnerRow: false
^Plane:
MustBeDestroyed:
Tooltip:
GenericVisibility: Enemy
ShowOwnerRow: false
^Ship:
MustBeDestroyed:
Tooltip:
GenericVisibility: Enemy
ShowOwnerRow: false
^Wall:
Tooltip:
ShowOwnerRow: false
^Husk:
Tooltip:
GenericVisibility: Enemy, Ally, Neutral
GenericStancePrefix: false
ShowOwnerRow: false
ATEK:
Buildable:
Prerequisites: ~disabled
STEK:
Buildable:
Prerequisites: ~disabled
GAP:
Buildable:
Prerequisites: ~disabled
@@ -2292,9 +2331,24 @@ Rules:
PDOX:
Buildable:
Prerequisites: ~disabled
E4:
Buildable:
Prerequisites: ~disabled
E7:
Buildable:
Prerequisites: ~disabled
THF:
Buildable:
Prerequisites: ~disabled
HIJACKER:
Buildable:
Prerequisites: ~disabled
SHOK:
Buildable:
Prerequisites: ~disabled
SNIPER:
Buildable:
Prerequisites: ~disabled
2TNK:
Buildable:
Prerequisites: ~disabled
@@ -2310,6 +2364,9 @@ Rules:
MNLY.AT:
Buildable:
Prerequisites: ~disabled
MNLY.AP:
Buildable:
Prerequisites: ~disabled
MRJ:
Buildable:
Prerequisites: ~disabled
@@ -2319,6 +2376,9 @@ Rules:
HIND:
Buildable:
Prerequisites: ~disabled
YAK:
Buildable:
Prerequisites: ~disabled
CA:
Buildable:
Prerequisites: ~disabled

View File

@@ -1,272 +0,0 @@
difficulty = OpenRA.GetDifficulty()
if difficulty == "Medium" then
BaseRaidInterval = Utils.Minutes(3)
BaseFrontAttackInterval = Utils.Minutes(3) + Utils.Seconds(30)
BaseRearAttackInterval = Utils.Minutes(8)
UBoatPatrolDelay = Utils.Minutes(2) + Utils.Seconds(30)
BaseFrontAttackWpts = { PatrolWpt1, BaseRaidWpt1 }
else
BaseRaidInterval = Utils.Minutes(2) + Utils.Seconds(30)
BaseFrontAttackInterval = Utils.Minutes(2)
BaseRearAttackInterval = Utils.Minutes(5)
UBoatPatrolDelay = Utils.Minutes(2)
BaseFrontAttackWpts = { PatrolWpt1 }
end
Village = { FarmHouse1, FarmHouse2, FarmHouse3, FarmHouse4, FarmHouse5, FarmHouse6, FarmHouse7, FarmHouse8, FarmHouse9, Church }
VillageRaidInterval = Utils.Minutes(3)
VillageRaidAircraft = { "mig", "mig" }
VillageRaidWpts = { VillageRaidWpt1, VillageRaidWpt2 }
BaseRaidAircraft = { "mig", "mig" }
BaseRaidWpts = { UboatPatrolWpt1, BaseRaidWpt2 }
BaseFrontAttackUnits = {
{ Barracks, {"e3", "e3", "e1", "e1", "e1"} },
{ WarFactory, {"3tnk", "3tnk", "apc"} }
}
BaseRearAttackUnits = {
{ Barracks, {"e3", "e3", "e1", "e1"} },
{ WarFactory, {"3tnk", "3tnk", "v2rl"} }
}
BaseRearAttackWpts = { GroundAttackWpt1, BaseRearAttackWpt1, BaseRearAttackWpt2, BaseRearAttackWpt3 }
SovietHarvesters = { Harvester1, Harvester2, Harvester3 }
HarvesterGuard = { HarvGuard1, HarvGuard2, HarvGuard3 }
UBoats = { Uboat1, Uboat2, Uboat3, Uboat4, Uboat5, Uboat6 }
UboatPatrolWpts1 = { UboatPatrolWpt1, UboatPatrolWpt2, UboatPatrolWpt3, UboatPatrolWpt4 }
UboatPatrolWpts2 = { UboatPatrolWpt4, UboatPatrolWpt2, UboatPatrolWpt1 }
UBoatPatrolUnits = { { SubPen, {"ss"} } }
HunterSubs = { { SubPen, {"ss", "ss"} } }
GroundPatrolWpts = { PatrolWpt1, PatrolWpt2 }
GroundPatrolUnits = {
{ { Barracks, {"e1", "e1", "e1", "e3", "e3"} }, { Kennel, {"dog"} } },
{ { WarFactory, {"apc", "apc", "ftrk"} } },
{ { WarFactory, {"3tnk", "3tnk"} } }
}
Reinforcements.ReinforceAir = function(owner, planeNames, entrypoint, rallypoint, interval, onCreateFunc)
local facing = { Map.GetFacing(CPos.op_Subtraction(rallypoint.Location, entrypoint.Location), 0), "Int32" }
local flight = { }
for i, planeName in ipairs(planeNames) do
local enterPosition = WPos.op_Addition(entrypoint.CenterPosition, WVec.New(0, 0, Rules.InitialAltitude(planeName)))
local plane = Actor.Create(planeName, { AddToWorld = false, Location = entrypoint.Location, CenterPosition = enterPosition, Owner = owner, Facing = facing })
flight[i] = plane
OpenRA.RunAfterDelay((i - 1) * interval, function()
World:Add(plane)
Actor.Fly(plane, rallypoint.CenterPosition)
if onCreateFunc ~= nil then
onCreateFunc(plane)
end
end)
end
return flight
end
FollowWaypoints = function(team, waypoints)
Utils.Do(waypoints, function(wpt)
Team.Do(team, function(a) Actor.Fly(a, wpt.CenterPosition) end)
end)
end
PlaneExitMap = function(actor, exitPoint)
Actor.Fly(actor, exitPoint.CenterPosition)
Actor.FlyOffMap(actor)
Actor.RemoveSelf(actor)
end
BaseRaid = function()
local base = Map.FindStructuresInBox(player, AlliedAreaTopLeft, AlliedAreaBottomRight)
if #base == 0 then
return
end
local target = base[OpenRA.GetRandomInteger(1, #base + 1)]
local flight = Team.New(Reinforcements.ReinforceAir(soviets, BaseRaidAircraft, BaseRaidEntrypoint, BaseRaidWpts[1], Utils.Seconds(1)))
FollowWaypoints(flight, BaseRaidWpts)
Team.Do(flight, function(plane)
Actor.FlyAttackActor(plane, target)
PlaneExitMap(plane, VillageRaidEntrypoint)
end)
OpenRA.RunAfterDelay(BaseRaidInterval, BaseRaid)
end
VillageRaid = function()
local target = nil
Utils.Do(Village, function(tgt)
if target == nil and not Actor.IsDead(tgt) then
target = tgt
return
end
end)
if target == nil then
return
end
local flight = Team.New(Reinforcements.ReinforceAir(soviets, VillageRaidAircraft, VillageRaidEntrypoint, VillageRaidWpts[1], Utils.Seconds(1)))
FollowWaypoints(flight, VillageRaidWpts)
Team.Do(flight, function(plane)
Actor.FlyAttackActor(plane, target)
PlaneExitMap(plane, BaseRaidEntrypoint)
end)
OpenRA.RunAfterDelay(VillageRaidInterval, VillageRaid)
end
SendUboatPatrol = function(team)
OpenRA.RunAfterDelay(UBoatPatrolDelay, function()
if difficulty == "Medium" then
Team.Patrol(team, UboatPatrolWpts1, 0, false)
else
Team.Do(team, Actor.Hunt)
end
OpenRA.RunAfterDelay(Utils.Minutes(2), function()
Team.Do(team, Actor.Stop)
Team.Patrol(team, UboatPatrolWpts2)
end)
end)
end
SendGroundPatrol = function(team)
Team.Patrol(team, GroundPatrolWpts, Utils.Seconds(3))
Team.Do(team, function(actor) Actor.OnIdle(actor, Actor.Hunt) end)
Team.AddEventHandler(team.OnAllKilled, function()
Production.BuildTeamFromTemplate(soviets, GroundPatrolUnits[OpenRA.GetRandomInteger(1, #GroundPatrolUnits + 1)], SendGroundPatrol)
end)
end
BaseFrontAttack = function(team)
Team.Patrol(team, BaseFrontAttackWpts, 0, false)
Team.Do(team, function(actor) Actor.OnIdle(actor, Actor.Hunt) end)
OpenRA.RunAfterDelay(BaseFrontAttackInterval, function() Production.BuildTeamFromTemplate(soviets, BaseFrontAttackUnits, BaseFrontAttack) end)
end
BaseRearAttack = function(team)
Team.Patrol(team, BaseRearAttackWpts, 0, false)
Team.Do(team, function(actor) Actor.OnIdle(actor, Actor.Hunt) end)
OpenRA.RunAfterDelay(BaseRearAttackInterval, function() Production.BuildTeamFromTemplate(soviets, BaseRearAttackUnits, BaseRearAttack) end)
end
InsertMCV = function ()
local mcv = Actor.Create("mcv", { Owner = player, Location = MCVInsertLocation.Location, Facing = Facing.North })
Actor.Move(mcv, MCVDeployLocation.Location)
Actor.DeployTransform(mcv)
end
SetupWorld = function()
if difficulty ~= "Medium" then
Actor.RemoveSelf(EasyMine)
end
Utils.Do(SovietHarvesters, Actor.Harvest)
harvesterGuard = Team.New(HarvesterGuard)
Utils.Do(SovietHarvesters, function(harvester)
Actor.OnDamaged(harvester, function(h)
Team.Do(harvesterGuard, function(g)
Actor.Stop(g)
Actor.AttackMove(g, h.Location, 3)
end)
end)
end)
Utils.Do(UBoats, function(a) Actor.SetStance(a, "Defend") end)
Utils.Do(Actor.ActorsWithTrait("RepairableBuilding"), function(building)
if Actor.Owner(building) == soviets then
Actor.OnDamaged(building, function(b)
if Actor.Owner(b) == soviets then
Actor.RepairBuilding(b)
end
end)
end
end)
-- Production.SetRallyPoint(WarFactory, Rallypoint)
Production.EventHandlers.Setup(soviets)
-- RunAfterDelay is used so that the 'Building captured' and 'Mission accomplished' sounds don't play at the same time
Actor.OnCaptured(AirForceHQ, function() OpenRA.RunAfterDelay(Utils.Seconds(3), MissionAccomplished) end)
Actor.OnKilled(AirForceHQ, MissionFailed)
village = Team.New(Village)
Team.AddEventHandler(village.OnAllKilled, MissionFailed)
end
tick = 0
alliedBaseEstablished = false
Tick = function()
tick = tick + 1
if OpenRA.GetOre(soviets) > (OpenRA.GetOreCapacity(soviets) * 0.75) then
Mission.TickTakeOre(soviets)
end
if Mission.RequiredUnitsAreDestroyed(player) then
OpenRA.RunAfterDelay(Utils.Seconds(1), MissionFailed)
end
if not alliedBaseEstablished and tick > Utils.Minutes(5) and tick % Utils.Seconds(10) == 0 then
-- FIXME: replace with cell trigger when available
local base = Map.FindStructuresInBox(player, AlliedAreaTopLeft, AlliedAreaBottomRight)
if #base > 0 then
alliedBaseEstablished = true
OpenRA.RunAfterDelay(BaseFrontAttackInterval, function()
Production.BuildTeamFromTemplate(soviets, BaseFrontAttackUnits, BaseFrontAttack)
local plane, paratroopers = SupportPowers.Paradrop(soviets, "badr", {"e1", "e1", "e1", "e3", "e3"}, BaseRaidEntrypoint.Location, MCVDeployLocation.Location)
Utils.Do(paratroopers, function(actor) Actor.OnIdle(actor, Actor.Hunt) end)
end)
OpenRA.RunAfterDelay(BaseRearAttackInterval, function()
Production.BuildTeamFromTemplate(soviets, BaseRearAttackUnits, BaseRearAttack)
end)
Production.BuildTeamFromTemplate(soviets, HunterSubs, function(team)
Team.Do(team, function(actor) Actor.OnIdle(actor, Actor.Hunt) end)
end)
OpenRA.RunAfterDelay(BaseRaidInterval, BaseRaid)
end
end
end
WorldLoaded = function()
player = OpenRA.GetPlayer("Allies")
soviets = OpenRA.GetPlayer("Soviets")
civvies = OpenRA.GetPlayer("Civilians")
SetupWorld()
OpenRA.RunAfterDelay(1, function()
Production.BuildTeamFromTemplate(soviets, UBoatPatrolUnits, SendUboatPatrol)
Production.BuildTeamFromTemplate(soviets, GroundPatrolUnits[OpenRA.GetRandomInteger(1, #GroundPatrolUnits + 1)], SendGroundPatrol)
end)
OpenRA.RunAfterDelay(VillageRaidInterval, VillageRaid)
InsertMCV()
OpenRA.SetViewportCenterPosition(Camera.CenterPosition)
OpenRA.RunAfterDelay(Utils.Seconds(5), function() Actor.RemoveSelf(Camera) end)
end
MissionFailed = function()
Mission.MissionOver(nil, { player }, true)
end
MissionAccomplished = function()
Mission.MissionOver({ player }, nil, true)
end