Merge pull request #6934 from abcdefg30/survival01
Ported Survival01 to Lua
This commit is contained in:
@@ -137,9 +137,11 @@ namespace OpenRA.Traits
|
||||
var entered = currentActors.Except(oldActors);
|
||||
var exited = oldActors.Except(currentActors);
|
||||
|
||||
if (onActorEntered != null)
|
||||
foreach (var a in entered)
|
||||
onActorEntered(a);
|
||||
|
||||
if (onActorExited != null)
|
||||
foreach (var a in exited)
|
||||
onActorExited(a);
|
||||
|
||||
|
||||
@@ -408,6 +408,7 @@
|
||||
<Compile Include="Scripting\Properties\HealthProperties.cs" />
|
||||
<Compile Include="Scripting\Properties\CombatProperties.cs" />
|
||||
<Compile Include="Scripting\Properties\DiplomacyProperties.cs" />
|
||||
<Compile Include="Scripting\Properties\PowerProperties.cs" />
|
||||
<Compile Include="Scripting\Global\MapGlobal.cs" />
|
||||
<Compile Include="Scripting\Global\PlayerGlobal.cs" />
|
||||
<Compile Include="Scripting\Global\UtilsGlobal.cs" />
|
||||
|
||||
@@ -220,6 +220,68 @@ namespace OpenRA.Mods.RA.Scripting
|
||||
GetScriptTriggers(a).RegisterCallback(Trigger.OnCapture, func, context);
|
||||
}
|
||||
|
||||
[Desc("Call a function when this actor is killed or captured. " +
|
||||
"The callback function will be called as func().")]
|
||||
public void OnKilledOrCaptured(Actor a, LuaFunction func)
|
||||
{
|
||||
var called = false;
|
||||
|
||||
var copy = (LuaFunction)func.CopyReference();
|
||||
Action<Actor> OnKilledOrCaptured = m =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (called)
|
||||
return;
|
||||
|
||||
copy.Call().Dispose();
|
||||
copy.Dispose();
|
||||
called = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
context.FatalError(e.Message);
|
||||
}
|
||||
};
|
||||
|
||||
GetScriptTriggers(a).OnCapturedInternal += OnKilledOrCaptured;
|
||||
GetScriptTriggers(a).OnKilledInternal += OnKilledOrCaptured;
|
||||
}
|
||||
|
||||
[Desc("Call a function when all of the actors in a group have been killed or captured. " +
|
||||
"The callback function will be called as func().")]
|
||||
public void OnAllKilledOrCaptured(Actor[] actors, LuaFunction func)
|
||||
{
|
||||
var group = actors.ToList();
|
||||
|
||||
var copy = (LuaFunction)func.CopyReference();
|
||||
Action<Actor> OnMemberKilledOrCaptured = m =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!group.Contains(m))
|
||||
return;
|
||||
|
||||
group.Remove(m);
|
||||
if (!group.Any())
|
||||
{
|
||||
copy.Call().Dispose();
|
||||
copy.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
context.FatalError(e.Message);
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var a in group)
|
||||
{
|
||||
GetScriptTriggers(a).OnCapturedInternal += OnMemberKilledOrCaptured;
|
||||
GetScriptTriggers(a).OnKilledInternal += OnMemberKilledOrCaptured;
|
||||
}
|
||||
}
|
||||
|
||||
[Desc("Call a function when a ground-based actor enters this cell footprint." +
|
||||
"Returns the trigger id for later removal using RemoveFootprintTrigger(int id)." +
|
||||
"The callback function will be called as func(Actor a, int id).")]
|
||||
@@ -278,6 +340,64 @@ namespace OpenRA.Mods.RA.Scripting
|
||||
context.World.ActorMap.RemoveCellTrigger(id);
|
||||
}
|
||||
|
||||
[Desc("Call a function when an actor enters this range." +
|
||||
"Returns the trigger id for later removal using RemoveProximityTrigger(int id)." +
|
||||
"The callback function will be called as func(Actor a, int id).")]
|
||||
public int OnEnteredProximityTrigger(WPos pos, WRange range, LuaFunction func)
|
||||
{
|
||||
var triggerId = 0;
|
||||
var onEntry = (LuaFunction)func.CopyReference();
|
||||
Action<Actor> invokeEntry = a =>
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var luaActor = a.ToLuaValue(context))
|
||||
using (var id = triggerId.ToLuaValue(context))
|
||||
onEntry.Call(luaActor, id).Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
context.FatalError(e.Message);
|
||||
}
|
||||
};
|
||||
|
||||
triggerId = context.World.ActorMap.AddProximityTrigger(pos, range, invokeEntry, null);
|
||||
|
||||
return triggerId;
|
||||
}
|
||||
|
||||
[Desc("Call a function when an actor leaves this range." +
|
||||
"Returns the trigger id for later removal using RemoveProximityTrigger(int id)." +
|
||||
"The callback function will be called as func(Actor a, int id).")]
|
||||
public int OnExitedProximityTrigger(WPos pos, WRange range, LuaFunction func)
|
||||
{
|
||||
var triggerId = 0;
|
||||
var onExit = (LuaFunction)func.CopyReference();
|
||||
Action<Actor> invokeExit = a =>
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var luaActor = a.ToLuaValue(context))
|
||||
using (var id = triggerId.ToLuaValue(context))
|
||||
onExit.Call(luaActor, id).Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
context.FatalError(e.Message);
|
||||
}
|
||||
};
|
||||
|
||||
triggerId = context.World.ActorMap.AddProximityTrigger(pos, range, null, invokeExit);
|
||||
|
||||
return triggerId;
|
||||
}
|
||||
|
||||
[Desc("Removes a previously created proximitry trigger.")]
|
||||
public void RemoveProximityTrigger(int id)
|
||||
{
|
||||
context.World.ActorMap.RemoveProximityTrigger(id);
|
||||
}
|
||||
|
||||
[Desc("Call a function when this actor is infiltrated. The callback function " +
|
||||
"will be called as func(Actor self, Actor infiltrator).")]
|
||||
public void OnInfiltrated(Actor a, LuaFunction func)
|
||||
|
||||
73
OpenRA.Mods.RA/Scripting/Properties/PowerProperties.cs
Normal file
73
OpenRA.Mods.RA/Scripting/Properties/PowerProperties.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using Eluant;
|
||||
using OpenRA.Mods.Common.Power;
|
||||
using OpenRA.Scripting;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Scripting
|
||||
{
|
||||
[ScriptPropertyGroup("Power")]
|
||||
public class PlayerPowerProperties : ScriptPlayerProperties, Requires<PowerManagerInfo>
|
||||
{
|
||||
readonly PowerManager pm;
|
||||
|
||||
public PlayerPowerProperties(ScriptContext context, Player player)
|
||||
: base(context, player)
|
||||
{
|
||||
pm = player.PlayerActor.Trait<PowerManager>();
|
||||
}
|
||||
|
||||
[Desc("Returns the total of the power the player has.")]
|
||||
public int PowerProvided
|
||||
{
|
||||
get { return pm.PowerProvided; }
|
||||
}
|
||||
|
||||
[Desc("Returns the power used by the player.")]
|
||||
public int PowerDrained
|
||||
{
|
||||
get { return pm.PowerDrained; }
|
||||
}
|
||||
|
||||
[Desc("Returns the player's power state " +
|
||||
"(\"Normal\", \"Low\" or \"Critical\").")]
|
||||
public string PowerState
|
||||
{
|
||||
get { return pm.PowerState.ToString(); }
|
||||
}
|
||||
|
||||
[Desc("Triggers low power for the chosen amount of ticks.")]
|
||||
public void TriggerPowerOutage(int ticks)
|
||||
{
|
||||
pm.TriggerPowerOutage(ticks);
|
||||
}
|
||||
}
|
||||
|
||||
[ScriptPropertyGroup("Power")]
|
||||
public class ActorPowerProperties : ScriptActorProperties, Requires<PowerInfo>
|
||||
{
|
||||
readonly PowerInfo pi;
|
||||
|
||||
public ActorPowerProperties(ScriptContext context, Actor self)
|
||||
: base(context, self)
|
||||
{
|
||||
pi = self.Info.Traits.GetOrDefault<PowerInfo>();
|
||||
}
|
||||
|
||||
[Desc("Returns the power drained/provided by this actor.")]
|
||||
public int Power
|
||||
{
|
||||
get { return pi.Amount; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ namespace OpenRA.Mods.RA.Scripting
|
||||
readonly World world;
|
||||
|
||||
public event Action<Actor> OnKilledInternal = _ => { };
|
||||
public event Action<Actor> OnCapturedInternal = _ => { };
|
||||
public event Action<Actor> OnRemovedInternal = _ => { };
|
||||
public event Action<Actor, Actor> OnProducedInternal = (a, b) => { };
|
||||
public event Action<Actor, Actor> OnOtherProducedInternal = (a, b) => { };
|
||||
@@ -236,6 +237,9 @@ namespace OpenRA.Mods.RA.Scripting
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Run any internally bound callbacks
|
||||
OnCapturedInternal(self);
|
||||
}
|
||||
|
||||
public void Infiltrated(Actor self, Actor infiltrator)
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
readonly ScrollPanelWidget descriptionPanel;
|
||||
readonly LabelWidget description;
|
||||
readonly SpriteFont descriptionFont;
|
||||
readonly DropDownButtonWidget difficultyButton;
|
||||
readonly ButtonWidget startVideoButton;
|
||||
readonly ButtonWidget stopVideoButton;
|
||||
readonly VqaPlayerWidget videoPlayer;
|
||||
@@ -39,6 +40,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
|
||||
bool showVideoPlayer;
|
||||
|
||||
string difficulty;
|
||||
|
||||
[ObjectCreator.UseCtor]
|
||||
public MissionBrowserLogic(Widget widget, Action onStart, Action onExit)
|
||||
{
|
||||
@@ -67,6 +70,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
description = descriptionPanel.Get<LabelWidget>("MISSION_DESCRIPTION");
|
||||
descriptionFont = Game.Renderer.Fonts[description.Font];
|
||||
|
||||
difficultyButton = widget.Get<DropDownButtonWidget>("DIFFICULTY_DROPDOWNBUTTON");
|
||||
|
||||
startVideoButton = widget.Get<ButtonWidget>("START_VIDEO_BUTTON");
|
||||
stopVideoButton = widget.Get<ButtonWidget>("STOP_VIDEO_BUTTON");
|
||||
stopVideoButton.IsVisible = () => showVideoPlayer;
|
||||
@@ -176,6 +181,28 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
description.Bounds.Height = descriptionFont.Measure(text).Y;
|
||||
descriptionPanel.ScrollToTop();
|
||||
descriptionPanel.Layout.AdjustChildren();
|
||||
|
||||
difficultyButton.IsVisible = () => map.Options.Difficulties.Any();
|
||||
if (!map.Options.Difficulties.Any())
|
||||
return;
|
||||
|
||||
difficulty = map.Options.Difficulties.First();
|
||||
difficultyButton.OnMouseDown = _ =>
|
||||
{
|
||||
var options = map.Options.Difficulties.Select(d => new DropDownOption
|
||||
{
|
||||
Title = d,
|
||||
IsSelected = () => difficulty == d,
|
||||
OnClick = () => difficulty = d
|
||||
});
|
||||
Func<DropDownOption, ScrollItemWidget, ScrollItemWidget> setupItem = (option, template) =>
|
||||
{
|
||||
var item = ScrollItemWidget.Setup(template, option.IsSelected, option.OnClick);
|
||||
item.Get<LabelWidget>("LABEL").GetText = () => option.Title;
|
||||
return item;
|
||||
};
|
||||
difficultyButton.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", options.Count() * 30, options, setupItem);
|
||||
};
|
||||
}
|
||||
|
||||
void StopVideo()
|
||||
@@ -202,6 +229,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
Action lobbyReady = null;
|
||||
lobbyReady = () =>
|
||||
{
|
||||
om.IssueOrder(Order.Command("difficulty {0}".F(difficulty)));
|
||||
Game.LobbyInfoChanged -= lobbyReady;
|
||||
onStart();
|
||||
om.IssueOrder(Order.Command("state {0}".F(Session.ClientState.Ready)));
|
||||
@@ -210,5 +238,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
||||
|
||||
om = Game.JoinServer(IPAddress.Loopback.ToString(), Game.CreateLocalServer(selectedMapPreview.Uid), "", false);
|
||||
}
|
||||
|
||||
class DropDownOption
|
||||
{
|
||||
public string Title;
|
||||
public Func<bool> IsSelected;
|
||||
public Action OnClick;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Red Alert Lua scripts", "Re
|
||||
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\monster-tank-madness\monster-tank-madness.lua = mods\ra\maps\monster-tank-madness\monster-tank-madness.lua
|
||||
mods\ra\maps\survival01\survival01.lua = mods\ra\maps\survival01\survival01.lua
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "System Lua scripts", "System Lua scripts", "{A4D6AEA4-8009-4256-903B-8D227E50452B}"
|
||||
|
||||
@@ -102,6 +102,13 @@ Container@MISSIONBROWSER_PANEL:
|
||||
Height: 35
|
||||
Text: Play
|
||||
Font: Bold
|
||||
DropDownButton@DIFFICULTY_DROPDOWNBUTTON:
|
||||
X: PARENT_RIGHT - 290 - 150
|
||||
Y: 376
|
||||
Width: 140
|
||||
Height: 35
|
||||
Text: Difficulty
|
||||
Font: Bold
|
||||
Container@MISSION_BIN:
|
||||
Children:
|
||||
VqaPlayer@MISSION_VIDEO:
|
||||
|
||||
@@ -98,6 +98,13 @@ Background@MISSIONBROWSER_PANEL:
|
||||
Text: Back
|
||||
Font: Bold
|
||||
Key: escape
|
||||
DropDownButton@DIFFICULTY_DROPDOWNBUTTON:
|
||||
X: PARENT_RIGHT - 140 - 130 - 150
|
||||
Y: PARENT_BOTTOM - 45
|
||||
Width: 140
|
||||
Height: 25
|
||||
Text: Difficulty
|
||||
Font: Bold
|
||||
Background@MISSION_BIN:
|
||||
X: 20
|
||||
Y: 50
|
||||
|
||||
@@ -115,6 +115,8 @@ WorldLoaded = function()
|
||||
ukraine.AddPrimaryObjective("Destroy the convoy.")
|
||||
end)
|
||||
|
||||
Trigger.AfterDelay(DateTime.Seconds(1), function() Media.PlaySpeechNotification(allies, "MissionTimerInitialised") end)
|
||||
|
||||
RunInitialActivities()
|
||||
|
||||
SendConstructionVehicleReinforcements()
|
||||
|
||||
@@ -9,11 +9,21 @@ BeachheadTrigger =
|
||||
CPos.New(137, 104), CPos.New(137, 105), CPos.New(137, 106), CPos.New(136, 106), CPos.New(136, 107)
|
||||
}
|
||||
|
||||
BaseRaidInterval = DateTime.Minutes(3)
|
||||
BaseFrontAttackInterval = DateTime.Minutes(3) + DateTime.Seconds(30)
|
||||
BaseRearAttackInterval = DateTime.Minutes(8)
|
||||
UBoatPatrolDelay = DateTime.Minutes(2) + DateTime.Seconds(30)
|
||||
BaseFrontAttackWpts = { PatrolWpt1.Location, BaseRaidWpt1.Location }
|
||||
Difficulty = Map.Difficulty
|
||||
|
||||
if Difficulty == "Medium" then
|
||||
BaseRaidInterval = DateTime.Minutes(3)
|
||||
BaseFrontAttackInterval = DateTime.Minutes(3) + DateTime.Seconds(30)
|
||||
BaseRearAttackInterval = DateTime.Minutes(8)
|
||||
UBoatPatrolDelay = DateTime.Minutes(2) + DateTime.Seconds(30)
|
||||
BaseFrontAttackWpts = { PatrolWpt1.Location, BaseRaidWpt1.Location }
|
||||
else
|
||||
BaseRaidInterval = DateTime.Minutes(2)
|
||||
BaseFrontAttackInterval = DateTime.Minutes(2) + DateTime.Seconds(30)
|
||||
BaseRearAttackInterval = DateTime.Minutes(5)
|
||||
UBoatPatrolDelay = DateTime.Minutes(2)
|
||||
BaseFrontAttackWpts = { PatrolWpt1.Location }
|
||||
end
|
||||
|
||||
Village = { FarmHouse1, FarmHouse2, FarmHouse3, FarmHouse4, FarmHouse5, FarmHouse6, FarmHouse7, FarmHouse8, FarmHouse9, Church }
|
||||
VillageRaidInterval = DateTime.Minutes(3)
|
||||
@@ -224,7 +234,7 @@ WorldLoaded = function()
|
||||
|
||||
sovietObjective = soviets.AddPrimaryObjective("Destroy the village.")
|
||||
villageObjective = player.AddPrimaryObjective("Save the village.")
|
||||
beachheadObjective = player.AddSecondaryObjective("Get your MCV to the main island.")
|
||||
beachheadObjective = player.AddPrimaryObjective("Get your MCV to the main island.")
|
||||
|
||||
beachheadTrigger = false
|
||||
Trigger.OnExitedFootprint(BeachheadTrigger, function(a, id)
|
||||
@@ -234,6 +244,17 @@ WorldLoaded = function()
|
||||
player.MarkCompletedObjective(beachheadObjective)
|
||||
|
||||
captureObjective = player.AddPrimaryObjective("Locate and capture the enemy's Air Force HQ.")
|
||||
|
||||
if AirForceHQ.IsDead then
|
||||
player.MarkFailedObjective(captureObjective)
|
||||
return
|
||||
end
|
||||
if AirForceHQ.Owner == player then
|
||||
player.MarkCompletedObjective(captureObjective)
|
||||
player.MarkCompletedObjective(villageObjective)
|
||||
return
|
||||
end
|
||||
|
||||
Trigger.OnCapture(AirForceHQ, function()
|
||||
Trigger.AfterDelay(DateTime.Seconds(3), function()
|
||||
player.MarkCompletedObjective(captureObjective)
|
||||
@@ -242,6 +263,8 @@ WorldLoaded = function()
|
||||
end)
|
||||
Trigger.OnKilled(AirForceHQ, function() player.MarkFailedObjective(captureObjective) end)
|
||||
|
||||
Actor.Create("mainland", true, { Owner = player })
|
||||
|
||||
Trigger.AfterDelay(BaseFrontAttackInterval, function()
|
||||
Build(BaseFrontAttackUnits, BaseFrontAttack)
|
||||
ParadropSovietUnits()
|
||||
|
||||
@@ -2248,10 +2248,23 @@ Rules:
|
||||
E6:
|
||||
Buildable:
|
||||
Prerequisites: ~disabled
|
||||
HPAD:
|
||||
TENT:
|
||||
Buildable:
|
||||
Prerequisites: anypower, ~structures.allies, ~techlevel.infonly, mainland
|
||||
DOME:
|
||||
Buildable:
|
||||
Prerequisites: proc, ~techlevel.medium, mainland
|
||||
WEAP:
|
||||
Buildable:
|
||||
Prerequisites: proc, ~techlevel.low, mainland
|
||||
ProvidesCustomPrerequisite:
|
||||
Prerequisite: givefix
|
||||
WEAP:
|
||||
MAINLAND:
|
||||
Tooltip:
|
||||
Name: Reach the mainland
|
||||
ProvidesCustomPrerequisite:
|
||||
Prerequisite: mainland
|
||||
HPAD:
|
||||
ProvidesCustomPrerequisite:
|
||||
Prerequisite: givefix
|
||||
FIX:
|
||||
|
||||
BIN
mods/ra/maps/survival01/map.bin
Normal file
BIN
mods/ra/maps/survival01/map.bin
Normal file
Binary file not shown.
BIN
mods/ra/maps/survival01/map.png
Normal file
BIN
mods/ra/maps/survival01/map.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
1367
mods/ra/maps/survival01/map.yaml
Normal file
1367
mods/ra/maps/survival01/map.yaml
Normal file
File diff suppressed because it is too large
Load Diff
392
mods/ra/maps/survival01/survival01.lua
Normal file
392
mods/ra/maps/survival01/survival01.lua
Normal file
@@ -0,0 +1,392 @@
|
||||
Difficulty = Map.Difficulty
|
||||
|
||||
if Difficulty == "Easy" then
|
||||
AttackAtFrameIncrement = DateTime.Seconds(22)
|
||||
AttackAtFrameIncrementInf = DateTime.Seconds(16)
|
||||
TimerTicks = DateTime.Minutes(15)
|
||||
IncrementTurningPoint = TimerTicks / 2
|
||||
DamageModifier = 0.5
|
||||
LongBowReinforcements = { "heli", "heli" }
|
||||
ParadropArtillery = true
|
||||
elseif Difficulty == "Medium" then
|
||||
AttackAtFrameIncrement = DateTime.Seconds(18)
|
||||
AttackAtFrameIncrementInf = DateTime.Seconds(12)
|
||||
TimerTicks = DateTime.Minutes(20)
|
||||
IncrementTurningPoint = TimerTicks / 2
|
||||
MoreParas = true
|
||||
DamageModifier = 0.75
|
||||
LongBowReinforcements = { "heli", "heli" }
|
||||
else --Difficulty == "Hard"
|
||||
AttackAtFrameIncrement = DateTime.Seconds(14)
|
||||
AttackAtFrameIncrementInf = DateTime.Seconds(8)
|
||||
TimerTicks = DateTime.Minutes(25)
|
||||
IncrementTurningPoint = DateTime.Minutes(10)
|
||||
MoreParas = true
|
||||
AttackAtFrameNaval = DateTime.Minutes(3) + DateTime.Seconds(45)
|
||||
SpawnNavalUnits = true
|
||||
DamageModifier = 1
|
||||
LongBowReinforcements = { "heli" }
|
||||
end
|
||||
|
||||
AlliedArtilleryParadrops = { "arty", "arty", "arty" }
|
||||
AlliedAirReinforcementsWaypoints =
|
||||
{
|
||||
{ AirReinforcementsEntry1.Location, AirReinforcementsEntry2.Location },
|
||||
{ AirReinforcementsRally1.Location, AirReinforcementsRally2.Location }
|
||||
}
|
||||
FrenchReinforcements = { "2tnk", "2tnk", "2tnk", "2tnk", "2tnk", "1tnk", "1tnk", "1tnk", "arty", "arty", "arty", "jeep", "jeep" }
|
||||
|
||||
SpawningSovietUnits = true
|
||||
SpawningInfantry = true
|
||||
AttackAtFrameInf = DateTime.Seconds(12)
|
||||
AttackAtFrame = DateTime.Seconds(18)
|
||||
SovietAttackGroupSize = 5
|
||||
SovietInfantryGroupSize = 7
|
||||
FactoryClearRange = 10
|
||||
ParadropTicks = DateTime.Seconds(30)
|
||||
BadgerPassengers = { "e1", "e1", "e1", "e2", "e2" }
|
||||
ParadropWaypoints =
|
||||
{
|
||||
{ BadgerEntryPoint1.Location, ParaDrop1.Location },
|
||||
{ BadgerEntryPoint2.Location, ParaDrop2.Location },
|
||||
{ BadgerEntryPoint1.Location, Alliesbase2.Location },
|
||||
{ BadgerEntryPoint2.Location, Alliesbase1.Location }
|
||||
}
|
||||
NavalTransportPassengers = { "e1", "e1", "e2", "e4", "e4" }
|
||||
NavalReinforcementsWaypoints = { NavalWaypoint1, NavalWaypoint2, NavalWaypoint2, NavalWaypoint3 }
|
||||
Squad1 = { "e1", "e1" }
|
||||
Squad2 = { "e2", "e2" }
|
||||
SovietVehicles = { "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "3tnk", "v2rl", "v2rl", "ftrk", "ftrk", "ftrk", "apc", "apc" }
|
||||
SovietInfantry = { "e1", "e1", "e1", "e1", "e2", "e2", "e2", "e4", "e4", "e3" }
|
||||
SovietEntryPoints = { SovietEntryPoint1, SovietEntryPoint2, SovietEntryPoint3, SovietEntryPoint4, SovietEntryPoint5 }
|
||||
SovietRallyPoints = { SovietRallyPoint1, SovietRallyPoint2, SovietRallyPoint3, SovietRallyPoint4, SovietRallyPoint5 }
|
||||
SovietGateRallyPoints = { AlliesBaseGate2, AlliesBaseGate2, AlliesBaseGate1, AlliesBaseGate1, AlliesBaseGate1 }
|
||||
|
||||
Airfields = { SovietAirfield1, SovietAirfield2, SovietAirfield3 }
|
||||
SovietBuildings = { Barrack1, SubPen, RadarDome, AdvancedPowerPlant1, AdvancedPowerPlant2, AdvancedPowerPlant3, WarFactory, Refinery, Silo1, Silo2, FlameTower1, FlameTower2, FlameTower3, Sam1, Sam2, Sam3, Sam4, SovietAirfield1, SovietAirfield2, SovietAirfield3 }
|
||||
|
||||
IdleTrigger = function(units, dest)
|
||||
Utils.Do(units, function(unit)
|
||||
Trigger.OnIdle(unit, function()
|
||||
local bool = Utils.All(units, function(unit) return unit.IsIdle end)
|
||||
if bool then
|
||||
Utils.Do(units, function(unit)
|
||||
if not unit.IsDead then
|
||||
Trigger.ClearAll(unit)
|
||||
Trigger.AfterDelay(0, function()
|
||||
if not unit.IsDead then
|
||||
if dest then unit.AttackMove(dest, 3) end
|
||||
Trigger.OnIdle(unit, unit.Hunt)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end)
|
||||
Trigger.OnDamaged(unit, function()
|
||||
Utils.Do(units, function(unit)
|
||||
if not unit.IsDead then
|
||||
Trigger.ClearAll(unit)
|
||||
Trigger.AfterDelay(0, function()
|
||||
if not unit.IsDead then Trigger.OnIdle(unit, unit.Hunt) end
|
||||
end)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if KillObj and soviets.HasNoRequiredUnits() then
|
||||
allies.MarkCompletedObjective(KillObj)
|
||||
end
|
||||
|
||||
if allies.HasNoRequiredUnits() then
|
||||
soviets.MarkCompletedObjective(SovietObj)
|
||||
end
|
||||
|
||||
if soviets.Resources > soviets.ResourceCapacity / 2 then
|
||||
soviets.Resources = soviets.ResourceCapacity / 2
|
||||
end
|
||||
|
||||
if DateTime.Minutes(20) == TimerTicks - DateTime.GameTime then
|
||||
Media.PlaySpeechNotification(allies, "TwentyMinutesRemaining")
|
||||
elseif DateTime.Minutes(10) == TimerTicks - DateTime.GameTime then
|
||||
Media.PlaySpeechNotification(allies, "TenMinutesRemaining")
|
||||
elseif DateTime.Minutes(5) == TimerTicks - DateTime.GameTime then
|
||||
Media.PlaySpeechNotification(allies, "WarningFiveMinutesRemaining")
|
||||
InitTimer()
|
||||
end
|
||||
end
|
||||
|
||||
SendSovietParadrops = function(table)
|
||||
local plane = Actor.Create("badr", true, { Owner = soviets, Location = table[1] })
|
||||
Utils.Do(BadgerPassengers, function(type)
|
||||
local unit = Actor.Create(type, false, { Owner = soviets })
|
||||
plane.LoadPassenger(unit)
|
||||
Trigger.OnIdle(unit, unit.Hunt)
|
||||
end)
|
||||
plane.Paradrop(table[2])
|
||||
end
|
||||
|
||||
SendSovietNavalReinforcements = function()
|
||||
if SpawnNavalUnits then
|
||||
local entry = NavalEntryPoint.Location
|
||||
local units = Reinforcements.ReinforceWithTransport(soviets, "lst", NavalTransportPassengers, { entry, Utils.Random(NavalReinforcementsWaypoints).Location }, { entry })[2]
|
||||
Utils.Do(units, function(unit)
|
||||
Trigger.OnIdle(unit, unit.Hunt)
|
||||
end)
|
||||
|
||||
local delay = Utils.RandomInteger(AttackAtFrameNaval, AttackAtFrameNaval + DateTime.Minutes(2))
|
||||
|
||||
Trigger.AfterDelay(delay, SendSovietNavalReinforcements)
|
||||
end
|
||||
end
|
||||
|
||||
SpawnSovietInfantry = function()
|
||||
local units = { }
|
||||
for i = 0, SovietInfantryGroupSize - 1, 1 do
|
||||
local type = Utils.Random(SovietInfantry)
|
||||
units[i] = type
|
||||
end
|
||||
|
||||
soviets.Build(units, function(soldiers)
|
||||
Trigger.AfterDelay(25, function() IdleTrigger(soldiers) end)
|
||||
end)
|
||||
end
|
||||
|
||||
SpawnSovietUnits = function()
|
||||
local units = { }
|
||||
for i = 0, SovietAttackGroupSize - 1, 1 do
|
||||
local type = Utils.Random(SovietVehicles)
|
||||
units[i] = type
|
||||
end
|
||||
|
||||
local route = Utils.RandomInteger(1, #SovietEntryPoints + 1)
|
||||
local attackers = Reinforcements.Reinforce(soviets, units, { SovietEntryPoints[route].Location, SovietRallyPoints[route].Location })
|
||||
Trigger.AfterDelay(25, function()
|
||||
IdleTrigger(attackers, SovietGateRallyPoints[route].Location)
|
||||
end)
|
||||
end
|
||||
|
||||
SendInfantryWave = function()
|
||||
if SpawningInfantry then
|
||||
SpawnSovietInfantry()
|
||||
|
||||
if DateTime.GameTime < IncrementTurningPoint then
|
||||
AttackAtFrameIncrementInf = AttackAtFrameIncrementInf + Utils.RandomInteger(DateTime.Seconds(2), DateTime.Seconds(3))
|
||||
elseif not (AttackAtFrameIncrementInf <= DateTime.Seconds(4)) then
|
||||
AttackAtFrameIncrementInf = AttackAtFrameIncrementInf - Utils.RandomInteger(DateTime.Seconds(2), DateTime.Seconds(3))
|
||||
end
|
||||
|
||||
Trigger.AfterDelay(AttackAtFrameInf + AttackAtFrameIncrementInf, SendInfantryWave)
|
||||
end
|
||||
end
|
||||
|
||||
SendVehicleWave = function()
|
||||
if SpawningSovietUnits then
|
||||
SpawnSovietUnits()
|
||||
|
||||
if DateTime.GameTime < IncrementTurningPoint then
|
||||
AttackAtFrameIncrement = AttackAtFrameIncrement + Utils.RandomInteger(DateTime.Seconds(4), DateTime.Seconds(6))
|
||||
elseif not (AttackAtFrameIncrement <= DateTime.Seconds(4)) then
|
||||
AttackAtFrameIncrement = AttackAtFrameIncrement - Utils.RandomInteger(DateTime.Seconds(4), DateTime.Seconds(6))
|
||||
end
|
||||
|
||||
Trigger.AfterDelay(AttackAtFrame + AttackAtFrameIncrement, SendVehicleWave)
|
||||
end
|
||||
end
|
||||
|
||||
InitTimer = function()
|
||||
Trigger.AfterDelay(DateTime.Minutes(1), function()
|
||||
Media.PlaySpeechNotification(allies, "WarningFourMinutesRemaining")
|
||||
|
||||
Trigger.AfterDelay(ParadropTicks, function()
|
||||
SendSovietParadrops(ParadropWaypoints[3])
|
||||
SendSovietParadrops(ParadropWaypoints[2])
|
||||
end)
|
||||
Trigger.AfterDelay(ParadropTicks * 2, function()
|
||||
SendSovietParadrops(ParadropWaypoints[4])
|
||||
SendSovietParadrops(ParadropWaypoints[1])
|
||||
end)
|
||||
end)
|
||||
|
||||
Trigger.AfterDelay(DateTime.Minutes(2), function() Media.PlaySpeechNotification(allies, "WarningThreeMinutesRemaining") end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(3), function()
|
||||
Media.PlaySpeechNotification(allies, "WarningTwoMinutesRemaining")
|
||||
|
||||
AttackAtFrameIncrement = DateTime.Seconds(4)
|
||||
AttackAtFrameIncrementInf = DateTime.Seconds(4)
|
||||
end)
|
||||
|
||||
Trigger.AfterDelay(DateTime.Minutes(4), function() Media.PlaySpeechNotification(allies, "WarningOneMinuteRemaining") end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(4) + DateTime.Seconds(45), function() Media.PlaySpeechNotification(allies, "AlliedForcesApproaching") end)
|
||||
Trigger.AfterDelay(DateTime.Minutes(5), TimerExpired)
|
||||
end
|
||||
|
||||
TimerExpired = function()
|
||||
SpawningSovietUnits = false
|
||||
SpawningInfantry = false
|
||||
SpawnNavalUnits = false
|
||||
|
||||
Media.PlaySpeechNotification(allies, "AlliedReinforcementsArrived")
|
||||
Reinforcements.Reinforce(allies, FrenchReinforcements, { SovietEntryPoint7.Location, Alliesbase.Location })
|
||||
|
||||
if DestroyObj then
|
||||
KillObj = allies.AddPrimaryObjective("Take control of French reinforcements and\nkill all remaining soviet forces.")
|
||||
else
|
||||
DestroyObj = allies.AddPrimaryObjective("Take control of French reinforcements and\ndismantle the nearby Soviet base.")
|
||||
end
|
||||
|
||||
allies.MarkCompletedObjective(SurviveObj)
|
||||
if not allies.IsObjectiveCompleted(KillSams) then
|
||||
allies.MarkFailedObjective(KillSams)
|
||||
end
|
||||
end
|
||||
|
||||
DropAlliedArtillery = function(table)
|
||||
local plane = Actor.Create("badr", true, { Owner = allies, Location = table[1] })
|
||||
Utils.Do(AlliedArtilleryParadrops, function(type)
|
||||
local unit = Actor.Create(type, false, { Owner = allies })
|
||||
plane.LoadPassenger(unit)
|
||||
end)
|
||||
plane.Paradrop(table[2])
|
||||
end
|
||||
|
||||
SendLongBowReinforcements = function()
|
||||
Media.PlaySpeechNotification(allies, "AlliedReinforcementsArrived")
|
||||
Reinforcements.Reinforce(allies, LongBowReinforcements, AlliedAirReinforcementsWaypoints[1])
|
||||
Reinforcements.Reinforce(allies, LongBowReinforcements, AlliedAirReinforcementsWaypoints[2])
|
||||
if ParadropArtillery then
|
||||
DropAlliedArtillery({ Utils.Random(AlliedAirReinforcementsWaypoints)[1], Alliesbase.Location })
|
||||
end
|
||||
end
|
||||
|
||||
InitObjectives = function()
|
||||
Trigger.OnObjectiveAdded(allies, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective")
|
||||
end)
|
||||
|
||||
SurviveObj = allies.AddPrimaryObjective("Enforce your position and hold-out the onslaught\nuntil reinforcements arrive.")
|
||||
KillSams = allies.AddSecondaryObjective("Destroy the two SAM Sites before reinforcements\narrive.")
|
||||
Media.DisplayMessage("The soviets are blocking our GPS. We need to investigate their new technology.")
|
||||
CaptureAirfields = allies.AddSecondaryObjective("Capture and hold the soviet airbase\nin the north east.")
|
||||
SovietObj = soviets.AddPrimaryObjective("Eliminate all Allied forces.")
|
||||
|
||||
Trigger.OnObjectiveCompleted(allies, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective completed")
|
||||
end)
|
||||
Trigger.OnObjectiveFailed(allies, function(p, id)
|
||||
Media.DisplayMessage(p.GetObjectiveDescription(id), "Objective failed")
|
||||
end)
|
||||
|
||||
Trigger.OnPlayerLost(allies, function()
|
||||
Media.PlaySpeechNotification(allies, "Lose")
|
||||
end)
|
||||
Trigger.OnPlayerWon(allies, function()
|
||||
Media.PlaySpeechNotification(allies, "Win")
|
||||
Media.DisplayMessage("The French forces have survived and dismantled the soviet presence in the area!")
|
||||
end)
|
||||
end
|
||||
|
||||
InitMission = function()
|
||||
Camera.Position = Alliesbase.CenterPosition
|
||||
camera1 = Actor.Create("camera.sam", true, { Owner = allies, Location = Sam1.Location })
|
||||
camera2 = Actor.Create("camera.sam", true, { Owner = allies, Location = Sam2.Location })
|
||||
Trigger.OnKilled(Sam1, function()
|
||||
if camera1.IsInWorld then camera1.Destroy() end
|
||||
end)
|
||||
Trigger.OnKilled(Sam2, function()
|
||||
if camera2.IsInWorld then camera2.Destroy() end
|
||||
end)
|
||||
Trigger.OnAllKilledOrCaptured({ Sam1, Sam2 }, function()
|
||||
if not allies.IsObjectiveFailed(KillSams) then
|
||||
allies.MarkCompletedObjective(KillSams)
|
||||
SendLongBowReinforcements()
|
||||
end
|
||||
end)
|
||||
|
||||
local count = 0
|
||||
Utils.Do(Airfields, function(field)
|
||||
Trigger.OnCapture(field, function()
|
||||
count = count + 1
|
||||
if count == #Airfields then
|
||||
allies.MarkCompletedObjective(CaptureAirfields)
|
||||
local atek = Actor.Create("atek.mission", true, { Owner = allies, Location = HiddenATEK.Location })
|
||||
Trigger.AfterDelay(DateTime.Seconds(5), atek.Destroy)
|
||||
end
|
||||
end)
|
||||
Trigger.OnKilled(field, function()
|
||||
allies.MarkFailedObjective(CaptureAirfields)
|
||||
end)
|
||||
end)
|
||||
|
||||
Trigger.OnAllKilledOrCaptured(SovietBuildings, function()
|
||||
if DestroyObj then
|
||||
if not soviets.HasNoRequiredUnits() then
|
||||
KillObj = allies.AddPrimaryObjective("Kill all remaining soviet forces.")
|
||||
end
|
||||
allies.MarkCompletedObjective(DestroyObj)
|
||||
else
|
||||
DestroyObj = allies.AddPrimaryObjective("Dismantle the nearby Soviet base.")
|
||||
allies.MarkCompletedObjective(DestroyObj)
|
||||
end
|
||||
end)
|
||||
|
||||
Trigger.AfterDelay(DateTime.Seconds(1), function() Media.PlaySpeechNotification(allies, "MissionTimerInitialised") end)
|
||||
end
|
||||
|
||||
SetupSoviets = function()
|
||||
Barrack1.IsPrimaryBuilding = true
|
||||
Barrack1.RallyPoint = SovietInfantryRally1.Location
|
||||
Trigger.OnKilledOrCaptured(Barrack1, function()
|
||||
SpawningInfantry = false
|
||||
end)
|
||||
|
||||
Trigger.AfterDelay(0, function()
|
||||
local buildings = Map.ActorsInBox(Map.TopLeft, Map.BottomRight, function(self) return self.Owner == soviets and self.HasProperty("StartBuildingRepairs") end)
|
||||
Utils.Do(buildings, function(actor)
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Owner == soviets and building.Health < building.MaxHealth * DamageModifier then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
Reinforcements.Reinforce(soviets, Squad1, { AlliesBaseGate1.Location, Alliesbase1.Location })
|
||||
Reinforcements.Reinforce(soviets, Squad2, { AlliesBaseGate2.Location, Alliesbase2.Location })
|
||||
|
||||
Trigger.AfterDelay(ParadropTicks, function()
|
||||
SendSovietParadrops(ParadropWaypoints[1])
|
||||
SendSovietParadrops(ParadropWaypoints[2])
|
||||
end)
|
||||
Trigger.AfterDelay(ParadropTicks * 2, function()
|
||||
SendSovietParadrops(ParadropWaypoints[3])
|
||||
SendSovietParadrops(ParadropWaypoints[4])
|
||||
end)
|
||||
|
||||
Trigger.AfterDelay(AttackAtFrame, SendVehicleWave)
|
||||
Trigger.AfterDelay(AttackAtFrameInf, SendInfantryWave)
|
||||
|
||||
if MoreParas then
|
||||
local delay = Utils.RandomInteger(TimerTicks/3, TimerTicks*2/3)
|
||||
Trigger.AfterDelay(delay, function()
|
||||
SendSovietParadrops(ParadropWaypoints[Utils.RandomInteger(1,3)])
|
||||
SendSovietParadrops(ParadropWaypoints[Utils.RandomInteger(3,5)])
|
||||
end)
|
||||
end
|
||||
if SpawnNavalUnits then
|
||||
Trigger.AfterDelay(AttackAtFrameNaval, SendSovietNavalReinforcements)
|
||||
end
|
||||
end
|
||||
|
||||
WorldLoaded = function()
|
||||
|
||||
allies = Player.GetPlayer("Allies")
|
||||
soviets = Player.GetPlayer("Soviets")
|
||||
|
||||
InitObjectives()
|
||||
InitMission()
|
||||
SetupSoviets()
|
||||
end
|
||||
@@ -47,6 +47,7 @@ Speech:
|
||||
WarningFiveMinutesRemaining: 5minr
|
||||
ControlCenterDeactivated: cntlded1
|
||||
OperationControlTerminated: opterm1
|
||||
MissionTimerInitialised: mtimein1
|
||||
|
||||
Sounds:
|
||||
Notifications:
|
||||
|
||||
Reference in New Issue
Block a user