Initial commit: OpenRA game engine
Some checks failed
Continuous Integration / Linux (.NET 8.0) (push) Has been cancelled
Continuous Integration / Windows (.NET 8.0) (push) Has been cancelled

Fork from OpenRA/OpenRA with one-click launch script (start-ra.cmd)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
let5sne.win10
2026-01-10 21:46:54 +08:00
commit 9cf6ebb986
4065 changed files with 635973 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,12 @@
## rules.yaml
briefing =
LANDCOM 66 HQS.
TOP SECRET.
TO: FIELD COMMANDER A34
SOVIETS HAVE LAUNCHED HEAVY ATTACKS ON OUR POSITION.
SURVIVE AND HOLD THE BASE UNTIL OUR FRENCH ALLIES ARRIVE.
CONFIRMATION CODE 5593.
TRANSMISSION ENDS.

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,155 @@
Player:
PlayerResources:
DefaultCash: 5000
World:
LuaScript:
Scripts: campaign.lua, utils.lua, survival01.lua
MissionData:
Briefing: briefing
ScriptLobbyDropdown@difficulty:
ID: difficulty
Label: dropdown-difficulty.label
Description: dropdown-difficulty.description
Values:
easy: options-difficulty.easy
normal: options-difficulty.normal
hard: options-difficulty.hard
Default: normal
^Palettes:
IndexedPlayerPalette:
PlayerIndex:
Allies: 224, 224, 225, 225, 226, 184, 185, 186, 187, 188, 188, 189, 190, 190, 191, 191
IndexedPlayerPalette@NOSHADOW:
PlayerIndex:
Allies: 224, 224, 225, 225, 226, 184, 185, 186, 187, 188, 188, 189, 190, 190, 191, 191
powerproxy.paratroopers:
ParatroopersPower:
DropItems: E1,E1,E1,E2,E2
powerproxy.allied:
Inherits: powerproxy.paratroopers
ParatroopersPower:
DropItems: ARTY,ARTY,ARTY
CAMERA.sam:
Inherits: CAMERA
RevealsShroud:
Range: 4c0
AFLD.mission:
Inherits: AFLD
-AirstrikePower@spyplane:
-ParatroopersPower@paratroopers:
-AirstrikePower@parabombs:
-SupportPowerChargeBar:
RenderSprites:
Image: AFLD
ATEK.mission:
Inherits: ATEK
GpsPower:
ChargeInterval: 0
Power:
Amount: 0
-Selectable:
-Targetable:
-GivesBuildableArea:
-Huntable:
RenderSprites:
Image: ATEK
Interactable:
GUN:
Valued:
Cost: 1000
E7:
Buildable:
Prerequisites: ~disabled
SHOK:
Buildable:
Prerequisites: ~disabled
MIG:
Buildable:
Prerequisites: ~disabled
HELI:
Buildable:
Prerequisites: ~disabled
MSLO:
Buildable:
Prerequisites: ~disabled
GAP:
Buildable:
Prerequisites: ~disabled
SYRD:
Buildable:
Prerequisites: ~disabled
PDOX:
Buildable:
Prerequisites: ~disabled
AGUN:
Buildable:
Prerequisites: ~disabled
ATEK:
Buildable:
Prerequisites: ~disabled
4TNK:
Buildable:
Prerequisites: ~disabled
MCV:
Buildable:
Prerequisites: ~disabled
MNLY:
Buildable:
Prerequisites: ~disabled
TTNK:
Buildable:
Prerequisites: ~disabled
CTNK:
Buildable:
Prerequisites: ~disabled
DOME:
Buildable:
Prerequisites: ~disabled
BRIK:
Buildable:
Prerequisites: ~disabled
MRJ:
Buildable:
Prerequisites: ~disabled
MGG:
Buildable:
Prerequisites: ~disabled
STNK:
Buildable:
Prerequisites: ~disabled
QTNK:
Buildable:
Prerequisites: ~disabled
DTRK:
Buildable:
Prerequisites: ~disabled

View File

@@ -0,0 +1,419 @@
--[[
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 == "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 == "normal" 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
AlliedAirReinforcementsWaypoints =
{
{ AirReinforcementsEntry1.Location, AirReinforcementsRally1.Location },
{ AirReinforcementsEntry2.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)
ParadropWaypoints =
{
{ Angle.East + Angle.New(16), ParaDrop1},
{ Angle.East - Angle.New(16), ParaDrop2},
{ Angle.East + Angle.New(16), Alliesbase2},
{ Angle.East - Angle.New(16), Alliesbase1}
}
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, _)
Utils.Do(units, function(unit)
if not unit.IsDead then
Trigger.OnIdle(unit, function()
local bool = Utils.All(units, function(unit) return unit.IsIdle end)
if bool then
SetupHuntTrigger(units)
end
end)
Trigger.OnDamaged(unit, function()
SetupHuntTrigger(units)
end)
Trigger.OnCapture(unit, function()
Trigger.ClearAll(unit)
end)
end
end)
end
SetupHuntTrigger = function(units)
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)
Trigger.OnCapture(unit, function()
Trigger.ClearAll(unit)
end)
end
end)
end
end)
end
Ticked = TimerTicks
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 Ticked > 0 then
if DateTime.Minutes(20) == Ticked then
Media.PlaySpeechNotification(Allies, "TwentyMinutesRemaining")
elseif DateTime.Minutes(10) == Ticked then
Media.PlaySpeechNotification(Allies, "TenMinutesRemaining")
elseif DateTime.Minutes(5) == Ticked then
Media.PlaySpeechNotification(Allies, "WarningFiveMinutesRemaining")
elseif DateTime.Minutes(4) == Ticked then
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)
elseif DateTime.Minutes(3) == Ticked then
Media.PlaySpeechNotification(Allies, "WarningThreeMinutesRemaining")
elseif DateTime.Minutes(2) == Ticked then
Media.PlaySpeechNotification(Allies, "WarningTwoMinutesRemaining")
AttackAtFrameIncrement = DateTime.Seconds(4)
AttackAtFrameIncrementInf = DateTime.Seconds(4)
elseif DateTime.Minutes(1) == Ticked then
Media.PlaySpeechNotification(Allies, "WarningOneMinuteRemaining")
elseif DateTime.Seconds(45) == Ticked then
Media.PlaySpeechNotification(Allies, "AlliedForcesApproaching")
end
if (Ticked % DateTime.Seconds(1)) == 0 then
Timer = UserInterface.GetFluentMessage("french-reinforcements-arrive-in", { ["time"] = Utils.FormatTime(Ticked) })
UserInterface.SetMissionText(Timer, TimerColor)
end
Ticked = Ticked - 1
elseif Ticked == 0 then
FinishTimer()
TimerExpired()
Ticked = Ticked - 1
end
end
FrenchAlliesArrived = UserInterface.GetFluentMessage("french-allies-arrived")
FinishTimer = function()
for i = 0, 9, 1 do
local c = TimerColor
if i % 2 == 0 then
c = HSLColor.White
end
Trigger.AfterDelay(DateTime.Seconds(i), function() UserInterface.SetMissionText(FrenchAlliesArrived, c) end)
end
Trigger.AfterDelay(DateTime.Seconds(10), function() UserInterface.SetMissionText("") end)
end
SendSovietParadrops = function(table)
local aircraft = ParaTroopersPowerProxy.TargetParatroopers(table[2].CenterPosition, table[1])
Utils.Do(aircraft, function(a)
Trigger.OnPassengerExited(a, function(t, p)
IdleHunt(p)
end)
end)
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
TimerExpired = function()
SpawningSovietUnits = false
SpawningInfantry = false
SpawnNavalUnits = false
Beacon.New(Allies, SovietEntryPoint7.CenterPosition - WVec.New(3 * 1024, 0, 0))
Media.PlaySpeechNotification(Allies, "AlliedReinforcementsArrived")
Reinforcements.Reinforce(Allies, FrenchReinforcements, { SovietEntryPoint7.Location, Alliesbase.Location })
if DestroyObj then
KillObj = AddPrimaryObjective(Allies, "takeover-reinforcements-kill-remaining-soviet-forces")
else
DestroyObj = AddPrimaryObjective(Allies, "takeover-reinforcements-dismantle-soviet-base")
end
Allies.MarkCompletedObjective(SurviveObj)
if not Allies.IsObjectiveCompleted(KillSams) then
Allies.MarkFailedObjective(KillSams)
end
end
DropAlliedArtillery = function(facing, dropzone)
local proxy = Actor.Create("powerproxy.allied", true, { Owner = Allies })
proxy.TargetParatroopers(dropzone, facing)
proxy.Destroy()
end
SendLongBowReinforcements = function()
Media.PlaySpeechNotification(Allies, "AlliedReinforcementsArrived")
Reinforcements.Reinforce(Allies, LongBowReinforcements, AlliedAirReinforcementsWaypoints[1])
Reinforcements.Reinforce(Allies, LongBowReinforcements, AlliedAirReinforcementsWaypoints[2])
if ParadropArtillery then
local facing = Angle.New(Utils.RandomInteger(128, 384))
DropAlliedArtillery(facing, Alliesbase.CenterPosition)
end
end
AddObjectives = function()
InitObjectives(Allies)
SurviveObj = AddPrimaryObjective(Allies, "enforce-position-hold-until-reinforcements")
KillSams = AddSecondaryObjective(Allies, "destroy-two-sams-before-reinforcements")
Media.DisplayMessage(UserInterface.GetFluentMessage("soviets-blocking-gps"))
CaptureAirfields = AddSecondaryObjective(Allies, "capture-hold-soviet-airbase-northeast")
SovietObj = AddPrimaryObjective(Soviets, "")
Trigger.OnPlayerWon(Allies, function()
Media.DisplayMessage(UserInterface.GetFluentMessage("french-survived-dismantled-soviet-presence"))
end)
end
InitMission = function()
Camera.Position = Alliesbase.CenterPosition
local camera1 = Actor.Create("camera.sam", true, { Owner = Allies, Location = Sam1.Location })
local 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 = AddPrimaryObjective(Allies, "kill-remaining-soviet-forces")
end
Allies.MarkCompletedObjective(DestroyObj)
else
DestroyObj = AddPrimaryObjective(Allies, "dismantle-nearby-soviet-base")
Allies.MarkCompletedObjective(DestroyObj)
end
end)
Trigger.AfterDelay(DateTime.Seconds(1), function() Media.PlaySpeechNotification(Allies, "MissionTimerInitialised") end)
TimerColor = Allies.Color
end
SetupSoviets = function()
Barrack1.IsPrimaryBuilding = true
Barrack1.RallyPoint = SovietInfantryRally1.Location
Trigger.OnKilledOrCaptured(Barrack1, function()
SpawningInfantry = false
end)
Trigger.AfterDelay(0, function()
local buildings = Utils.Where(Map.ActorsInWorld, 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 })
ParaTroopersPowerProxy = Actor.Create("powerproxy.paratroopers", false, { Owner = Soviets })
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")
AddObjectives()
InitMission()
SetupSoviets()
end