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:
@@ -515,7 +515,7 @@
|
|||||||
<Compile Include="Warheads\PerCellDamageWarhead.cs" />
|
<Compile Include="Warheads\PerCellDamageWarhead.cs" />
|
||||||
<Compile Include="Warheads\SpreadDamageWarhead.cs" />
|
<Compile Include="Warheads\SpreadDamageWarhead.cs" />
|
||||||
<Compile Include="Scripting\Global\ReinforcementsGlobal.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\HarvesterProperties.cs" />
|
||||||
<Compile Include="Scripting\Properties\HelicopterProperties.cs" />
|
<Compile Include="Scripting\Properties\HelicopterProperties.cs" />
|
||||||
<Compile Include="Scripting\Properties\PlaneProperties.cs" />
|
<Compile Include="Scripting\Properties\PlaneProperties.cs" />
|
||||||
@@ -586,4 +586,4 @@ copy "FuzzyLogicLibrary.dll" "$(SolutionDir)"
|
|||||||
cd "$(SolutionDir)"</PostBuildEvent>
|
cd "$(SolutionDir)"</PostBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.RA
|
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.",
|
"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.")]
|
"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>
|
public class ClassicProductionQueueInfo : ProductionQueueInfo, Requires<TechTreeInfo>, Requires<PowerManagerInfo>, Requires<PlayerResourcesInfo>
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ namespace OpenRA.Mods.RA.Scripting
|
|||||||
[ScriptGlobal("Date")]
|
[ScriptGlobal("Date")]
|
||||||
public class DateGlobal : ScriptGlobal
|
public class DateGlobal : ScriptGlobal
|
||||||
{
|
{
|
||||||
public DateGlobal(ScriptContext context) : base(context) { }
|
public DateGlobal(ScriptContext context)
|
||||||
|
: base(context) { }
|
||||||
|
|
||||||
[Desc("True on the 31st of October.")]
|
[Desc("True on the 31st of October.")]
|
||||||
public bool IsHalloween
|
public bool IsHalloween
|
||||||
@@ -25,4 +26,17 @@ namespace OpenRA.Mods.RA.Scripting
|
|||||||
get { return DateTime.Today.Month == 10 && DateTime.Today.Day == 31; }
|
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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ namespace OpenRA.Mods.RA.Scripting
|
|||||||
{
|
{
|
||||||
public TriggerGlobal(ScriptContext context) : base(context) { }
|
public TriggerGlobal(ScriptContext context) : base(context) { }
|
||||||
|
|
||||||
static ScriptTriggers GetScriptTriggers(Actor a)
|
public static ScriptTriggers GetScriptTriggers(Actor a)
|
||||||
{
|
{
|
||||||
var events = a.TraitOrDefault<ScriptTriggers>();
|
var events = a.TraitOrDefault<ScriptTriggers>();
|
||||||
if (events == null)
|
if (events == null)
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using Eluant;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using OpenRA.Mods.RA.Activities;
|
using OpenRA.Mods.RA.Activities;
|
||||||
using OpenRA.Scripting;
|
using OpenRA.Scripting;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
@@ -17,8 +20,13 @@ namespace OpenRA.Mods.RA.Scripting
|
|||||||
[ScriptPropertyGroup("Combat")]
|
[ScriptPropertyGroup("Combat")]
|
||||||
public class CombatProperties : ScriptActorProperties, Requires<AttackBaseInfo>, Requires<IMoveInfo>
|
public class CombatProperties : ScriptActorProperties, Requires<AttackBaseInfo>, Requires<IMoveInfo>
|
||||||
{
|
{
|
||||||
|
readonly IMove move;
|
||||||
|
|
||||||
public CombatProperties(ScriptContext context, Actor self)
|
public CombatProperties(ScriptContext context, Actor self)
|
||||||
: base(context, self) { }
|
: base(context, self)
|
||||||
|
{
|
||||||
|
move = self.Trait<IMove>();
|
||||||
|
}
|
||||||
|
|
||||||
[ScriptActorPropertyActivity]
|
[ScriptActorPropertyActivity]
|
||||||
[Desc("Seek out and attack nearby targets.")]
|
[Desc("Seek out and attack nearby targets.")]
|
||||||
@@ -33,11 +41,35 @@ namespace OpenRA.Mods.RA.Scripting
|
|||||||
"close enough to complete the activity.")]
|
"close enough to complete the activity.")]
|
||||||
public void AttackMove(CPos cell, int closeEnough = 0)
|
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)));
|
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)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using OpenRA.Mods.RA.Buildings;
|
||||||
using OpenRA.Scripting;
|
using OpenRA.Scripting;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
@@ -33,4 +34,34 @@ namespace OpenRA.Mods.RA.Scripting
|
|||||||
[Desc("Maximum health of the actor.")]
|
[Desc("Maximum health of the actor.")]
|
||||||
public int MaxHealth { get { return health.MaxHP; } }
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -27,4 +27,17 @@ namespace OpenRA.Mods.RA.Scripting
|
|||||||
self.QueueActivity(new Fly(self, Target.FromCell(self.World, cell)));
|
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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,10 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using Eluant;
|
using Eluant;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenRA.Mods.Common;
|
||||||
using OpenRA.Mods.RA.Activities;
|
using OpenRA.Mods.RA.Activities;
|
||||||
using OpenRA.Scripting;
|
using OpenRA.Scripting;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
@@ -37,4 +41,234 @@ namespace OpenRA.Mods.RA.Scripting
|
|||||||
self.QueueActivity(new WaitFor(() => p.Produce(self, actorInfo, raceVariant)));
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -18,22 +18,31 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.RA.Scripting
|
namespace OpenRA.Mods.RA.Scripting
|
||||||
{
|
{
|
||||||
public enum Trigger { OnIdle, OnDamaged, OnKilled, OnProduction, OnPlayerWon, OnPlayerLost, OnObjectiveAdded,
|
public enum Trigger { OnIdle, OnDamaged, OnKilled, OnProduction, OnOtherProduction, OnPlayerWon, OnPlayerLost,
|
||||||
OnObjectiveCompleted, OnObjectiveFailed, OnCapture, OnAddedToWorld, OnRemovedFromWorld };
|
OnObjectiveAdded, OnObjectiveCompleted, OnObjectiveFailed, OnCapture, OnAddedToWorld, OnRemovedFromWorld };
|
||||||
|
|
||||||
[Desc("Allows map scripts to attach triggers to this actor via the Triggers global.")]
|
[Desc("Allows map scripts to attach triggers to this actor via the Triggers global.")]
|
||||||
public class ScriptTriggersInfo : TraitInfo<ScriptTriggers> { }
|
public class ScriptTriggersInfo : ITraitInfo
|
||||||
|
|
||||||
public sealed class ScriptTriggers : INotifyIdle, INotifyDamage, INotifyKilled, INotifyProduction, INotifyObjectivesUpdated, INotifyCapture, INotifyAddedToWorld, INotifyRemovedFromWorld, IDisposable
|
|
||||||
{
|
{
|
||||||
|
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> OnKilledInternal = _ => { };
|
||||||
public event Action<Actor> OnRemovedInternal = _ => { };
|
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 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>>());
|
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)
|
public void UnitProduced(Actor self, Actor other, CPos exit)
|
||||||
{
|
{
|
||||||
|
// Run Lua callbacks
|
||||||
foreach (var f in Triggers[Trigger.OnProduction])
|
foreach (var f in Triggers[Trigger.OnProduction])
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -115,6 +125,9 @@ namespace OpenRA.Mods.RA.Scripting
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run any internally bound callbacks
|
||||||
|
OnProducedInternal(self, other);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnPlayerWon(Player player)
|
public void OnPlayerWon(Player player)
|
||||||
@@ -263,22 +276,46 @@ namespace OpenRA.Mods.RA.Scripting
|
|||||||
OnRemovedInternal(self);
|
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)
|
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()
|
public void ClearAll()
|
||||||
{
|
{
|
||||||
foreach (var trigger in Triggers)
|
foreach (Trigger t in Enum.GetValues(typeof(Trigger)))
|
||||||
trigger.Value.Clear();
|
Clear(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
var pairs = Triggers.Values;
|
ClearAll();
|
||||||
pairs.SelectMany(l => l).Select(p => p.First).Do(f => f.Dispose());
|
|
||||||
pairs.Do(l => l.Clear());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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-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\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\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
|
mods\ra\maps\fort-lonestar\fort-lonestar.lua = mods\ra\maps\fort-lonestar\fort-lonestar.lua
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
|||||||
@@ -1,137 +1,166 @@
|
|||||||
Nod1Template = { {HandOfNod, {"e1", "e1", "e3", "e3"}} }
|
AutoTrigger = { CPos.New(51, 47), CPos.New(52, 47), CPos.New(53, 47), CPos.New(54, 47) }
|
||||||
Auto1Template = { {HandOfNod, {"e1", "e1", "e3"}} }
|
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
|
KillsUntilReinforcements = 12
|
||||||
HeliDelay = {83, 137, 211}
|
HeliDelay = { 83, 137, 211 }
|
||||||
|
|
||||||
GDIReinforcements = {"e2", "e2", "e2", "e2"}
|
GDIReinforcements = { "e2", "e2", "e2", "e2", "e2" }
|
||||||
GDIReinforcementsWaypoints = {GDIReinforcementsEntry, GDIReinforcementsWP1}
|
GDIReinforcementsWaypoints = { GDIReinforcementsEntry.Location, GDIReinforcementsWP1.Location }
|
||||||
|
|
||||||
NodHelis = {
|
NodHelis = {
|
||||||
{Utils.Seconds(HeliDelay[1]), {NodHeliEntry, NodHeliLZ1}, {"e1", "e1", "e3"}},
|
{ Utils.Seconds(HeliDelay[1]), { NodHeliEntry.Location, NodHeliLZ1.Location }, { "e1", "e1", "e3" } },
|
||||||
{Utils.Seconds(HeliDelay[2]), {NodHeliEntry, NodHeliLZ2}, {"e1", "e1", "e1", "e1"}},
|
{ Utils.Seconds(HeliDelay[2]), { NodHeliEntry.Location, NodHeliLZ2.Location }, { "e1", "e1", "e1", "e1" } },
|
||||||
{Utils.Seconds(HeliDelay[3]), {NodHeliEntry, NodHeliLZ3}, {"e1", "e1", "e3"}}
|
{ Utils.Seconds(HeliDelay[3]), { NodHeliEntry.Location, NodHeliLZ3.Location }, { "e1", "e1", "e3" } }
|
||||||
}
|
}
|
||||||
|
|
||||||
SendHeli = function(heli, func)
|
SendHeli = function(heli)
|
||||||
Reinforcements.ReinforceWithCargo(nod, "tran", heli[2], heli[3], func)
|
units = Reinforcements.ReinforceWithTransport(nod, "tran", heli[3], heli[2], { heli[2][1] })
|
||||||
OpenRA.RunAfterDelay(heli[1], function() SendHeli(heli, func) end)
|
Utils.Do(units[2], function(actor)
|
||||||
end
|
actor.Hunt()
|
||||||
|
Trigger.OnIdle(actor, actor.Hunt)
|
||||||
HeliAction = function(heliActor, team)
|
Trigger.OnKilled(actor, KillCounter)
|
||||||
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)
|
|
||||||
end)
|
end)
|
||||||
|
Trigger.AfterDelay(heli[1], function() SendHeli(heli) end)
|
||||||
end
|
end
|
||||||
|
|
||||||
SendGDIReinforcements = function()
|
SendGDIReinforcements = function()
|
||||||
Reinforcements.ReinforceWithCargo(player, "apc", GDIReinforcementsWaypoints, GDIReinforcements, function(apc, team)
|
Media.PlaySpeechNotification(gdi, "Reinforce")
|
||||||
Team.Add(team, apc)
|
Reinforcements.ReinforceWithTransport(gdi, "apc", GDIReinforcements, GDIReinforcementsWaypoints, nil, function(apc, team)
|
||||||
Actor.OnKilled(apc, SendGDIReinforcements)
|
table.insert(team, apc)
|
||||||
Team.Do(team, function(unit) Actor.SetStance(unit, "Defend") end)
|
Trigger.OnAllKilled(team, function() Trigger.AfterDelay(Utils.Seconds(5), SendGDIReinforcements) end)
|
||||||
|
Utils.Do(team, function(unit) unit.Stance = "Defend" end)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
BuildNod1 = function()
|
BuildNod1 = function()
|
||||||
Production.BuildTeamFromTemplate(nod, Nod1Template, function(team)
|
if HandOfNod.IsDead then
|
||||||
Team.Do(team, function(actor)
|
return
|
||||||
Actor.OnIdle(actor, Actor.Hunt)
|
end
|
||||||
Actor.OnKilled(actor, KillCounter)
|
|
||||||
|
local func = function(team)
|
||||||
|
Utils.Do(team, function(actor)
|
||||||
|
Trigger.OnIdle(actor, actor.Hunt)
|
||||||
|
Trigger.OnKilled(actor, KillCounter)
|
||||||
end)
|
end)
|
||||||
Team.AddEventHandler(team.OnAllKilled, BuildNod1)
|
Trigger.OnAllKilled(team, BuildNod1)
|
||||||
end)
|
end
|
||||||
|
|
||||||
|
if not HandOfNod.Build(Nod1Units, func) then
|
||||||
|
Trigger.AfterDelay(Utils.Seconds(5), BuildNod1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
BuildAuto1 = function()
|
BuildAuto1 = function()
|
||||||
Production.BuildTeamFromTemplate(nod, Auto1Template, function(team)
|
if HandOfNod.IsDead then
|
||||||
Team.Do(team, function(actor)
|
return
|
||||||
Actor.OnIdle(actor, Actor.Hunt)
|
end
|
||||||
Actor.OnKilled(actor, KillCounter)
|
|
||||||
|
local func = function(team)
|
||||||
|
Utils.Do(team, function(actor)
|
||||||
|
Trigger.OnIdle(actor, actor.Hunt)
|
||||||
|
Trigger.OnKilled(actor, KillCounter)
|
||||||
end)
|
end)
|
||||||
end)
|
end
|
||||||
|
|
||||||
|
if not HandOfNod.IsDead and HandOfNod.Build(Auto1Units, func) then
|
||||||
|
Trigger.AfterDelay(Utils.Seconds(5), BuildAuto1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
kills = 0
|
kills = 0
|
||||||
KillCounter = function() kills = kills + 1 end
|
KillCounter = function() kills = kills + 1 end
|
||||||
|
|
||||||
Auto1Triggered = false
|
|
||||||
GDIHeliTriggered = false
|
|
||||||
ReinforcementsSent = false
|
ReinforcementsSent = false
|
||||||
Tick = function()
|
Tick = function()
|
||||||
|
nod.Cash = 1000
|
||||||
|
|
||||||
if not ReinforcementsSent and kills >= KillsUntilReinforcements then
|
if not ReinforcementsSent and kills >= KillsUntilReinforcements then
|
||||||
ReinforcementsSent = true
|
ReinforcementsSent = true
|
||||||
|
gdi.MarkCompletedObjective(reinforcementsObjective)
|
||||||
SendGDIReinforcements()
|
SendGDIReinforcements()
|
||||||
end
|
end
|
||||||
|
|
||||||
if Mission.RequiredUnitsAreDestroyed(player) then
|
if gdi.HasNoRequiredUnits() then
|
||||||
OpenRA.RunAfterDelay(Utils.Seconds(1), MissionFailed)
|
Trigger.AfterDelay(Utils.Seconds(1), function() gdi.MarkFailedObjective(gdiObjective) end)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
SetupWorld = function()
|
SetupWorld = function()
|
||||||
OpenRA.GiveCash(nod, 10000)
|
Utils.Do(nod.GetGroundAttackers(nod), function(unit)
|
||||||
Production.EventHandlers.Setup(nod)
|
Trigger.OnKilled(unit, KillCounter)
|
||||||
|
|
||||||
Utils.Do(Mission.GetGroundAttackersOf(nod), function(unit)
|
|
||||||
Actor.OnKilled(unit, KillCounter)
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
Utils.Do(Mission.GetGroundAttackersOf(player), function(unit)
|
Utils.Do(gdi.GetGroundAttackers(), function(unit)
|
||||||
Actor.SetStance(unit, "Defend")
|
unit.Stance = "Defend"
|
||||||
end)
|
end)
|
||||||
|
|
||||||
Actor.Hunt(Hunter1)
|
Hunter1.Hunt()
|
||||||
Actor.Hunt(Hunter2)
|
Hunter2.Hunt()
|
||||||
|
|
||||||
Actor.OnRemovedFromWorld(crate, MissionAccomplished)
|
Trigger.OnRemovedFromWorld(crate, function() gdi.MarkCompletedObjective(gdiObjective) end)
|
||||||
end
|
end
|
||||||
|
|
||||||
WorldLoaded = function()
|
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")
|
|
||||||
|
|
||||||
SetupWorld()
|
SetupWorld()
|
||||||
|
|
||||||
OpenRA.RunAfterDelay(1, BuildNod1)
|
Trigger.OnObjectiveAdded(gdi, function(p, id)
|
||||||
Utils.Do(NodHelis, function(heli)
|
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||||
OpenRA.RunAfterDelay(heli[1], function() SendHeli(heli, HeliAction) end)
|
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)
|
end)
|
||||||
|
|
||||||
OpenRA.SetViewportCenterPosition(Actor56.CenterPosition)
|
Trigger.OnPlayerWon(gdi, function()
|
||||||
end
|
Media.PlaySpeechNotification(gdi, "Win")
|
||||||
|
Trigger.AfterDelay(Utils.Seconds(1), function()
|
||||||
|
Media.PlayMovieFullscreen("burdet1.vqa")
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
MissionAccomplished = function()
|
Trigger.OnPlayerLost(gdi, function()
|
||||||
Mission.MissionOver({ player }, nil, true)
|
Media.PlaySpeechNotification(gdi, "Lose")
|
||||||
Media.PlayMovieFullscreen("burdet1.vqa")
|
Trigger.AfterDelay(Utils.Seconds(1), function()
|
||||||
end
|
Media.PlayMovieFullscreen("gameover.vqa")
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
MissionFailed = function()
|
gdiObjective = gdi.AddPrimaryObjective("Retrieve the crate with the stolen rods.")
|
||||||
Mission.MissionOver(nil, { player }, true)
|
reinforcementsObjective = gdi.AddSecondaryObjective("Eliminate " .. KillsUntilReinforcements .. " Nod units for reinforcements.")
|
||||||
Media.PlayMovieFullscreen("gameover.vqa")
|
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
|
end
|
||||||
|
|||||||
@@ -326,6 +326,12 @@ Actors:
|
|||||||
Health: 1
|
Health: 1
|
||||||
Facing: 0
|
Facing: 0
|
||||||
SubCell: 3
|
SubCell: 3
|
||||||
|
Actor710: e1
|
||||||
|
Location: 12,54
|
||||||
|
Owner: GDI
|
||||||
|
Health: 1
|
||||||
|
Facing: 0
|
||||||
|
SubCell: 5
|
||||||
Actor71: e1
|
Actor71: e1
|
||||||
Location: 12,54
|
Location: 12,54
|
||||||
Owner: GDI
|
Owner: GDI
|
||||||
@@ -416,6 +422,12 @@ Actors:
|
|||||||
Health: 1
|
Health: 1
|
||||||
Facing: 64
|
Facing: 64
|
||||||
SubCell: 4
|
SubCell: 4
|
||||||
|
Actor860: e2
|
||||||
|
Location: 14,54
|
||||||
|
Owner: GDI
|
||||||
|
Health: 1
|
||||||
|
Facing: 0
|
||||||
|
SubCell: 5
|
||||||
Actor86: e2
|
Actor86: e2
|
||||||
Location: 14,54
|
Location: 14,54
|
||||||
Owner: GDI
|
Owner: GDI
|
||||||
@@ -524,9 +536,6 @@ Actors:
|
|||||||
GDIReinforcementsEntry: waypoint
|
GDIReinforcementsEntry: waypoint
|
||||||
Location: 7,50
|
Location: 7,50
|
||||||
Owner: Neutral
|
Owner: Neutral
|
||||||
Auto1Trigger: waypoint
|
|
||||||
Location: 52,47
|
|
||||||
Owner: Neutral
|
|
||||||
NodHeliEntry: waypoint
|
NodHeliEntry: waypoint
|
||||||
Location: 41,23
|
Location: 41,23
|
||||||
Owner: Neutral
|
Owner: Neutral
|
||||||
@@ -547,8 +556,8 @@ Rules:
|
|||||||
-SpawnMPUnits:
|
-SpawnMPUnits:
|
||||||
-MPStartLocations:
|
-MPStartLocations:
|
||||||
-CrateSpawner:
|
-CrateSpawner:
|
||||||
LuaScriptInterface:
|
LuaScript:
|
||||||
LuaScripts: gdi04a.lua
|
Scripts: gdi04a.lua
|
||||||
ObjectivesPanel:
|
ObjectivesPanel:
|
||||||
PanelName: MISSION_OBJECTIVES
|
PanelName: MISSION_OBJECTIVES
|
||||||
Player:
|
Player:
|
||||||
@@ -595,18 +604,16 @@ Rules:
|
|||||||
GenericVisibility: Enemy, Ally, Neutral
|
GenericVisibility: Enemy, Ally, Neutral
|
||||||
GenericStancePrefix: false
|
GenericStancePrefix: false
|
||||||
ShowOwnerRow: false
|
ShowOwnerRow: false
|
||||||
HARV:
|
|
||||||
-MustBeDestroyed:
|
|
||||||
CRATE:
|
CRATE:
|
||||||
Crate:
|
Crate:
|
||||||
Lifetime: 9999
|
Lifetime: 9999
|
||||||
LuaScriptEvents:
|
|
||||||
HealUnitsCrateAction:
|
HealUnitsCrateAction:
|
||||||
-RevealMapCrateAction:
|
-RevealMapCrateAction:
|
||||||
-GiveMcvCrateAction:
|
-GiveMcvCrateAction:
|
||||||
-GiveCashCrateAction:
|
-GiveCashCrateAction:
|
||||||
-ExplodeCrateAction@fire:
|
-ExplodeCrateAction@fire:
|
||||||
-GrantUpgradeCrateAction@cloak:
|
-GrantUpgradeCrateAction@cloak:
|
||||||
|
-DuplicateUnitCrateAction:
|
||||||
ScriptTriggers:
|
ScriptTriggers:
|
||||||
|
|
||||||
Sequences:
|
Sequences:
|
||||||
@@ -615,7 +622,7 @@ VoxelSequences:
|
|||||||
|
|
||||||
Weapons:
|
Weapons:
|
||||||
Tiberium:
|
Tiberium:
|
||||||
Warhead: SpreadDamage
|
Warhead@1Dam: SpreadDamage
|
||||||
Damage: 6
|
Damage: 6
|
||||||
|
|
||||||
Voices:
|
Voices:
|
||||||
|
|||||||
@@ -1,172 +1,198 @@
|
|||||||
NodxTemplate = { {HandOfNod, {"e1", "e1", "e3", "e3"}} }
|
BhndTrigger = { CPos.New(39, 21), CPos.New(40, 21), CPos.New(41, 21) }
|
||||||
AutoTemplate = { {HandOfNod, {"e1", "e1", "e1", "e3", "e3"}} }
|
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
|
KillsUntilReinforcements = 12
|
||||||
kills = 0
|
|
||||||
KillCounter = function() kills = kills + 1 end
|
|
||||||
|
|
||||||
GDIReinforcements = {"e2", "e2", "e2", "e2"}
|
GDIReinforcements = { "e2", "e2", "e2", "e2", "e2" }
|
||||||
GDIReinforcementsWaypoints = {GDIReinforcementsEntry, GDIReinforcementsWP1}
|
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)
|
SendHeli = function(heli)
|
||||||
Reinforcements.ReinforceWithCargo(nod, "tran", heli[1], heli[2], func)
|
units = Reinforcements.ReinforceWithTransport(nod, "tran", heli[2], heli[1], { heli[1][1] })
|
||||||
end
|
Utils.Do(units[2], function(actor)
|
||||||
|
actor.Hunt()
|
||||||
HeliAction = function(heliActor, team)
|
Trigger.OnIdle(actor, actor.Hunt)
|
||||||
Actor.AfterMove(heliActor)
|
Trigger.OnKilled(actor, KillCounter)
|
||||||
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)
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
SendGDIReinforcements = function()
|
SendGDIReinforcements = function()
|
||||||
Reinforcements.ReinforceWithCargo(player, "apc", GDIReinforcementsWaypoints, GDIReinforcements, function(apc, team)
|
Media.PlaySpeechNotification(gdi, "Reinforce")
|
||||||
Team.Add(team, apc)
|
Reinforcements.ReinforceWithTransport(gdi, "apc", GDIReinforcements, GDIReinforcementsWaypoints, nil, function(apc, team)
|
||||||
Actor.OnKilled(apc, SendGDIReinforcements)
|
table.insert(team, apc)
|
||||||
Team.Do(team, function(unit) Actor.SetStance(unit, "Defend") end)
|
Trigger.OnAllKilled(team, function() Trigger.AfterDelay(Utils.Seconds(5), SendGDIReinforcements) end)
|
||||||
|
Utils.Do(team, function(unit) unit.Stance = "Defend" end)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
Build = function(template, repeats, func)
|
Build = function(unitTypes, repeats, func)
|
||||||
Production.BuildTeamFromTemplate(nod, template, function(team)
|
if HandOfNod.IsDead then
|
||||||
Team.Do(team, func)
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local innerFunc = function(units)
|
||||||
|
Utils.Do(units, func)
|
||||||
if repeats then
|
if repeats then
|
||||||
Team.AddEventHandler(team.OnAllKilled, function()
|
Trigger.OnAllKilled(units, function()
|
||||||
Build(template, repeats, func)
|
Build(unitTypes, repeats, func)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
|
|
||||||
|
if not HandOfNod.Build(unitTypes, innerFunc) then
|
||||||
|
Trigger.AfterDelay(Utils.Seconds(5), function()
|
||||||
|
Build(unitTypes, repeats, func)
|
||||||
|
end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
BuildNod1 = function()
|
BuildNod1 = function()
|
||||||
Build(NodxTemplate, false, function(actor)
|
Build(NodxUnits, false, function(actor)
|
||||||
Actor.OnKilled(actor, KillCounter)
|
Trigger.OnKilled(actor, KillCounter)
|
||||||
Actor.Patrol(actor, {waypoint1, waypoint2, waypoint3, waypoint4}, 0, false)
|
actor.Patrol({ waypoint1.Location, waypoint2.Location, waypoint3.Location, waypoint4.Location }, false)
|
||||||
Actor.OnIdle(actor, Actor.Hunt)
|
Trigger.OnIdle(actor, actor.Hunt)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
BuildNod2 = function()
|
BuildNod2 = function()
|
||||||
Build(NodxTemplate, false, function(actor)
|
Build(NodxUnits, false, function(actor)
|
||||||
Actor.OnKilled(actor, KillCounter)
|
Trigger.OnKilled(actor, KillCounter)
|
||||||
Actor.Patrol(actor, {waypoint1, waypoint2}, 0, false)
|
actor.Patrol({ waypoint1.Location, waypoint2.Location }, false)
|
||||||
Actor.OnIdle(actor, Actor.Hunt)
|
Trigger.OnIdle(actor, actor.Hunt)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
BuildAuto = function()
|
BuildAuto = function()
|
||||||
Build(AutoTemplate, true, function(actor)
|
Build(AutoUnits, true, function(actor)
|
||||||
Actor.OnKilled(actor, KillCounter)
|
Trigger.OnKilled(actor, KillCounter)
|
||||||
Actor.OnIdle(actor, Actor.Hunt)
|
Trigger.OnIdle(actor, actor.Hunt)
|
||||||
end)
|
end)
|
||||||
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
|
ReinforcementsSent = false
|
||||||
|
kills = 0
|
||||||
|
KillCounter = function() kills = kills + 1 end
|
||||||
Tick = function()
|
Tick = function()
|
||||||
|
nod.Cash = 1000
|
||||||
|
|
||||||
if not ReinforcementsSent and kills >= KillsUntilReinforcements then
|
if not ReinforcementsSent and kills >= KillsUntilReinforcements then
|
||||||
ReinforcementsSent = true
|
ReinforcementsSent = true
|
||||||
|
gdi.MarkCompletedObjective(reinforcementsObjective)
|
||||||
SendGDIReinforcements()
|
SendGDIReinforcements()
|
||||||
end
|
end
|
||||||
|
|
||||||
if Mission.RequiredUnitsAreDestroyed(player) then
|
if gdi.HasNoRequiredUnits() then
|
||||||
OpenRA.RunAfterDelay(Utils.Seconds(1), MissionFailed)
|
Trigger.AfterDelay(Utils.Seconds(1), function()
|
||||||
end
|
gdi.MarkFailedObjective(gdiObjective)
|
||||||
|
|
||||||
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)
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
SetupWorld = function()
|
SetupWorld = function()
|
||||||
OpenRA.GiveCash(nod, 10000)
|
Utils.Do(nod.GetGroundAttackers(), function(unit)
|
||||||
Production.EventHandlers.Setup(nod)
|
Trigger.OnKilled(unit, KillCounter)
|
||||||
|
|
||||||
Utils.Do(Mission.GetGroundAttackersOf(nod), function(unit)
|
|
||||||
Actor.OnKilled(unit, KillCounter)
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
Utils.Do(Mission.GetGroundAttackersOf(player), function(unit)
|
Utils.Do(gdi.GetGroundAttackers(), function(unit)
|
||||||
Actor.SetStance(unit, "Defend")
|
unit.Stance = "Defend"
|
||||||
end)
|
end)
|
||||||
|
|
||||||
hunters1 = Team.New({Hunter1, Hunter2})
|
Utils.Do(Hunters, function(actor) actor.Hunt() end)
|
||||||
hunters2 = Team.New({Hunter3, Hunter4, Hunter5})
|
|
||||||
|
|
||||||
OpenRA.RunAfterDelay(1, function() Team.Do(hunters1, Actor.Hunt) end)
|
Trigger.OnRemovedFromWorld(crate, function() gdi.MarkCompletedObjective(gdiObjective) end)
|
||||||
OpenRA.RunAfterDelay(1, function() Team.Do(hunters2, Actor.Hunt) end)
|
|
||||||
|
|
||||||
Actor.OnRemovedFromWorld(crate, MissionAccomplished)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
WorldLoaded = function()
|
WorldLoaded = function()
|
||||||
Media.PlayMovieFullscreen("bkground.vqa", function() Media.PlayMovieFullscreen("nitejump.vqa") end)
|
gdi = Player.GetPlayer("GDI")
|
||||||
|
nod = Player.GetPlayer("Nod")
|
||||||
|
|
||||||
player = OpenRA.GetPlayer("GDI")
|
Trigger.OnObjectiveAdded(gdi, function(p, id)
|
||||||
nod = OpenRA.GetPlayer("Nod")
|
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()
|
SetupWorld()
|
||||||
|
|
||||||
OpenRA.SetViewportCenterPosition(GDIReinforcementsWP1.CenterPosition)
|
bhndTrigger = false
|
||||||
end
|
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()
|
atk1Trigger = false
|
||||||
Mission.MissionOver({ player }, nil, true)
|
Trigger.OnExitedFootprint(Atk1Trigger, function(a, id)
|
||||||
Media.PlayMovieFullscreen("burdet1.vqa")
|
if not atk1Trigger and a.Owner == gdi then
|
||||||
end
|
atk1Trigger = true
|
||||||
|
Trigger.RemoveFootprintTrigger(id)
|
||||||
|
BuildNod1()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
MissionFailed = function()
|
atk2Trigger = false
|
||||||
Mission.MissionOver(nil, { player }, true)
|
Trigger.OnEnteredFootprint(Atk2Trigger, function(a, id)
|
||||||
Media.PlayMovieFullscreen("gameover.vqa")
|
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
|
end
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
@@ -597,21 +597,6 @@ Actors:
|
|||||||
crate: CRATE
|
crate: CRATE
|
||||||
Location: 14,13
|
Location: 14,13
|
||||||
Owner: Neutral
|
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
|
HeliEntry: waypoint
|
||||||
Location: 4,26
|
Location: 4,26
|
||||||
Owner: Neutral
|
Owner: Neutral
|
||||||
@@ -626,8 +611,8 @@ Rules:
|
|||||||
-SpawnMPUnits:
|
-SpawnMPUnits:
|
||||||
-MPStartLocations:
|
-MPStartLocations:
|
||||||
-CrateSpawner:
|
-CrateSpawner:
|
||||||
LuaScriptInterface:
|
LuaScript:
|
||||||
LuaScripts: gdi04b.lua
|
Scripts: gdi04b.lua
|
||||||
ObjectivesPanel:
|
ObjectivesPanel:
|
||||||
PanelName: MISSION_OBJECTIVES
|
PanelName: MISSION_OBJECTIVES
|
||||||
Player:
|
Player:
|
||||||
@@ -674,21 +659,20 @@ Rules:
|
|||||||
GenericVisibility: Enemy, Ally, Neutral
|
GenericVisibility: Enemy, Ally, Neutral
|
||||||
GenericStancePrefix: false
|
GenericStancePrefix: false
|
||||||
ShowOwnerRow: false
|
ShowOwnerRow: false
|
||||||
HARV:
|
|
||||||
-MustBeDestroyed:
|
|
||||||
E3:
|
E3:
|
||||||
AutoTarget:
|
AutoTarget:
|
||||||
ScanRadius: 5
|
ScanRadius: 5
|
||||||
CRATE:
|
CRATE:
|
||||||
Crate:
|
Crate:
|
||||||
Lifetime: 9999
|
Lifetime: 9999
|
||||||
LuaScriptEvents:
|
|
||||||
HealUnitsCrateAction:
|
HealUnitsCrateAction:
|
||||||
-RevealMapCrateAction:
|
-RevealMapCrateAction:
|
||||||
-GiveMcvCrateAction:
|
-GiveMcvCrateAction:
|
||||||
-GiveCashCrateAction:
|
-GiveCashCrateAction:
|
||||||
-ExplodeCrateAction@fire:
|
-ExplodeCrateAction@fire:
|
||||||
-GrantUpgradeCrateAction@cloak:
|
-GrantUpgradeCrateAction@cloak:
|
||||||
|
-DuplicateUnitCrateAction:
|
||||||
|
ScriptTriggers:
|
||||||
|
|
||||||
Sequences:
|
Sequences:
|
||||||
|
|
||||||
@@ -696,7 +680,7 @@ VoxelSequences:
|
|||||||
|
|
||||||
Weapons:
|
Weapons:
|
||||||
Tiberium:
|
Tiberium:
|
||||||
Warhead: SpreadDamage
|
Warhead@1Dam: SpreadDamage
|
||||||
Damage: 4
|
Damage: 4
|
||||||
|
|
||||||
Voices:
|
Voices:
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
279
mods/ra/maps/intervention/intervention.lua
Normal file
279
mods/ra/maps/intervention/intervention.lua
Normal 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
|
||||||
@@ -2205,7 +2205,7 @@ Actors:
|
|||||||
Actor14: wood
|
Actor14: wood
|
||||||
Location: 23,57
|
Location: 23,57
|
||||||
Owner: Neutral
|
Owner: Neutral
|
||||||
Camera: CAMERA
|
CameraSpot: CAMERA
|
||||||
Location: 79,137
|
Location: 79,137
|
||||||
Owner: Allies
|
Owner: Allies
|
||||||
|
|
||||||
@@ -2220,8 +2220,8 @@ Rules:
|
|||||||
-CrateSpawner:
|
-CrateSpawner:
|
||||||
-SpawnMPUnits:
|
-SpawnMPUnits:
|
||||||
-MPStartLocations:
|
-MPStartLocations:
|
||||||
LuaScriptInterface:
|
LuaScript:
|
||||||
LuaScripts: mission.lua
|
Scripts: intervention.lua
|
||||||
ObjectivesPanel:
|
ObjectivesPanel:
|
||||||
PanelName: MISSION_OBJECTIVES
|
PanelName: MISSION_OBJECTIVES
|
||||||
CAMERA:
|
CAMERA:
|
||||||
@@ -2229,17 +2229,26 @@ Rules:
|
|||||||
Range: 18c0
|
Range: 18c0
|
||||||
MISS:
|
MISS:
|
||||||
Tooltip:
|
Tooltip:
|
||||||
Name: Air Force HQ
|
Name: Soviet Air Force HQ
|
||||||
Capturable:
|
Capturable:
|
||||||
Type: building
|
Type: building
|
||||||
AllowAllies: False
|
AllowAllies: False
|
||||||
AllowNeutral: False
|
AllowNeutral: False
|
||||||
AllowEnemies: True
|
AllowEnemies: True
|
||||||
CaptureThreshold: 1.0
|
CaptureThreshold: 1.0
|
||||||
E6:
|
E6.MOD:
|
||||||
|
Inherits: E6
|
||||||
|
Buildable:
|
||||||
|
Prerequisites: ~barracks
|
||||||
|
-RepairsBridges:
|
||||||
Captures:
|
Captures:
|
||||||
CaptureTypes: building
|
CaptureTypes: building
|
||||||
Sabotage: False
|
Sabotage: False
|
||||||
|
RenderInfantry:
|
||||||
|
Image: e6
|
||||||
|
E6:
|
||||||
|
Buildable:
|
||||||
|
Prerequisites: ~disabled
|
||||||
HPAD:
|
HPAD:
|
||||||
ProvidesCustomPrerequisite:
|
ProvidesCustomPrerequisite:
|
||||||
Prerequisite: givefix
|
Prerequisite: givefix
|
||||||
@@ -2254,12 +2263,12 @@ Rules:
|
|||||||
Name: Weapons Factory or Helipad
|
Name: Weapons Factory or Helipad
|
||||||
MIG:
|
MIG:
|
||||||
Buildable:
|
Buildable:
|
||||||
Prerequisites: afld
|
Prerequisites: ~afld
|
||||||
LimitedAmmo:
|
LimitedAmmo:
|
||||||
Ammo: 2
|
Ammo: 2
|
||||||
HELI:
|
HELI:
|
||||||
Buildable:
|
Buildable:
|
||||||
Prerequisites: hpad
|
Prerequisites: ~hpad
|
||||||
Valued:
|
Valued:
|
||||||
Cost: 1500
|
Cost: 1500
|
||||||
SAM:
|
SAM:
|
||||||
@@ -2270,19 +2279,49 @@ Rules:
|
|||||||
TSLA:
|
TSLA:
|
||||||
Power:
|
Power:
|
||||||
Amount: -50
|
Amount: -50
|
||||||
^Vehicles:
|
^Building:
|
||||||
|
Tooltip:
|
||||||
|
GenericVisibility: Enemy
|
||||||
|
ShowOwnerRow: false
|
||||||
|
^Vehicle:
|
||||||
MustBeDestroyed:
|
MustBeDestroyed:
|
||||||
|
Tooltip:
|
||||||
|
GenericVisibility: Enemy
|
||||||
|
ShowOwnerRow: false
|
||||||
^Tank:
|
^Tank:
|
||||||
MustBeDestroyed:
|
MustBeDestroyed:
|
||||||
|
Tooltip:
|
||||||
|
GenericVisibility: Enemy
|
||||||
|
ShowOwnerRow: false
|
||||||
^Infantry:
|
^Infantry:
|
||||||
MustBeDestroyed:
|
MustBeDestroyed:
|
||||||
|
Tooltip:
|
||||||
|
GenericVisibility: Enemy
|
||||||
|
ShowOwnerRow: false
|
||||||
^Plane:
|
^Plane:
|
||||||
MustBeDestroyed:
|
MustBeDestroyed:
|
||||||
|
Tooltip:
|
||||||
|
GenericVisibility: Enemy
|
||||||
|
ShowOwnerRow: false
|
||||||
^Ship:
|
^Ship:
|
||||||
MustBeDestroyed:
|
MustBeDestroyed:
|
||||||
|
Tooltip:
|
||||||
|
GenericVisibility: Enemy
|
||||||
|
ShowOwnerRow: false
|
||||||
|
^Wall:
|
||||||
|
Tooltip:
|
||||||
|
ShowOwnerRow: false
|
||||||
|
^Husk:
|
||||||
|
Tooltip:
|
||||||
|
GenericVisibility: Enemy, Ally, Neutral
|
||||||
|
GenericStancePrefix: false
|
||||||
|
ShowOwnerRow: false
|
||||||
ATEK:
|
ATEK:
|
||||||
Buildable:
|
Buildable:
|
||||||
Prerequisites: ~disabled
|
Prerequisites: ~disabled
|
||||||
|
STEK:
|
||||||
|
Buildable:
|
||||||
|
Prerequisites: ~disabled
|
||||||
GAP:
|
GAP:
|
||||||
Buildable:
|
Buildable:
|
||||||
Prerequisites: ~disabled
|
Prerequisites: ~disabled
|
||||||
@@ -2292,9 +2331,24 @@ Rules:
|
|||||||
PDOX:
|
PDOX:
|
||||||
Buildable:
|
Buildable:
|
||||||
Prerequisites: ~disabled
|
Prerequisites: ~disabled
|
||||||
|
E4:
|
||||||
|
Buildable:
|
||||||
|
Prerequisites: ~disabled
|
||||||
E7:
|
E7:
|
||||||
Buildable:
|
Buildable:
|
||||||
Prerequisites: ~disabled
|
Prerequisites: ~disabled
|
||||||
|
THF:
|
||||||
|
Buildable:
|
||||||
|
Prerequisites: ~disabled
|
||||||
|
HIJACKER:
|
||||||
|
Buildable:
|
||||||
|
Prerequisites: ~disabled
|
||||||
|
SHOK:
|
||||||
|
Buildable:
|
||||||
|
Prerequisites: ~disabled
|
||||||
|
SNIPER:
|
||||||
|
Buildable:
|
||||||
|
Prerequisites: ~disabled
|
||||||
2TNK:
|
2TNK:
|
||||||
Buildable:
|
Buildable:
|
||||||
Prerequisites: ~disabled
|
Prerequisites: ~disabled
|
||||||
@@ -2310,6 +2364,9 @@ Rules:
|
|||||||
MNLY.AT:
|
MNLY.AT:
|
||||||
Buildable:
|
Buildable:
|
||||||
Prerequisites: ~disabled
|
Prerequisites: ~disabled
|
||||||
|
MNLY.AP:
|
||||||
|
Buildable:
|
||||||
|
Prerequisites: ~disabled
|
||||||
MRJ:
|
MRJ:
|
||||||
Buildable:
|
Buildable:
|
||||||
Prerequisites: ~disabled
|
Prerequisites: ~disabled
|
||||||
@@ -2319,6 +2376,9 @@ Rules:
|
|||||||
HIND:
|
HIND:
|
||||||
Buildable:
|
Buildable:
|
||||||
Prerequisites: ~disabled
|
Prerequisites: ~disabled
|
||||||
|
YAK:
|
||||||
|
Buildable:
|
||||||
|
Prerequisites: ~disabled
|
||||||
CA:
|
CA:
|
||||||
Buildable:
|
Buildable:
|
||||||
Prerequisites: ~disabled
|
Prerequisites: ~disabled
|
||||||
|
|||||||
@@ -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
|
|
||||||
Reference in New Issue
Block a user