Add grace period & polish to Situation Critical

This commit is contained in:
JovialFeline
2025-10-15 11:47:41 -04:00
committed by Gustas Kažukauskas
parent 0fb42b39d9
commit 3dcbdaa56e
5 changed files with 302 additions and 137 deletions

View File

@@ -6,17 +6,38 @@
the License, or (at your option) any later version. For more
information, see COPYING.
]]
MissleSubs = { MSub1, MSub2, MSub3, MSub4 }
VolkovEntryPath = { LSTEntry.Location, LZ.Location }
VolkovandFriend = { "volk", "delphi" }
InsertionTransport = "lst.reinforcement"
SamSites = { Sam1, Sam2, Sam3, Sam4, Sam5, Sam6, Sam7, Sam8, Sam9, Sam10, Sam11, Sam12 }
PrimaryTargets = { BioLab, Silo1, Silo2 }
TimerTicks = DateTime.Minutes(8)
Shocktroopers = { Shok1, Shok2, Shok3, Shok4 }
local USSR = Player.GetPlayer("USSR")
local Turkey = Player.GetPlayer("Turkey")
local Ukraine = Player.GetPlayer("Ukraine")
InnerPatrolPaths =
local MissileSubs = { MSub1, MSub2, MSub3, MSub4 }
local VolkovEntryPath = { LSTEntry.Location, LZ.Location }
local VolkovAndFriend = { "delphi", "volk" }
local InsertionTransport = "lst.reinforcement"
local SamSites = { Sam1, Sam2, Sam3, Sam4, Sam5, Sam6, Sam7, Sam8, Sam9, Sam10, Sam11, Sam12 }
local PrimaryTargets = { BioLab, Silo1, Silo2 }
local Shocktroopers = { Shok1, Shok2, Shok3, Shok4 }
local GuardLab = AddPrimaryObjective(Turkey, "")
local KillPower = AddPrimaryObjective(USSR, "kill-power")
local InfiltrateLab = AddPrimaryObjective(USSR, "infiltrate-bio-weapons-lab-scientist")
local DestroyFacility = AddPrimaryObjective(USSR, "destroy-bio-weapons-lab-missile-silos")
local KillSams = AddSecondaryObjective(USSR, "destroy-all-sam-sites-strategic-bombers")
local VolkovSurvive = AddPrimaryObjective(USSR, "volkov-survive")
local LabInfiltrated = false
local VolkovArrived = false
local LaunchStarted = false
local BombersCalled = false
local LowPowerDuration = 0
local LowPowerThreshold = DateTime.Seconds(2)
local TimerTicks = DateTime.Minutes(8)
local TimerColor = Turkey.Color
---@type cpos[][]
local InnerPatrolPaths =
{
{ InnerPatrol2.Location, InnerPatrol3.Location, InnerPatrol4.Location, InnerPatrol1.Location },
{ InnerPatrol3.Location, InnerPatrol2.Location, InnerPatrol1.Location, InnerPatrol4.Location },
@@ -24,7 +45,8 @@ InnerPatrolPaths =
{ InnerPatrol1.Location, InnerPatrol4.Location, InnerPatrol3.Location, InnerPatrol2.Location }
}
OuterPatrols =
---@type actor[][]
local OuterPatrols =
{
{ TeamOne1, TeamOne2, TeamOne3 },
{ TeamTwo1, TeamTwo2, TeamTwo3 },
@@ -33,7 +55,8 @@ OuterPatrols =
{ TeamFive1, TeamFive2, TeamFive3 }
}
OuterPatrolPaths =
---@type cpos[][]
local OuterPatrolPaths =
{
{ OuterPatrol1.Location, OuterPatrol2.Location, OuterPatrol3.Location, OuterPatrol4.Location, OuterPatrol5.Location, OuterPatrol6.Location, OuterPatrol7.Location },
{ OuterPatrol5.Location, OuterPatrol4.Location, OuterPatrol3.Location, OuterPatrol2.Location, OuterPatrol1.Location, OuterPatrol7.Location, OuterPatrol6.Location },
@@ -42,7 +65,42 @@ OuterPatrolPaths =
{ OuterPatrol3.Location, OuterPatrol2.Location, OuterPatrol1.Location, OuterPatrol7.Location, OuterPatrol6.Location, OuterPatrol5.Location, OuterPatrol4.Location }
}
GroupPatrol = function(units, waypoints, delay)
local function IsVolkovNearBlast()
-- Within this radius, most normal infantry are left at 20% HP or less.
local cyborgsInDanger = Map.ActorsInCircle(TacticalNukeCenter.CenterPosition, WDist.FromCells(12), function(a)
return a.Type == "volk"
end)
return #cyborgsInDanger == 1
end
local function ClearCountdown()
UserInterface.SetMissionText("")
DateTime.TimeLimit = 0
TimerTicks = 0
end
---@param duration integer
local function SetRunText(duration)
local text = UserInterface.GetFluentMessage("run-for-it")
local seconds = math.floor(duration / DateTime.Seconds(1))
Media.PlaySoundNotification(USSR, "AlertBleep")
for i = 0, seconds - 1, 1 do
local color = Ukraine.Color
if i % 2 ~= 0 then
color = HSLColor.White
end
Trigger.AfterDelay(DateTime.Seconds(i), function() UserInterface.SetMissionText(text, color) end)
end
Trigger.AfterDelay(duration, function() UserInterface.SetMissionText("") end)
end
---@param units actor[]
---@param path cpos[]
---@param delay integer
local function GroupPatrol(units, path, delay)
local i = 1
local stop = false
@@ -51,30 +109,36 @@ GroupPatrol = function(units, waypoints, delay)
if stop then
return
end
if unit.Location == waypoints[i] then
local bool = Utils.All(units, function(actor) return actor.IsIdle end)
if bool then
stop = true
i = i + 1
if i > #waypoints then
i = 1
end
Trigger.AfterDelay(delay, function() stop = false end)
if unit.Location ~= path[i] then
unit.AttackMove(path[i])
return
end
local bool = Utils.All(units, function(actor) return actor.IsIdle or actor.IsDead end)
if bool then
stop = true
i = i + 1
if i > #path then
i = 1
end
else
unit.AttackMove(waypoints[i])
Trigger.AfterDelay(delay, function() stop = false end)
end
end)
end)
end
StartPatrols = function()
local function StartPatrols()
for i = 1, 5 do
GroupPatrol(OuterPatrols[i], OuterPatrolPaths[i], DateTime.Seconds(3))
end
for i = 1, 4 do
Trigger.AfterDelay(DateTime.Seconds(3* (i - 1)), function()
Trigger.AfterDelay(DateTime.Seconds(3 * (i - 1)), function()
if Shocktroopers[i].IsDead then
return
end
Trigger.OnIdle(Shocktroopers[i], function()
Shocktroopers[i].Patrol(InnerPatrolPaths[i])
end)
@@ -82,8 +146,104 @@ StartPatrols = function()
end
end
LabInfiltrated = false
SetupTriggers = function()
local function LaunchMissiles()
if LaunchStarted then
return
end
LaunchStarted = true
UserInterface.SetMissionText(UserInterface.GetFluentMessage("too-late"), USSR.Color)
Actor.Create("camera", true, { Owner = USSR, Location = LaunchCameraMark.Location })
-- Edge case that seems impossible in RA1.
if Silo1.IsDead and Silo2.IsDead and not BioLab.IsDead then
Actor.Create("flare", true, { Owner = Ukraine, Location = GasEntry.Location })
BioLab.GrantCondition("demolish-disabled")
return
end
Camera.Position = LaunchCameraMark.CenterPosition
local delay = 15
Utils.Do({ Silo1, Silo2 }, function(silo)
Trigger.AfterDelay(delay, function()
if silo.IsDead then
return
end
silo.ActivateNukePower(DefaultCameraPosition.Location)
end)
if not silo.IsDead then
silo.GrantCondition("demolish-disabled")
delay = delay + 15
end
end)
end
local function SendInBombers()
if LaunchStarted or not LabInfiltrated or not USSR.IsObjectiveCompleted(KillSams) then
return
end
BombersCalled = true
ClearCountdown()
local bombDelay = DateTime.Seconds(2)
Trigger.AfterDelay(DateTime.Seconds(1), function()
Actor.Create("camera.bomber", true, { Owner = USSR, Location = TacticalNukeCenter.Location })
end)
if IsVolkovNearBlast() then
bombDelay = DateTime.Seconds(8)
SetRunText(bombDelay + DateTime.Seconds(1))
end
Trigger.AfterDelay(bombDelay, function()
local proxy = Actor.Create("powerproxy.parabombs", false, { Owner = USSR })
proxy.TargetAirstrike(TacticalNuke1.CenterPosition, Angle.SouthWest)
proxy.TargetAirstrike(TacticalNuke2.CenterPosition, Angle.SouthWest)
proxy.TargetAirstrike(TacticalNuke3.CenterPosition, Angle.SouthWest)
proxy.Destroy()
end)
end
local function SendInVolkov()
if VolkovArrived or LowPowerDuration < LowPowerThreshold then
return
end
VolkovArrived = true
USSR.MarkCompletedObjective(KillPower)
Media.PlaySpeechNotification(USSR, "ReinforcementsArrived")
Beacon.New(USSR, LZ.CenterPosition, DateTime.Seconds(6))
local teamVolkov = Reinforcements.ReinforceWithTransport(USSR, InsertionTransport, VolkovAndFriend, VolkovEntryPath, { VolkovEntryPath[1] })[2]
local scientist, volkov = teamVolkov[1], teamVolkov[2]
Trigger.OnKilled(volkov, function()
USSR.MarkFailedObjective(VolkovSurvive)
end)
Trigger.OnAddedToWorld(volkov, function()
Media.DisplayMessage(UserInterface.GetFluentMessage("software-update-failed-manual-targets"), UserInterface.GetFluentMessage("volkov"))
end)
Trigger.OnAddedToWorld(scientist, function(b)
Trigger.OnKilled(b, function()
if not LabInfiltrated then
USSR.MarkFailedObjective(InfiltrateLab)
end
end)
Trigger.AfterDelay(DateTime.Seconds(5), function()
if not scientist.IsDead then
scientist.GrantCondition("can-be-targeted")
end
end)
end)
end
local function SetupStartTriggers()
Trigger.OnAllKilled(SamSites, function()
USSR.MarkCompletedObjective(KillSams)
SendInBombers()
@@ -105,94 +265,52 @@ SetupTriggers = function()
end)
Trigger.OnAllKilled(PrimaryTargets, function()
if LaunchStarted then
return
end
if not BombersCalled then
ClearCountdown()
end
USSR.MarkCompletedObjective(DestroyFacility)
USSR.MarkCompletedObjective(VolkovSurvive)
Trigger.AfterDelay(DateTime.Seconds(2), function()
USSR.MarkCompletedObjective(VolkovSurvive)
end)
end)
Trigger.OnAllKilled(MissleSubs, function()
Trigger.OnAllKilled(MissileSubs, function()
if not VolkovArrived then
USSR.MarkFailedObjective(KillPower)
end
end)
end
SendInBombers = function()
if LabInfiltrated and USSR.IsObjectiveCompleted(KillSams) then
local proxy = Actor.Create("powerproxy.parabombs", false, { Owner = USSR })
proxy.TargetAirstrike(TacticalNuke1.CenterPosition, Angle.SouthWest)
proxy.TargetAirstrike(TacticalNuke2.CenterPosition, Angle.SouthWest)
proxy.TargetAirstrike(TacticalNuke3.CenterPosition, Angle.SouthWest)
proxy.Destroy()
end
end
SendInVolkov = function()
if not VolkovArrived then
USSR.MarkCompletedObjective(KillPower)
Media.PlaySpeechNotification(USSR, "ReinforcementsArrived")
local teamVolkov = Reinforcements.ReinforceWithTransport(USSR, InsertionTransport, VolkovandFriend, VolkovEntryPath, { VolkovEntryPath[1] })[2]
VolkovArrived = true
Trigger.OnKilled(teamVolkov[1], function()
USSR.MarkFailedObjective(VolkovSurvive)
end)
Trigger.OnAddedToWorld(teamVolkov[1], function(a)
Media.DisplayMessage(UserInterface.GetFluentMessage("software-update-failed-manual-targets"), UserInterface.GetFluentMessage("volkov"))
end)
Trigger.OnAddedToWorld(teamVolkov[2], function(b)
Trigger.OnKilled(b, function()
if not LabInfiltrated then
USSR.MarkFailedObjective(InfiltrateLab)
end
end)
end)
end
end
Ticked = TimerTicks
Tick = function()
if Turkey.PowerState ~= "Normal" then
LowPowerDuration = LowPowerDuration + 1
SendInVolkov()
else
LowPowerDuration = 0
end
if Ticked > 0 then
if (Ticked % DateTime.Seconds(1)) == 0 then
Timer = UserInterface.GetFluentMessage("missiles-launch-in", { ["time"] = Utils.FormatTime(Ticked) })
UserInterface.SetMissionText(Timer, TimerColor)
if TimerTicks > 0 then
if (TimerTicks % DateTime.Seconds(1)) == 0 then
local text = UserInterface.GetFluentMessage("missiles-launch-in", { ["time"] = Utils.FormatTime(TimerTicks) })
UserInterface.SetMissionText(text, TimerColor)
end
Ticked = Ticked - 1
elseif Ticked == 0 then
UserInterface.SetMissionText(UserInterface.GetFluentMessage("too-late"), USSR.Color)
Turkey.MarkCompletedObjective(LaunchMissles)
TimerTicks = TimerTicks - 1
elseif TimerTicks == 0 and not BombersCalled and not USSR.IsObjectiveCompleted(DestroyFacility) then
Turkey.MarkCompletedObjective(GuardLab)
LaunchMissiles()
end
end
WorldLoaded = function()
USSR = Player.GetPlayer("USSR")
Turkey = Player.GetPlayer("Turkey")
InitObjectives(USSR)
LaunchMissles = AddPrimaryObjective(Turkey, "")
KillPower = AddPrimaryObjective(USSR, "kill-power")
InfiltrateLab = AddPrimaryObjective(USSR, "infiltrate-bio-weapons-lab-scientist")
DestroyFacility = AddPrimaryObjective(USSR, "destroy-bio-weapons-lab-missile-silos")
KillSams = AddSecondaryObjective(USSR, "destroy-all-sam-sites-strategic-bombers")
VolkovSurvive = AddPrimaryObjective(USSR, "volkov-survive")
Trigger.AfterDelay(DateTime.Minutes(3), function()
Media.PlaySpeechNotification(USSR, "WarningFiveMinutesRemaining")
end)
Trigger.AfterDelay(DateTime.Minutes(5), function()
Media.PlaySpeechNotification(USSR, "WarningThreeMinutesRemaining")
end)
Trigger.AfterDelay(DateTime.Minutes(7), function()
Media.PlaySpeechNotification(USSR, "WarningOneMinuteRemaining")
end)
StartPatrols()
SetupTriggers()
SetupStartTriggers()
Camera.Position = DefaultCameraPosition.CenterPosition
TimerColor = Turkey.Color
DateTime.TimeLimit = TimerTicks
end