--[[ Copyright (c) The OpenRA Developers and Contributors 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. ]] if Difficulty == "hard" then TimerTicks = DateTime.Minutes(25) elseif Difficulty == "normal" then TimerTicks = DateTime.Minutes(28) else TimerTicks = DateTime.Minutes(31) end Announcements = { { speech = "TwentyMinutesRemaining", delay = DateTime.Minutes(20) }, { speech = "TenMinutesRemaining", delay = DateTime.Minutes(10) }, { speech = "WarningFiveMinutesRemaining", delay = DateTime.Minutes(5) }, { speech = "WarningFourMinutesRemaining", delay = DateTime.Minutes(4) }, { speech = "WarningThreeMinutesRemaining", delay = DateTime.Minutes(3) }, { speech = "WarningTwoMinutesRemaining", delay = DateTime.Minutes(2) }, { speech = "WarningOneMinuteRemaining", delay = DateTime.Minutes(1) } } TownAttackers = { TownAttacker1, TownAttacker2, TownAttacker3, TownAttacker4, TownAttacker5, TownAttacker6, TownAttacker7 } PatrolPoints1 = { PatrolPoint11.Location, PatrolPoint12.Location, PatrolPoint13.Location, PatrolPoint14.Location, PatrolPoint15.Location } PatrolPoints2 = { PatrolPoint21.Location, PatrolPoint22.Location, PatrolPoint23.Location, PatrolPoint24.Location, PatrolPoint25.Location } PatrolPoints3 = { PatrolPoint31.Location, PatrolPoint32.Location, PatrolPoint33.Location, PatrolPoint34.Location } PatrolPoints4 = { PatrolPoint41.Location, PatrolPoint42.Location, PatrolPoint43.Location, PatrolPoint44.Location, PatrolPoint45.Location } Patrol1 = { "e1", "e1", "e1", "e1", "e1" } Patrol2 = { "e1", "dog.patrol", "dog.patrol" } Patrol3 = { "e1", "e1", "dog.patrol" } TransportType = "lst.unselectable.unloadonly" SecureLabFailed = function() Utils.Do(Humans, function(player) if player then player.MarkFailedObjective(SecureLab) end end) end TimerStarted = false StartTimer = function() Utils.Do(Humans, function(player) if player.IsLocalPlayer then TimerColor = player.Color end end) CountDownTimerAnnouncements() Ticked = TimerTicks TimerStarted = true Trigger.AfterDelay(DateTime.Seconds(3), function() Utils.Do(Humans, function(player) Media.PlaySpeechNotification(player, "TimerStarted") end) end) end CountDownTimerAnnouncements = function() for i = #Announcements, 1, -1 do local delay = TimerTicks - Announcements[i].delay Trigger.AfterDelay(delay, function() if not LabSecured then Utils.Do(Humans, function(player) Media.PlaySpeechNotification(player, Announcements[i].speech) end) end end) end end ReinforcementsHaveArrived = false LabInfiltrated = function() Utils.Do(Humans, function(player) if player then SecureLab = AddPrimaryObjective(player, "secure-laboratory-guards") DestroyBase = AddPrimaryObjective(player, "destroy-remaining-soviet-presence") player.MarkCompletedObjective(InfiltrateLab) Trigger.ClearAll(Lab) Trigger.AfterDelay(0, function() Trigger.OnKilled(Lab, SecureLabFailed) end) end end) Camera.Position = ReinforcementsUnloadPoint.CenterPosition local entryPath = { ReinforcementsEntryPoint.Location, ReinforcementsUnloadPoint.Location } local exit = { ReinforcementsEntryPoint.Location } local mcvActors = { "mcv" } if Allies2 then mcvActors = { "mcv", "mcv" } end local reinforcements = Reinforcements.ReinforceWithTransport(Allies, TransportType, mcvActors, entryPath, exit) local mcvs = reinforcements[2] Trigger.OnAddedToWorld(mcvs[1], function(mcvUnloaded) -- Don't call this twice (because of the owner change) if mcvUnloaded.Owner == Allies1 then return end mcvUnloaded.Owner = Allies1 if not Allies2 then Allies1.Cash = 5000 end Media.PlaySpeechNotification(Allies1, "AlliedReinforcementsSouth") StartTimer() HijackTruck.Destroy() ReinforcementsHaveArrived = true end) if Allies2 then Trigger.OnAddedToWorld(mcvs[2], function(mcvUnloaded) -- Don't call this twice (because of the owner change) if mcvUnloaded.Owner == Allies2 then return end mcvUnloaded.Owner = Allies2 Allies1.Cash = 2500 Allies2.Cash = 2500 end) end Utils.Do(Humans, function(player) for i = 0, 2 do Trigger.AfterDelay(DateTime.Seconds(i), function() Media.PlaySoundNotification(player, "AlertBuzzer") end) end end) if BridgeTank.IsDead then return end local attackPoint = BridgeAttackPoint.CenterPosition local radius = WDist.FromCells(5) local bridge = Map.ActorsInCircle(attackPoint, radius, function(actor) return actor.Type == "br3" end)[1] BridgeTank.Attack(bridge, true, true) end InfiltrateLabFailed = function() Utils.Do(Humans, function(player) if player then player.MarkFailedObjective(InfiltrateLab) end end) end ChangeOwnerOnAddedToWorld = function(actor, newOwner) Trigger.OnAddedToWorld(actor, function(unloadedActor) unloadedActor.Owner = newOwner Trigger.Clear(unloadedActor, "OnAddedToWorld") end) end InsertSpies = function() Utils.Do(Humans, function(player) if player then InfiltrateLab = AddPrimaryObjective(player, "infiltrate-laboratory") end end) Trigger.OnKilled(Lab, function() if not Allies1.IsObjectiveCompleted(InfiltrateLab) then InfiltrateLabFailed() end end) -- The delay isn't purely cosmetic, but also prevents a System.InvalidOperationException -- "Collection was modified after the enumerator was instantiated." in tick_activities local infiltrationCount = 0 Trigger.OnInfiltrated(Lab, function() infiltrationCount = infiltrationCount + 1 if (Allies2 and infiltrationCount == 2) or not Allies2 then Trigger.AfterDelay(DateTime.Seconds(3), LabInfiltrated) end end) local spyActors = { "spy.strong" } if Allies2 then spyActors = { "spy.strong", "spy.strong" } end local entryPath = { SpyReinforcementsEntryPoint.Location, SpyReinforcementsUnloadPoint.Location } local exit = { SpyReinforcementsExitPoint.Location } local reinforcements = Reinforcements.ReinforceWithTransport(Allies, TransportType, spyActors, entryPath, exit) local transport = reinforcements[1] Camera.Position = transport.CenterPosition local spies = reinforcements[2] Trigger.OnAnyKilled(spies, InfiltrateLabFailed) ChangeOwnerOnAddedToWorld(spies[1], Allies1) if Allies2 then ChangeOwnerOnAddedToWorld(spies[2], Allies2) end end StopHunt = function(unit) if not unit.IsDead then unit.Stop() Trigger.Clear(unit, "OnIdle") end end AttackTown = function() Utils.Do(TownAttackers, IdleHunt) Trigger.OnRemovedFromWorld(Hospital, function() Utils.Do(TownAttackers, StopHunt) end) end CapOre = function(player) if player.Resources > player.ResourceCapacity * 0.9 then player.Resources = player.ResourceCapacity * 0.8 end end NewPatrol = function(actorType, start, waypoints) local guard = Actor.Create(actorType, true, { Owner = Soviets, Location = start }) guard.Patrol(waypoints, true, Utils.RandomInteger(50, 75)) end SetupPatrols = function() Utils.Do(Patrol1, function(patrol1) NewPatrol(patrol1, PatrolPoints1[1], PatrolPoints1) end) Utils.Do(Patrol2, function(patrol2) NewPatrol(patrol2, PatrolPoints1[3], PatrolPoints1) end) Utils.Do(Patrol2, function(patrol3) NewPatrol(patrol3, PatrolPoints3[1], PatrolPoints3) end) Utils.Do(Patrol2, function(patrol4) NewPatrol(patrol4, PatrolPoints4[1], PatrolPoints4) end) if Difficulty == "hard" then Utils.Do(Patrol3, function(patrol5) NewPatrol(patrol5, PatrolPoints2[1], PatrolPoints2) end) end local checkpoint = { BaseGuardTruckPos.Location } Trigger.OnEnteredFootprint(checkpoint, function(a, id) Trigger.RemoveFootprintTrigger(id) if not BaseGuard.IsDead then BaseGuard.ScriptedMove(BaseGuardMovePos.Location) end end) end Ticked = 0 SecureLabTimer = function() if not TimerStarted or LabSecured then return end if Ticked > 0 then if (Ticked % DateTime.Seconds(1)) == 0 then Timer = UserInterface.Translate("secure-lab-in", { ["time"] = Utils.FormatTime(Ticked) }) UserInterface.SetMissionText(Timer, TimerColor) end Ticked = Ticked - 1 elseif Ticked <= 0 then TimerColor = Soviets.Color UserInterface.SetMissionText(UserInterface.Translate("soviet-research-lab-not-secured-in-time"), TimerColor) SecureLabFailed() end end SovietBaseMaintenanceSetup = function() local sovietbuildings = Utils.Where(Map.NamedActors, function(a) return a.Owner == Soviets and a.HasProperty("StartBuildingRepairs") end) Trigger.OnAllKilledOrCaptured(sovietbuildings, function() Utils.Do(Humans, function(player) player.MarkCompletedObjective(DestroyBase) end) end) Utils.Do(sovietbuildings, function(sovietbuilding) Trigger.OnDamaged(sovietbuilding, function(building) if building.Owner == Soviets and building.Health < building.MaxHealth * 3/4 then building.StartBuildingRepairs() end end) end) end CheckPlayerDefeat = function() if not ReinforcementsHaveArrived then return end Utils.Do(Humans, function(player) if player.HasNoRequiredUnits() then player.MarkFailedObjective(DestroyBase) end end) end LabSecured = false CheckLabSecured = function() if not ReinforcementsHaveArrived or LabSecured then return end if Allies1.HasNoRequiredUnits() or (Allies2 and Allies2.HasNoRequiredUnits()) then Utils.Do(Humans, function(player) player.MarkFailedObjective(SecureLab) end) end local radius = WDist.FromCells(10) local labGuards = Utils.Where(Map.ActorsInCircle(LabWaypoint.CenterPosition, radius), function(a) return a.Owner == Soviets and a.HasProperty("Move") end) if #labGuards < 1 then LabSecured = true Utils.Do(Humans, function(player) player.MarkCompletedObjective(SecureLab) end) UserInterface.SetMissionText("") end end Tick = function() CapOre(Soviets) SecureLabTimer() CheckLabSecured() CheckPlayerDefeat() end WorldLoaded = function() Allies = Player.GetPlayer("Allies") Neutral = Player.GetPlayer("Neutral") Creeps = Player.GetPlayer("Creeps") Soviets = Player.GetPlayer("Soviets") Allies1 = Player.GetPlayer("Allies1") Allies2 = Player.GetPlayer("Allies2") Humans = { Allies1, Allies2 } Utils.Do(Humans, function(player) if player and player.IsLocalPlayer then InitObjectives(player) end end) InsertSpies() AttackTown() SetupPatrols() SovietBaseMaintenanceSetup() end