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

View File

@@ -0,0 +1,150 @@
--[[
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.
]]
AttackGroup = { }
AttackGroupSize = 10
BGAttackGroup = { }
BGAttackGroupSize = 8
SovietInfantry = { "e1", "e2", "e4" }
SovietVehicles = { "3tnk", "3tnk", "v2rl" }
SovietAircraftType = { "mig", "yak" }
Planes = { }
ProductionInterval =
{
easy = DateTime.Seconds(30),
normal = DateTime.Seconds(20),
hard = DateTime.Seconds(10)
}
SendBGAttackGroup = function()
if #BGAttackGroup < BGAttackGroupSize then
return
end
Utils.Do(BGAttackGroup, function(unit)
if not unit.IsDead then
IdleHunt(unit)
end
end)
BGAttackGroup = { }
end
ProduceBadGuyInfantry = function()
if BadGuyRax.IsDead or BadGuyRax.Owner ~= BadGuy then
return
end
BadGuy.Build({ Utils.Random(SovietInfantry) }, function(units)
table.insert(BGAttackGroup, units[1])
SendBGAttackGroup()
Trigger.AfterDelay(ProductionInterval[Difficulty], ProduceBadGuyInfantry)
end)
end
SendAttackGroup = function()
if #AttackGroup < AttackGroupSize then
return
end
Utils.Do(AttackGroup, function(unit)
if not unit.IsDead then
IdleHunt(unit)
end
end)
AttackGroup = { }
end
ProduceUSSRInfantry = function()
if (USSRRax1.IsDead or USSRRax1.Owner ~= USSR) and (USSRRax2.IsDead or USSRRax2.Owner ~= USSR) then
return
end
USSR.Build({ Utils.Random(SovietInfantry) }, function(units)
table.insert(AttackGroup, units[1])
SendAttackGroup()
Trigger.AfterDelay(ProductionInterval[Difficulty], ProduceUSSRInfantry)
end)
end
ProduceVehicles = function()
if USSRWarFactory.IsDead or USSRWarFactory.Owner ~= USSR then
return
end
USSR.Build({ Utils.Random(SovietVehicles) }, function(units)
table.insert(AttackGroup, units[1])
SendAttackGroup()
Trigger.AfterDelay(ProductionInterval[Difficulty], ProduceVehicles)
end)
end
GroundAttackUnits = { {"4tnk", "3tnk", "e2", "e2", "e2", "e2" }, { "3tnk", "3tnk", "v2rl", "e4", "e4", "e4" }, {"ttnk", "ttnk", "ttnk", "shok", "shok", "shok" } }
GroundAttackPaths =
{
{ SovietGroundEntry1.Location },
{ SovietGroundEntry2.Location },
{ SovietGroundEntry3.Location }
}
GroundWavesDelays =
{
easy = 4,
normal = 3,
hard = 2
}
GroundWavesDelay = GroundWavesDelays[Difficulty]
GroundWaves = function()
if not ForwardCommand.IsDead then
local path = Utils.Random(GroundAttackPaths)
local units = Reinforcements.Reinforce(BadGuy, Utils.Random(GroundAttackUnits), path)
Utils.Do(units, IdleHunt)
Trigger.AfterDelay(DateTime.Minutes(GroundWavesDelay), GroundWaves)
end
end
ProduceAircraft = function()
if Airfield.IsDead or Airfield.Owner ~= USSR then
return
end
USSR.Build({ Utils.Random(SovietAircraftType) }, function(units)
local plane = units[1]
Planes[#Planes + 1] = plane
Trigger.OnKilled(plane, ProduceAircraft)
local alive = Utils.Where(Planes, function(y) return not y.IsDead end)
if #alive < 2 then
Trigger.AfterDelay(DateTime.Seconds(ProductionInterval[Difficulty] / 2), ProduceAircraft)
end
InitializeAttackAircraft(plane, Greece)
end)
end
ActivateAI = function()
local buildings = Utils.Where(Map.ActorsInWorld, function(self) return self.Owner == USSR and self.HasProperty("StartBuildingRepairs") end)
Utils.Do(buildings, function(actor)
Trigger.OnDamaged(actor, function(building)
if building.Owner == USSR and building.Health < building.MaxHealth * 3/4 then
building.StartBuildingRepairs()
end
end)
end)
ProduceBadGuyInfantry()
ProduceUSSRInfantry()
ProduceVehicles()
Trigger.AfterDelay(DateTime.Minutes(GroundWavesDelay), GroundWaves)
Trigger.AfterDelay(DateTime.Minutes(5), ProduceAircraft)
end

View File

@@ -0,0 +1,159 @@
--[[
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.
]]
StartUnits = { APC, StartSpy, Rifle1, Rifle2, Rifle3, Rifle4, Rocket1, Rocket2, Rocket3, Rocket4, Rocket5 }
SarinPlants = { SarinLab1, SarinLab2, SarinLab3, SarinLab4, SarinLab5 }
MammothStart = { CPos.New(37, 46), CPos.New(37, 47), CPos.New(37, 48), CPos.New(37, 49), CPos.New(37,50) }
NorthPatrol = { NorthPatrol1.Location, NorthPatrol2.Location, NorthPatrol3.Location, NorthPatrol4.Location, NorthPatrol5.Location }
BarrerlInvestigators = { Alert1, Alert2, Alert3, Alert4, Alert5 }
RaxTeam = { "e1", "e2", "e2", "e4", "e4", "shok" }
SouthPatrol = { SouthPatrol1.Location, SouthPatrol2.Location, SouthPatrol3.Location }
MCVReinforcements =
{
easy = { "1tnk", "1tnk", "2tnk", "2tnk", "2tnk", "2tnk", "arty", "mcv" },
normal = { "1tnk", "1tnk", "2tnk", "2tnk", "mcv" },
hard = { "1tnk", "1tnk", "mcv" }
}
SetupTriggers = function()
Trigger.OnEnteredFootprint(MammothStart, function(actor, mammothcam)
if actor.Owner == Greece then
Trigger.RemoveFootprintTrigger(mammothcam)
NorthMammoth.Patrol(NorthPatrol, true, 20)
local mammothCamera = Actor.Create("camera", true, { Owner = Greece, Location = NorthPatrol1.Location })
Trigger.AfterDelay(DateTime.Seconds(10), function()
mammothCamera.Destroy()
end)
end
end)
Trigger.OnEnteredProximityTrigger(NorthPatrol3.CenterPosition, WDist.FromCells(8), function(actor, trigger1)
if actor.Owner == Greece then
Trigger.RemoveProximityTrigger(trigger1)
local baseCamera = Actor.Create("camera", true, { Owner = Greece, Location = BaseCam.Location })
if Difficulty == "hard" then
Reinforcements.Reinforce(BadGuy, RaxTeam, { BadGuyRaxSpawn.Location, BaseCam.Location }, 0)
end
Trigger.AfterDelay(DateTime.Seconds(10), function()
baseCamera.Destroy()
end)
end
end)
Trigger.OnAllRemovedFromWorld(StartUnits, function()
if not MCVArrived then
USSR.MarkCompletedObjective(SovietObj)
end
end)
Trigger.OnKilled(VeryImportantBarrel, function()
Utils.Do(BarrerlInvestigators, function(actor)
if not actor.IsDead then
actor.AttackMove(AlertGo.Location)
end
end)
end)
Trigger.OnAnyKilled(SarinPlants, function()
Greece.MarkFailedObjective(CaptureSarin)
end)
Trigger.OnAllKilledOrCaptured(SarinPlants, function()
Greece.MarkCompletedObjective(CaptureSarin)
end)
Trigger.OnEnteredProximityTrigger(AlliesMove.CenterPosition, WDist.FromCells(3), function(actor, id)
if actor.Owner == Greece then
Trigger.RemoveProximityTrigger(id)
Media.PlaySpeechNotification(Greece, "SignalFlareSouth")
end
end)
end
MCVArrived = false
MCVArrivedTick = false
PowerDownTeslas = function()
if not MCVArrived then
CaptureSarin = AddPrimaryObjective(Greece, "capture-sarin-plants-intact")
KillBase = AddPrimaryObjective(Greece, "destroy-enemy-compound")
Greece.MarkCompletedObjective(TakeOutPower)
Media.PlaySpeechNotification(Greece, "ReinforcementsArrived")
Reinforcements.Reinforce(Greece, MCVReinforcements[Difficulty], { AlliesSpawn.Location, AlliesMove.Location })
local baseFlare = Actor.Create("flare", true, { Owner = Greece, Location = AlliedBase.Location })
Actor.Create("proc", true, { Owner = USSR, Location = Proc1.Location })
Actor.Create("proc", true, { Owner = USSR, Location = Proc2.Location })
SouthMammoth.Patrol(SouthPatrol, true, 20)
MCVArrived = true
Trigger.AfterDelay(DateTime.Seconds(1), function()
MCVArrivedTick = true
PrepareFinishingHunt(USSR)
end)
Trigger.AfterDelay(DateTime.Seconds(60), function()
local attackers = Reinforcements.Reinforce(USSR, { "e1", "e1", "e1", "e2", "e4" }, { SovietGroundEntry3.Location }, 5)
Utils.Do(attackers, IdleHunt)
end)
Trigger.AfterDelay(DateTime.Seconds(100), function()
baseFlare.Destroy()
ActivateAI()
end)
end
end
PrepareFinishingHunt = function(player)
local buildings = GetBaseBuildings(player)
Trigger.OnAllKilledOrCaptured(buildings, function()
Utils.Do(player.GetGroundAttackers(), function(actor)
actor.Stop()
IdleHunt(actor)
end)
end)
end
GetBaseBuildings = function(player)
-- Excludes the unrepairable sarin plants, which is desired anyway.
local buildings = Utils.Where(player.GetActors(), function(actor)
return actor.HasProperty("StartBuildingRepairs")
end)
return buildings
end
Tick = function()
USSR.Cash = 10000
BadGuy.Cash = 10000
if BadGuy.PowerState ~= "Normal" then
PowerDownTeslas()
end
if Greece.HasNoRequiredUnits() and MCVArrivedTick then
USSR.MarkCompletedObjective(SovietObj)
end
if USSR.HasNoRequiredUnits() then
Greece.MarkCompletedObjective(KillBase)
end
end
WorldLoaded = function()
Greece = Player.GetPlayer("Greece")
USSR = Player.GetPlayer("USSR")
BadGuy = Player.GetPlayer("BadGuy")
SovietObj = AddPrimaryObjective(USSR, "")
TakeOutPower = AddPrimaryObjective(Greece, "cut-power-east")
InitObjectives(Greece)
StartSpy.DisguiseAsType("e1", BadGuy)
Camera.Position = DefaultCameraPosition.CenterPosition
SetupTriggers()
end

Binary file not shown.

View File

@@ -0,0 +1,7 @@
## rules.yaml
briefing =
We have infiltrated the Soviets' Sarin facility. However, the main entrance is guarded by a wall of Tesla coils. We can't move a large force in until they are taken down.
Infiltrate the power grid to the east or destroy the power plants. Once done, reinforcements will arrive.
Destroy the Soviet compound, but capture all of the Sarin processor buildings intact -- we can't risk a chemical spill.

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,79 @@
World:
LuaScript:
Scripts: campaign.lua, utils.lua, controlledburn.lua, controlledburn-AI.lua
MissionData:
WinVideo: apcescpe.vqa
LossVideo: tesla.vqa
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
Player:
PlayerResources:
DefaultCash: 7500
HARV:
-MustBeDestroyed:
APC:
Buildable:
Prerequisites: ~vehicles.allies
MGG:
Buildable:
Prerequisites: ~disabled
FTRK:
Buildable:
Prerequisites: ~disabled
DTRK:
Buildable:
Prerequisites: ~disabled
CTNK:
Buildable:
Prerequisites: ~disabled
STNK:
Buildable:
Prerequisites: ~disabled
MSLO:
Buildable:
Prerequisites: ~disabled
ATEK:
Buildable:
Prerequisites: ~disabled
BIO:
Tooltip:
Name: actor-sarin-processing-plant-name
E7:
Buildable:
Prerequisites: ~disabled
E3:
Buildable:
Prerequisites: ~tent
MH60:
Buildable:
Prerequisites: ~disabled
TRAN:
Buildable:
Prerequisites: ~disabled
HELI:
Buildable:
Prerequisites: ~hpad