--[[ Copyright 2007-2020 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, either version 3 of the License, or (at your option) any later version. For more information, see COPYING. ]] TimerTicks = DateTime.Minutes(8) Squad1 = { FirstSquad1, FirstSquad2, FirstSquad3 } Squad2 = { SecondSquad1, SecondSquad2, SecondSquad3 } PatrolMammothPath = { Patrol1.Location, Patrol2.Location, Patrol3.Location, Patrol4.Location, Patrol5.Location, Patrol6.Location, Patrol7.Location } ConvoyEscape = { CPos.New(113, 42), CPos.New(117, 71) } ConvoyUnits = { easy = { { "e2", "e2", "e2", "truk", "truk", "truk" }, { "3tnk", "3tnk", "truk", "truk", "truk" } }, normal = { { "3tnk", "3tnk", "3tnk", "truk", "truk", "truk" }, { "3tnk", "v2rl", "e2", "e1", "e1", "truk", "truk", "truk" } }, hard = { { "3tnk", "3tnk", "3tnk", "3tnk", "truk", "truk", "truk" }, { "3tnk", "v2rl", "v2rl", "e1", "e1", "e4", "e4", "truk", "truk", "truk", "4tnk" }, { "ttnk", "ttnk", "ttnk", "shok", "shok", "shok", "shok", "truk", "truk", "truk" } } } BaseConvoyUnits = { "3tnk", "ttnk", "ttnk", "ttnk", "truk", "truk", "truk" } FinalConvoyUnits = { "3tnk", "3tnk", "3tnk", "3tnk", "truk", "truk", "truk", "4tnk" } AttackPaths = { { ExitNorth.Location }, { ExitEast.Location }, { AttackEntry1.Location }, { AttackEntry2.Location } } AttackWaveUnits = { { "3tnk", "3tnk" }, { "e1", "e1", "e1", "e2", "e2", "e4", "e4" }, { "shok", "shok", "shok", "shok", "shok" }, { "ttnk", "ttnk" }, { "4tnk", "e1", "e1", "e2" }, { "v2rl", "v2rl", "ftrk", "ftrk", "ftrk" } } ConvoyPaths = { { NorthwestEntry.Location, NorthwestPath1.Location, NorthwestBridge.Location, Patrol7.Location, Patrol6.Location, NortheastBridge.Location, NorthwestPath3.Location, ExitNorth.Location }, { CenterEntry.Location, CenterPath1.Location, CenterPath2.Location, Patrol1.Location, Patrol7.Location, Patrol6.Location, NortheastBridge.Location, NorthwestPath3.Location, ExitNorth.Location }, { CenterEntry.Location, CenterPath1.Location, CenterPath2.Location, Patrol1.Location, Patrol2.Location, SouthPath2.Location, SoutheastBridge.Location, SouthPath3.Location, ExitEast.Location }, { SouthEntry.Location, SouthPath1.Location, Patrol2.Location, SouthPath2.Location, SoutheastBridge.Location, SouthPath3.Location, ExitEast.Location } } BaseConvoyPath = { BaseEntry.Location, BasePath1.Location, CenterPath2.Location, Patrol1.Location, Patrol7.Location, Patrol6.Location, NortheastBridge.Location, NorthwestPath3.Location, ExitNorth.Location } FinalConvoyPath = { NorthEntry.Location, Patrol7.Location, Patrol6.Location, Patrol5.Location, FinalConvoy1.Location, ExitEast.Location } OpeningMoves = function() Utils.Do(Squad1, function(actor) actor.AttackMove(AlliedBase.Location) end) Utils.Do(Squad2, function(actor) actor.AttackMove(AlliedBase.Location) end) PatrolMammoth.Patrol(PatrolMammothPath, true, 10) end AttackWaveDelays = { easy = { DateTime.Seconds(40), DateTime.Seconds(80) }, normal = { DateTime.Seconds(30), DateTime.Seconds(60) }, hard = { DateTime.Seconds(20), DateTime.Seconds(40) } } AttackWaves = function() local attackpath = Utils.Random(AttackPaths) local attackers = Reinforcements.Reinforce(USSR, Utils.Random(AttackWaveUnits), { attackpath[1] }) Utils.Do(attackers, function(unit) Trigger.OnAddedToWorld(unit, function() unit.AttackMove(AlliedBase.Location) IdleHunt(unit) end) end) Trigger.AfterDelay(Utils.RandomInteger(AttackWaveDelay[1], AttackWaveDelay[2]), AttackWaves) end ConvoyWaves = { easy = 2, normal = 3, hard = 4 } ConvoysPassed = 0 SendConvoys = function() ConvoysSent = true Media.PlaySpeechNotification(Allies, "ConvoyApproaching") local path = Utils.Random(ConvoyPaths) local units = Reinforcements.Reinforce(USSR, Utils.Random(ConvoyUnits), { path[1] }) local lastWaypoint = path[#path] Utils.Do(units, function(unit) Trigger.OnAddedToWorld(unit, function() if unit.Type == "truk" then Utils.Do(path, function(waypoint) unit.Move(waypoint) end) Trigger.OnIdle(unit, function() unit.Move(lastWaypoint) end) else unit.Patrol(path) Trigger.OnIdle(unit, function() unit.AttackMove(lastWaypoint) end) end end) end) ConvoysPassed = ConvoysPassed + 1 if ConvoysPassed <= ConvoyWaves[Map.LobbyOption("difficulty")] then Trigger.AfterDelay(DateTime.Seconds(90), SendConvoys) else FinalTrucks() end end FinalTrucks = function() Trigger.AfterDelay(DateTime.Minutes(1), function() Media.PlaySpeechNotification(Allies, "ConvoyApproaching") local basePath = BaseConvoyPath local baseWaypoint = basePath[#basePath] local baseConvoy = Reinforcements.Reinforce(USSR, BaseConvoyUnits, { basePath[1] }) Utils.Do(baseConvoy, function(unit) Trigger.OnAddedToWorld(unit, function() Utils.Do(basePath, function(waypoint) unit.Move(waypoint) end) Trigger.OnIdle(unit, function() unit.Move(baseWaypoint) end) end) end) end) Trigger.AfterDelay(DateTime.Minutes(2), function() Media.PlaySpeechNotification(Allies, "ConvoyApproaching") local finalPath = FinalConvoyPath local finalWaypoint = finalPath[#finalPath] local finalConvoy = Reinforcements.Reinforce(USSR, FinalConvoyUnits, { finalPath[1] }) Utils.Do(finalConvoy, function(unit) Trigger.OnAddedToWorld(unit, function() Utils.Do(finalPath, function(waypoint) unit.Move(waypoint) end) Trigger.OnIdle(unit, function() unit.Move(finalWaypoint) end) end) end) Trigger.OnAllKilled(Utils.Where(finalConvoy, function(a) return a.Type == "truk" end), function() Allies.MarkCompletedObjective(StopTrucks) end) end) end ConvoyExit = function() Trigger.OnEnteredFootprint(ConvoyEscape, function(actor, id) if actor.Owner == USSR and actor.Type == "truk" then actor.Stop() actor.Destroy() Allies.MarkFailedObjective(StopTrucks) elseif actor.Owner == USSR and actor.Type ~= "truk" then actor.Stop() actor.Destroy() end end) end BridgeTriggers = function() Trigger.OnKilled(BridgeBarrel1, function() local theNorthEastBridge = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "bridge2" end)[1] if not theNorthEastBridge.IsDead then theNorthEastBridge.Kill() end end) Trigger.OnKilled(BridgeBarrel2, function() local theNorthwestBridge = Map.ActorsInBox(NorthwestPath1.CenterPosition, NorthEntry.CenterPosition, function(self) return self.Type == "bridge1" end)[1] if not theNorthwestBridge.IsDead then theNorthwestBridge.Kill() end end) Trigger.OnKilled(BridgeBarrel3, function() local theSoutheastBridge = Map.ActorsInBox(SoutheastBridge.CenterPosition, SouthPath3.CenterPosition, function(self) return self.Type == "bridge1" end)[1] if not theSoutheastBridge.IsDead then theSoutheastBridge.Kill() end end) AllThreeBridges = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "bridge1" or actor.Type == "bridge2" end) Trigger.OnAllKilled(AllThreeBridges, function() Allies.MarkCompletedObjective(DestroyBridges) end) end FinishTimer = function() for i = 0, 5 do local c = TimerColor if i % 2 == 0 then c = HSLColor.White end Trigger.AfterDelay(DateTime.Seconds(i), function() UserInterface.SetMissionText("The first trucks are entering your AO.", c) end) end Trigger.AfterDelay(DateTime.Seconds(6), function() UserInterface.SetMissionText("") end) end ticked = TimerTicks ConvoysSent = false Tick = function() if ticked > 0 then UserInterface.SetMissionText("First trucks arrive in " .. Utils.FormatTime(ticked), TimerColor) ticked = ticked - 1 elseif ticked == 0 and not ConvoysSent then SendConvoys() FinishTimer() end if Allies.HasNoRequiredUnits() then USSR.MarkCompletedObjective(SovietObj) end end WorldLoaded = function() Allies = Player.GetPlayer("Allies") USSR = Player.GetPlayer("USSR") SovietObj = USSR.AddObjective("Defeat the Allies.") StopTrucks = Allies.AddObjective("Destroy all Soviet convoy trucks.") DestroyBridges = Allies.AddObjective("Destroy the nearby bridges to slow the\nconvoys down.", "Secondary", false) Trigger.OnObjectiveAdded(Allies, function(p, id) Media.DisplayMessage(p.GetObjectiveDescription(id), "New " .. string.lower(p.GetObjectiveType(id)) .. " objective") end) 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") end) Trigger.AfterDelay(DateTime.Minutes(3), function() Media.PlaySpeechNotification(Allies, "WarningFiveMinutesRemaining") end) Trigger.AfterDelay(DateTime.Minutes(5), function() Media.PlaySpeechNotification(Allies, "WarningThreeMinutesRemaining") end) Trigger.AfterDelay(DateTime.Minutes(7), function() Media.PlaySpeechNotification(Allies, "WarningOneMinuteRemaining") end) Camera.Position = AlliedBase.CenterPosition TimerColor = Allies.Color OpeningMoves() Trigger.AfterDelay(DateTime.Seconds(30), AttackWaves) ConvoyExit() BridgeTriggers() local difficulty = Map.LobbyOption("difficulty") ConvoyUnits = ConvoyUnits[difficulty] AttackWaveDelay = AttackWaveDelays[difficulty] end