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,367 @@
--[[
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.GetFluentMessage("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.GetFluentMessage("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

Binary file not shown.

View File

@@ -0,0 +1,2 @@
## rules.yaml
briefing = The Soviets are currently developing a new weapon system at a secret research laboratory. This is a reconnaissance mission. Do not engage until we know what we are up against and wait for reinforcements. Our civilian contacts reported a heavily guarded installation under ruthless command.

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,235 @@
World:
TintPostProcessEffect@HAZE:
Red: 1
Green: 0.55
Blue: 0
MissionData:
Briefing: briefing
LuaScript:
Scripts: campaign.lua, utils.lua, infiltration.lua
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
TimeLimitManager:
TimeLimitLocked: True
^Palettes:
FixedColorPalette@SovietTruk:
Base: player
Name: truk-soviets
RemapIndex: 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95
Color: FE1100
IndexedPlayerPalette:
PlayerIndex:
Allies: 224, 224, 225, 225, 226, 184, 185, 186, 187, 188, 188, 189, 190, 190, 191, 191
Allies1: 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175
Allies2: 208, 208, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 154, 155, 143
IndexedPlayerPalette@NOSHADOW:
PlayerIndex:
Allies: 224, 224, 225, 225, 226, 184, 185, 186, 187, 188, 188, 189, 190, 190, 191, 191
Allies1: 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175
Allies2: 208, 208, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 154, 155, 143
MISS:
Targetable:
TargetTypes: GroundActor, C4, DetonateAttack, Structure, MissionObjective, NoAutoTarget
LST.Unselectable.UnloadOnly:
Inherits: LST
-Selectable:
RenderSprites:
Image: LST
Buildable:
Prerequisites: ~disabled
Cargo:
MaxWeight: 0
Targetable:
TargetTypes: GroundActor, Water, Repair, NoAutoTarget
Interactable:
SPY.Strong:
Inherits: SPY
Buildable:
Prerequisites: ~disabled
RenderSprites:
Image: SPY
Health:
HP: 10000
RevealsShroud:
Range: 6c0
Infiltrates:
Types: MissionObjective
CaptureManager:
Captures:
CaptureTypes: MissionObjective
ConsumedByCapture: False
EnterCursor: ability
EnterBlockedCursor: move-blocked
Passenger:
DOG.Patrol:
Inherits: DOG
Buildable:
Prerequisites: ~disabled
Mobile:
Speed: 56
RenderSprites:
Image: DOG
TRUK.Hijackable:
Inherits: TRUK
Inherits@CARGOPIPS: ^CargoPips
Buildable:
Prerequisites: ~disabled
Mobile:
RequiresCondition: mobile && !being-captured
Cargo:
Types: Infantry
MaxWeight: 5
PassengerConditions:
spy.strong: mobile
Targetable:
TargetTypes: GroundActor, Repair, Vehicle, NoAutoTarget
-Huntable:
Capturable:
Types: MissionObjective
-DeliversCash:
RenderSprites:
Image: TRUK
Palette: truk-soviets
RevealsShroud:
Range: 6c0
Voiced:
VoiceSet: SpyVoice
E7:
Buildable:
Prerequisites: ~disabled
TRAN:
Buildable:
Prerequisites: ~disabled
BARR:
Buildable:
Prerequisites: ~disabled
MIG:
Buildable:
Prerequisites: ~disabled
HELI:
Buildable:
Prerequisites: ~disabled
SS:
Buildable:
Prerequisites: ~disabled
AutoTarget:
InitialStanceAI: Defend
ARTY:
Buildable:
Prerequisites: ~disabled
AGUN:
Buildable:
Prerequisites: ~disabled
MSUB:
Buildable:
Prerequisites: ~disabled
CA:
Buildable:
Prerequisites: ~disabled
MSLO:
Buildable:
Prerequisites: ~disabled
SPEN:
Buildable:
Prerequisites: ~disabled
IRON:
Buildable:
Prerequisites: ~disabled
PDOX:
Buildable:
Prerequisites: ~disabled
TSLA:
Buildable:
Prerequisites: ~disabled
FTUR:
Buildable:
Prerequisites: ~disabled
SAM:
Buildable:
Prerequisites: ~disabled
HPAD:
Buildable:
Prerequisites: ~disabled
AFLD:
Buildable:
Prerequisites: ~disabled
ATEK:
Buildable:
Prerequisites: ~disabled
STEK:
Buildable:
Prerequisites: ~disabled
4TNK:
Buildable:
Prerequisites: ~disabled
MCV:
Buildable:
Prerequisites: ~disabled
APC:
Buildable:
Prerequisites: ~disabled
MNLY:
Buildable:
Prerequisites: ~disabled
TTNK:
Buildable:
Prerequisites: ~disabled
FTRK:
Buildable:
Prerequisites: ~disabled
CTNK:
Buildable:
Prerequisites: ~disabled
MGG:
Buildable:
Prerequisites: ~disabled
MRJ:
Buildable:
Prerequisites: ~disabled
GAP:
Buildable:
Prerequisites: ~disabled