From c58621e036fcc62f5bd4c7526f56dbcf24dbc8c1 Mon Sep 17 00:00:00 2001 From: JovialFeline Date: Fri, 19 Jul 2024 15:30:37 -0400 Subject: [PATCH] Add bombers, fixes to Production Disruption --- mods/ra/maps/production-disruption/map.yaml | 37 +-- .../production-disruption.lua | 213 ++++++++++++++---- mods/ra/maps/production-disruption/rules.yaml | 29 +++ 3 files changed, 219 insertions(+), 60 deletions(-) diff --git a/mods/ra/maps/production-disruption/map.yaml b/mods/ra/maps/production-disruption/map.yaml index bb57ef1633..78d74f3eab 100644 --- a/mods/ra/maps/production-disruption/map.yaml +++ b/mods/ra/maps/production-disruption/map.yaml @@ -26,12 +26,14 @@ Players: Faction: england PlayerReference@BadGuy: Name: BadGuy + Bot: campaign Faction: soviet Color: FF1400 Allies: USSR Enemies: Greece PlayerReference@USSR: Name: USSR + Bot: campaign Faction: soviet Color: FF1400 Allies: BadGuy @@ -410,7 +412,7 @@ Actors: Actor120: apwr Location: 71,41 Owner: USSR - Actor121: fcom + ForwardCommand: fcom Location: 51,40 Owner: USSR Actor122: apwr @@ -501,12 +503,12 @@ Actors: Location: 67,76 Owner: BadGuy Facing: 380 - SubCell: 3 + SubCell: 4 Actor148: e1 Location: 71,77 Owner: BadGuy Facing: 124 - SubCell: 4 + SubCell: 5 Actor149: e1 Location: 74,76 Owner: BadGuy @@ -526,11 +528,11 @@ Actors: Location: 76,62 Owner: USSR Facing: 380 - SubCell: 4 + SubCell: 5 Actor153: e1 Location: 54,40 Owner: USSR - SubCell: 3 + SubCell: 4 Actor154: e1 Location: 69,40 Owner: USSR @@ -558,7 +560,7 @@ Actors: Actor160: e2 Location: 71,39 Owner: USSR - SubCell: 4 + SubCell: 5 Rifle1: e1 Location: 78,81 Owner: USSR @@ -566,30 +568,30 @@ Actors: Rifle2: e1 Location: 78,79 Owner: USSR - SubCell: 3 + SubCell: 4 Rifle3: e1 Location: 77,80 Owner: USSR - SubCell: 4 + SubCell: 5 Rifle4: e1 Location: 47,71 Owner: USSR - SubCell: 4 + SubCell: 5 Rifle5: e1 Location: 49,71 Owner: USSR - SubCell: 3 + SubCell: 4 Rifle6: e1 Location: 49,70 Owner: USSR - SubCell: 3 + SubCell: 4 DefaultCameraPosition: waypoint Location: 58,86 Owner: Neutral TeslaCam: waypoint Location: 66,94 Owner: Neutral - LZ: waypoint + SouthLZ: waypoint Location: 54,85 Owner: Neutral Beach1: waypoint @@ -644,8 +646,17 @@ Actors: Location: 77,39 Owner: Neutral V2: waypoint - Location: 66,43 + Location: 63,44 Owner: Neutral + NorthLZ: waypoint + Owner: Neutral + Location: 60,56 + BomberTarget1: waypoint + Owner: Neutral + Location: 54,46 + BomberTarget2: waypoint + Owner: Neutral + Location: 65,46 Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml diff --git a/mods/ra/maps/production-disruption/production-disruption.lua b/mods/ra/maps/production-disruption/production-disruption.lua index 1498bd4527..d74feeab15 100644 --- a/mods/ra/maps/production-disruption/production-disruption.lua +++ b/mods/ra/maps/production-disruption/production-disruption.lua @@ -6,6 +6,7 @@ the License, or (at your option) any later version. For more information, see COPYING. ]] +FlameWallRevealed = false TimerTicks = DateTime.Minutes(12) LSTType = "lst.reinforcement" RifleSquad1 = { Rifle1, Rifle2, Rifle3 } @@ -16,44 +17,45 @@ DemoEngiPath = { WaterEntry1.Location, Beach1.Location } DemoEngiTeam = { "dtrk", "dtrk", "e6", "e6", "e6" } SovietWaterEntry1 = { WaterEntry2.Location, Beach2.Location } SovietWaterEntry2 = { WaterEntry2.Location, Beach3.Location } -SovietSquad = { "e1", "e1", "e1", "e4", "e4" } +SovietSquad = { "e1", "e1", "e2", "e4", "e4" } V2Squad = { "v2rl", "v2rl" } SubEscapePath = { SubPath1, SubPath2, SubPath3 } MissionStart = function() - LZCamera = Actor.Create("camera", true, { Owner = Greece, Location = LZ.Location }) - Chalk1.TargetParatroopers(LZ.CenterPosition, Angle.New(740)) if Difficulty == "normal" then - Actor.Create("tsla", true, { Owner = USSR, Location = EasyCamera.Location }) + local northCoil = Actor.Create("tsla", true, { Owner = USSR, Location = EasyCamera.Location }) Actor.Create("4tnk", true, { Owner = USSR, Facing = Angle.South, Location = Mammoth.Location }) Actor.Create("4tnk", true, { Owner = USSR, Facing = Angle.South, Location = Mammoth.Location + CVec.New(1,0) }) Actor.Create("v2rl", true, { Owner = USSR, Facing = Angle.South, Location = V2.Location }) + -- Avoid leaving infantry stranded on the island. + northCoil.GrantCondition("no-actors-on-sell") end + SpawnTemporaryCamera(SouthLZ.Location, DateTime.Seconds(15)) + Chalk1.TargetParatroopers(SouthLZ.CenterPosition, Angle.New(740)) + Trigger.AfterDelay(DateTime.Seconds(1), function() - Chalk2.TargetParatroopers(LZ.CenterPosition, Angle.New(780)) + Chalk2.TargetParatroopers(SouthLZ.CenterPosition, Angle.New(780)) end) Trigger.AfterDelay(DateTime.Seconds(5), function() UnitsArrived = true - TeslaCamera = Actor.Create("camera", true, { Owner = Greece, Location = TeslaCam.Location }) + SpawnTemporaryCamera(TeslaCam.Location, DateTime.Seconds(10)) end) Trigger.AfterDelay(DateTime.Seconds(10), function() - LZCamera.Destroy() Utils.Do(RifleSquad1, function(actor) if not actor.IsDead then - actor.AttackMove(LZ.Location) + actor.AttackMove(SouthLZ.Location) IdleHunt(actor) end end) end) Trigger.AfterDelay(DateTime.Seconds(15), function() - TeslaCamera.Destroy() Utils.Do(RifleSquad2, function(actor) if not actor.IsDead then - actor.AttackMove(LZ.Location) + actor.AttackMove(SouthLZ.Location) IdleHunt(actor) end end) @@ -61,34 +63,91 @@ MissionStart = function() end SetupTriggers = function() - Trigger.OnDamaged(SubPen, function() - Utils.Do(Heavys, function(actor) - if not actor.IsDead then - IdleHunt(actor) - end - end) - end) + SetupFlameWall() + SetupNorthBase() Trigger.OnKilled(Church, function() Actor.Create("healcrate", true, { Owner = Greece, Location = ChurchCrate.Location }) end) Trigger.OnKilled(ObjectiveDome, function() - if not DomeCaptured == true then + if not DomeCaptured then Greece.MarkFailedObjective(CaptureDome) end end) - Trigger.OnAllKilled(FlameTowerWall, function() - DomeCam = Actor.Create("camera", true, { Owner = Greece, Location = RadarCam.Location }) - Trigger.AfterDelay(DateTime.Seconds(5), function() - DomeCam.Destroy() + -- Avoid notifications unless part of the the northern base is captured. + Greece.PlayLowPowerNotification = false + local notifiers = Utils.Where(USSR.GetActors(), function(actor) + return actor.HasProperty("StartBuildingRepairs") + end) + + Utils.Do(notifiers, function(n) + Trigger.OnCapture(n, function() + Greece.PlayLowPowerNotification = true end) end) +end + +SetupFlameWall = function() + Trigger.OnAllKilled(FlameTowerWall, function() + SpawnTemporaryCamera(RadarCam.Location, DateTime.Seconds(5)) + end) + + -- Give some warning if they are not yet revealed by the power cut. + Trigger.OnEnteredProximityTrigger(FlameCam.CenterPosition, WDist.FromCells(8), function(actor, id) + if FlameWallRevealed then + Trigger.RemoveProximityTrigger(id) + return + end + + if actor.Owner == Greece then + FlameWallRevealed = true + Trigger.RemoveProximityTrigger(id) + SpawnTemporaryCamera(FlameCam.Location, DateTime.Seconds(10)) + end + end) +end + +SetupNorthBase = function() + local bombsPrepared = false + local tanksAlerted = false Trigger.OnKilledOrCaptured(SubPen, function() Greece.MarkCompletedObjective(StopProduction) end) + + Trigger.OnDamaged(SubPen, function(_, attacker) + if tanksAlerted or attacker.Type == "badr.bomber" then + return + end + + tanksAlerted = true + Utils.Do(Heavys, IdleHunt) + end) + + Trigger.OnKilledOrCaptured(ForwardCommand, function() + StartFireSale() + -- The original mission used four waypoints (7-10) for drops. + -- For simplicity, a four-Badger team will target the middle. + Chalk3.TargetParatroopers(NorthLZ.CenterPosition, Angle.New(927)) + + Trigger.AfterDelay(DateTime.Seconds(2), function() + Media.PlaySpeechNotification(Greece, "ReinforcementsArrived") + end) + + if not bombsPrepared then + bombsPrepared = true + BombNorthBase() + end + end) + + Trigger.OnAllKilledOrCaptured(USSR.GetActorsByType("sam"), function() + if not bombsPrepared then + bombsPrepared = true + BombNorthBase() + end + end) end PowerDown = false @@ -96,9 +155,13 @@ PowerDownTeslas = function() if not PowerDown then CaptureDome = AddSecondaryObjective(Greece, "capture-enemy-radar-dome") Greece.MarkCompletedObjective(PowerDownTeslaCoils) - Media.PlaySpeechNotification(Greece, "ReinforcementsArrived") + Media.PlaySoundNotification(Greece, "RadarDown") PowerDown = true + Trigger.AfterDelay(DateTime.Seconds(1), function() + Media.PlaySpeechNotification(Greece, "ReinforcementsArrived") + end) + local bridge = Utils.Where(Map.ActorsInWorld, function(actor) return actor.Type == "bridge1" end)[1] if not bridge.IsDead then bridge.Kill() @@ -117,34 +180,56 @@ PowerDownTeslas = function() Trigger.OnCapture(ObjectiveDome, function() DomeCaptured = true Greece.MarkCompletedObjective(CaptureDome) - SendChronos() - end) - FlameTowersCam = Actor.Create("camera", true, { Owner = Greece, Location = FlameCam.Location }) - Trigger.AfterDelay(DateTime.Seconds(10), function() - FlameTowersCam.Destroy() - end) - end -end - -SendChronos = function() - Trigger.AfterDelay(DateTime.Seconds(3), function() - local sovietWaterSquad1 = Reinforcements.ReinforceWithTransport(USSR, "lst", SovietSquad, { WaterEntry2.Location, Beach2.Location }, { WaterEntry2.Location })[2] - Utils.Do(sovietWaterSquad1, function(a) - Trigger.OnAddedToWorld(a, function() - IdleHunt(a) + Trigger.AfterDelay(DateTime.Seconds(3), function() + SendChronos() + SendWaterSquads() + Actor.Create("camera", true, { Owner = Greece, Location = EasyCamera.Location }) end) end) - Actor.Create("ctnk", true, { Owner = Greece, Location = ChronoSpawn1.Location }) - Actor.Create("ctnk", true, { Owner = Greece, Location = ChronoSpawn2.Location }) - Actor.Create("ctnk", true, { Owner = Greece, Location = ChronoSpawn3.Location }) - Actor.Create("camera", true, { Owner = Greece, Location = EasyCamera.Location }) - Media.PlaySound("chrono2.aud") + if not FlameWallRevealed then + FlameWallRevealed = true + SpawnTemporaryCamera(FlameCam.Location, DateTime.Seconds(10)) + end + end +end + +BombNorthBase = function() + local proxy = Actor.Create("powerproxy.parabombs", false, { Owner = Greece }) + proxy.TargetAirstrike(BomberTarget1.CenterPosition, Angle.New(970)) + proxy.TargetAirstrike(BomberTarget2.CenterPosition, Angle.New(932)) + proxy.Destroy() +end + +SendChronos = function() + local payload = { } + local proxy = Actor.Create("powerproxy.chronoshift", false, { Owner = Greece }) + local spawns = + { + { cell = ChronoSpawn2.Location, facing = Angle.NorthWest }, + { cell = ChronoSpawn1.Location, facing = Angle.NorthEast }, + { cell = ChronoSpawn3.Location, facing = Angle.South } + } + + Utils.Do(spawns, function(spawn) + local tank = Actor.Create("ctnk", true, { Owner = Greece, Facing = spawn.facing }) + payload[tank] = spawn.cell + end) + + Media.PlaySound("chrono2.aud") + proxy.Chronoshift(payload) + proxy.Destroy() +end + +SendWaterSquads = function() + local sovietWaterSquad1 = Reinforcements.ReinforceWithTransport(USSR, LSTType, SovietSquad, { WaterEntry2.Location, Beach2.Location }, { WaterEntry2.Location })[2] + Utils.Do(sovietWaterSquad1, function(a) + Trigger.OnAddedToWorld(a, IdleHunt) end) Trigger.AfterDelay(DateTime.Seconds(5), function() - local sovietWaterSquad2 = Reinforcements.ReinforceWithTransport(USSR, "lst", SovietSquad, { WaterEntry2.Location, Beach3.Location }, { WaterEntry2.Location })[2] + local sovietWaterSquad2 = Reinforcements.ReinforceWithTransport(USSR, LSTType, SovietSquad, { WaterEntry2.Location, Beach3.Location }, { WaterEntry2.Location })[2] Utils.Do(sovietWaterSquad2, function(a) Trigger.OnAddedToWorld(a, function() a.AttackMove(FlameCam.Location) @@ -154,7 +239,7 @@ SendChronos = function() end) Trigger.AfterDelay(DateTime.Seconds(13), function() - local sovietWaterSquad2 = Reinforcements.ReinforceWithTransport(USSR, "lst", V2Squad, { WaterEntry2.Location, Beach2.Location }, { WaterEntry2.Location })[2] + local sovietWaterSquad2 = Reinforcements.ReinforceWithTransport(USSR, LSTType, V2Squad, { WaterEntry2.Location, Beach2.Location }, { WaterEntry2.Location })[2] Utils.Do(sovietWaterSquad2, function(a) Trigger.OnAddedToWorld(a, function() a.AttackMove(FlameCam.Location) @@ -185,15 +270,47 @@ MissileSubEscape = function() end) end -SubmarineEscapes = UserInterface.Translate("submarine-escapes") +StartFireSale = function() + local structures = Utils.Where(USSR.GetActors(), function(actor) + return actor.HasProperty("StartBuildingRepairs") + end) + + if #structures == 0 then + return + end + + SpawnTemporaryCamera(BomberTarget1.Location, DateTime.Seconds(5)) + SpawnTemporaryCamera(BomberTarget2.Location, DateTime.Seconds(5)) + + Utils.Do(structures, function(building) + building.Sell() + end) + + Trigger.OnAllRemovedFromWorld(structures, function() + Utils.Do(USSR.GetGroundAttackers(), IdleHunt) + end) +end + +SpawnTemporaryCamera = function(location, duration) + local camera = Actor.Create("camera", true, { Owner = Greece, Location = location }) + + Trigger.AfterDelay(duration, function() + if camera.IsInWorld then + camera.Destroy() + end + end) +end + FinishTimer = function() + local submarineEscapes = UserInterface.Translate("submarine-escapes") + 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(SubmarineEscapes, c) end) + Trigger.AfterDelay(DateTime.Seconds(i), function() UserInterface.SetMissionText(submarineEscapes, c) end) end Trigger.AfterDelay(DateTime.Seconds(6), function() UserInterface.SetMissionText("") end) end @@ -217,6 +334,7 @@ Tick = function() end Ticked = Ticked - 1 elseif Ticked == 0 and not TimerFinished then + FinishTimer() MissileSubEscape() TimerFinished = true end @@ -250,6 +368,7 @@ WorldLoaded = function() TimerColor = USSR.Color Chalk1 = Actor.Create("chalk1", false, { Owner = Greece }) Chalk2 = Actor.Create("chalk2", false, { Owner = Greece }) + Chalk3 = Actor.Create("chalk3", false, { Owner = Greece }) MissionStart() SetupTriggers() end diff --git a/mods/ra/maps/production-disruption/rules.yaml b/mods/ra/maps/production-disruption/rules.yaml index bc2fa77c36..98c24773b2 100644 --- a/mods/ra/maps/production-disruption/rules.yaml +++ b/mods/ra/maps/production-disruption/rules.yaml @@ -5,6 +5,8 @@ World: WinVideo: battle.vqa LossVideo: slntsrvc.vqa Briefing: The Soviets are beginning construction of a new class of submarine capable of launching sea-to-ground missiles. We don't have to tell you the amount of devestation these could cause.\n\nTake a small squad of troops and infiltrate their power grid. When it is down, additional reinforcements will be sent in. When ready, head north and destroy their Sub pen, preventing further construction of these subs.\n\nIf any are built, they must not be allowed to escape! + StartGameNotification: + Notification: MissionTimerInitialised ScriptLobbyDropdown@difficulty: ID: difficulty Label: dropdown-difficulty.label @@ -15,6 +17,16 @@ World: hard: options-difficulty.hard Default: normal +powerproxy.chronoshift: + AlwaysVisible: + ChronoshiftPower: + Dimensions: 1, 1 + Footprint: x + +powerproxy.parabombs: + AirstrikePower: + DisplayBeacon: False + CHALK1: ParatroopersPower: DisplayBeacon: False @@ -27,6 +39,17 @@ CHALK2: DropItems: E3, E3, E3, E3, MEDI AlwaysVisible: +CHALK3: + ParatroopersPower: + DisplayBeacon: False + DropItems: E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1 + SquadSize: 4 + AlwaysVisible: + +CTNK: + Chronoshiftable: + ChronoshiftSound: + LST.Reinforcement: Inherits: LST RejectsOrders: @@ -42,3 +65,9 @@ MSUB: -Targetable@UNDERWATER: Targetable: -RequiresCondition: + +TSLA: + ExternalCondition@NOACTORSONSELL: + Condition: no-actors-on-sell + SpawnActorsOnSell: + RequiresCondition: !no-actors-on-sell