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,7 @@
## rules.yaml
briefing =
There is a special cargo that needs to be transported to a nearby Soviet base in the northeast.
Make sure the trucks reach their destination intact. Along the way, there is a bridge which the Allies have likely destroyed.
Use the Naval options at your disposal. Our attack subs will make short work of any Allied boats you discover.

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -0,0 +1,852 @@
MapFormat: 12
RequiresMod: ra
Title: 06a: Bridge over the River Grotzny
Author: Westwood Studios
Tileset: TEMPERAT
MapSize: 128,128
Bounds: 5,1,93,53
Visibility: MissionSelector
Categories: Campaign
LockPreview: True
Players:
PlayerReference@Neutral:
Name: Neutral
OwnsWorld: True
NonCombatant: True
Faction: allies
PlayerReference@Greece:
Name: Greece
Bot: campaign
Faction: allies
Color: E2E6F5
Enemies: USSR
PlayerReference@USSR:
Name: USSR
AllowBots: False
Playable: True
Required: True
LockFaction: True
Faction: soviet
LockColor: True
Color: FE1100
LockSpawn: True
LockTeam: True
Enemies: Greece
Actors:
Actor0: cycl
Location: 17,1
Owner: Greece
Actor1: cycl
Location: 18,1
Owner: Greece
Actor2: cycl
Location: 19,1
Owner: Greece
Actor3: cycl
Location: 20,1
Owner: Greece
Actor4: cycl
Location: 21,1
Owner: Greece
Actor5: cycl
Location: 22,1
Owner: Greece
Actor6: cycl
Location: 23,1
Owner: Greece
Actor7: cycl
Location: 24,1
Owner: Greece
Actor8: cycl
Location: 25,1
Owner: Greece
Actor9: cycl
Location: 26,1
Owner: Greece
Actor10: cycl
Location: 27,1
Owner: Greece
Actor11: cycl
Location: 28,1
Owner: Greece
Actor12: cycl
Location: 29,1
Owner: Greece
Actor13: cycl
Location: 30,1
Owner: Greece
Actor14: cycl
Location: 31,1
Owner: Greece
Actor15: cycl
Location: 32,1
Owner: Greece
Actor16: cycl
Location: 33,1
Owner: Greece
Actor17: cycl
Location: 34,1
Owner: Greece
Actor18: cycl
Location: 35,1
Owner: Greece
Actor19: cycl
Location: 17,2
Owner: Greece
Actor20: cycl
Location: 17,3
Owner: Greece
Actor21: cycl
Location: 18,3
Owner: Greece
Actor22: cycl
Location: 17,4
Owner: Greece
Actor23: cycl
Location: 18,4
Owner: Greece
Actor24: cycl
Location: 17,10
Owner: Greece
Actor25: cycl
Location: 18,10
Owner: Greece
Actor26: cycl
Location: 17,11
Owner: Greece
Actor27: cycl
Location: 18,11
Owner: Greece
Actor28: cycl
Location: 17,12
Owner: Greece
Actor29: cycl
Location: 17,13
Owner: Greece
Actor30: cycl
Location: 17,14
Owner: Greece
Actor31: cycl
Location: 17,15
Owner: Greece
Actor32: cycl
Location: 17,16
Owner: Greece
Actor33: cycl
Location: 17,17
Owner: Greece
Actor34: cycl
Location: 17,18
Owner: Greece
Actor35: cycl
Location: 18,18
Owner: Greece
Actor36: cycl
Location: 18,19
Owner: Greece
Actor37: cycl
Location: 31,19
Owner: Greece
Actor38: cycl
Location: 32,19
Owner: Greece
Actor39: cycl
Location: 18,20
Owner: Greece
Actor40: cycl
Location: 31,20
Owner: Greece
Actor41: cycl
Location: 17,21
Owner: Greece
Actor42: cycl
Location: 18,21
Owner: Greece
Actor43: cycl
Location: 31,21
Owner: Greece
Actor44: cycl
Location: 17,22
Owner: Greece
Actor45: sbag
Location: 19,22
Owner: Greece
Actor46: sbag
Location: 20,22
Owner: Greece
Actor47: sbag
Location: 21,22
Owner: Greece
Actor48: sbag
Location: 27,22
Owner: Greece
Actor49: sbag
Location: 28,22
Owner: Greece
Actor50: sbag
Location: 29,22
Owner: Greece
Actor51: cycl
Location: 31,22
Owner: Greece
Actor52: cycl
Location: 17,23
Owner: Greece
Actor53: sbag
Location: 21,23
Owner: Greece
Actor54: sbag
Location: 27,23
Owner: Greece
Actor55: cycl
Location: 31,23
Owner: Greece
Actor56: cycl
Location: 17,24
Owner: Greece
Actor57: cycl
Location: 18,24
Owner: Greece
Actor58: cycl
Location: 19,24
Owner: Greece
Actor59: cycl
Location: 20,24
Owner: Greece
Actor60: cycl
Location: 21,24
Owner: Greece
Actor61: cycl
Location: 27,24
Owner: Greece
Actor62: cycl
Location: 28,24
Owner: Greece
Actor63: cycl
Location: 29,24
Owner: Greece
Actor64: cycl
Location: 30,24
Owner: Greece
Actor65: cycl
Location: 31,24
Owner: Greece
Actor66: sbag
Location: 71,31
Owner: Greece
Actor67: sbag
Location: 72,31
Owner: Greece
Actor68: sbag
Location: 71,32
Owner: Greece
Actor69: sbag
Location: 72,32
Owner: Greece
Actor70: sbag
Location: 72,33
Owner: Greece
Actor71: sbag
Location: 73,33
Owner: Greece
Actor72: sbag
Location: 73,34
Owner: Greece
Actor73: sbag
Location: 74,34
Owner: Greece
Actor74: sbag
Location: 75,34
Owner: Greece
Actor75: sbag
Location: 74,35
Owner: Greece
Actor76: sbag
Location: 75,35
Owner: Greece
Actor77: t17
Location: 66,28
Owner: Neutral
Actor78: t08
Location: 83,35
Owner: Neutral
Actor79: t16
Location: 82,34
Owner: Neutral
Actor80: tc04
Location: 80,36
Owner: Neutral
Actor81: tc05
Location: 77,34
Owner: Neutral
Actor82: tc01
Location: 79,32
Owner: Neutral
Actor83: tc01
Location: 61,52
Owner: Neutral
Actor84: tc02
Location: 61,49
Owner: Neutral
Actor85: tc03
Location: 58,52
Owner: Neutral
Actor86: tc05
Location: 52,47
Owner: Neutral
Actor87: t16
Location: 35,21
Owner: Neutral
Actor88: tc04
Location: 36,24
Owner: Neutral
Actor89: t15
Location: 38,22
Owner: Neutral
Actor90: t12
Location: 31,24
Owner: Neutral
Actor91: tc05
Location: 95,15
Owner: Neutral
Actor92: tc01
Location: 94,19
Owner: Neutral
Actor93: tc03
Location: 85,13
Owner: Neutral
Actor94: tc02
Location: 94,6
Owner: Neutral
Actor95: tc01
Location: 96,11
Owner: Neutral
Actor96: tc04
Location: 84,4
Owner: Neutral
Actor97: t17
Location: 83,13
Owner: Neutral
Actor98: t16
Location: 88,11
Owner: Neutral
Actor99: t16
Location: 91,23
Owner: Neutral
Actor100: t14
Location: 93,24
Owner: Neutral
Actor101: t11
Location: 95,22
Owner: Neutral
Actor102: tc05
Location: 32,22
Owner: Neutral
Actor103: tc05
Location: 5,12
Owner: Neutral
Actor104: tc01
Location: 9,12
Owner: Neutral
Actor105: tc05
Location: 50,34
Owner: Neutral
Actor106: tc04
Location: 53,34
Owner: Neutral
Actor107: tc05
Location: 74,47
Owner: Neutral
Actor108: tc04
Location: 80,43
Owner: Neutral
Actor109: tc02
Location: 78,42
Owner: Neutral
Actor110: tc01
Location: 74,46
Owner: Neutral
Actor111: t17
Location: 73,48
Owner: Neutral
Actor112: t16
Location: 77,46
Owner: Neutral
Actor113: t15
Location: 80,41
Owner: Neutral
Actor114: t14
Location: 68,52
Owner: Neutral
Actor115: t13
Location: 84,40
Owner: Neutral
Actor116: tc02
Location: 65,52
Owner: Neutral
Actor117: tc01
Location: 66,49
Owner: Neutral
Actor118: t08
Location: 32,20
Owner: Neutral
Actor119: tc02
Location: 18,52
Owner: Neutral
Actor120: t15
Location: 27,51
Owner: Neutral
Actor121: t11
Location: 40,40
Owner: Neutral
Actor122: t10
Location: 41,34
Owner: Neutral
Actor123: t10
Location: 43,29
Owner: Neutral
Actor124: t08
Location: 41,32
Owner: Neutral
Actor125: t08
Location: 42,41
Owner: Neutral
Actor126: tc05
Location: 29,28
Owner: Neutral
Actor127: tc02
Location: 19,26
Owner: Neutral
Actor128: tc04
Location: 17,24
Owner: Neutral
Actor129: t14
Location: 37,33
Owner: Neutral
Actor130: tc01
Location: 38,28
Owner: Neutral
Actor131: t16
Location: 39,27
Owner: Neutral
Actor132: t16
Location: 37,28
Owner: Neutral
Actor133: t10
Location: 11,49
Owner: Neutral
Actor134: tc05
Location: 12,24
Owner: Neutral
Actor135: tc04
Location: 5,30
Owner: Neutral
Actor136: tc02
Location: 12,12
Owner: Neutral
Actor137: t16
Location: 11,12
Owner: Neutral
Actor234: t12
Owner: Neutral
Location: 15,14
Actor139: t08
Location: 16,15
Owner: Neutral
Actor140: t01
Location: 8,12
Owner: Neutral
Actor141: t10
Location: 13,33
Owner: Neutral
Actor142: t15
Location: 7,40
Owner: Neutral
Actor143: t14
Location: 17,32
Owner: Neutral
Actor144: tc02
Location: 5,39
Owner: Neutral
Actor145: tc03
Location: 85,6
Owner: Neutral
Actor233: t01
Owner: Neutral
Location: 15,13
Actor147: t10
Location: 14,12
Owner: Neutral
Actor148: tc05
Location: 81,4
Owner: Neutral
Actor149: t01
Location: 61,9
Owner: Neutral
Actor150: tc03
Location: 71,6
Owner: Neutral
Actor151: t17
Location: 60,6
Owner: Neutral
Actor152: t11
Location: 70,3
Owner: Neutral
Actor153: tc05
Location: 22,2
Owner: Neutral
Actor154: tc03
Location: 28,2
Owner: Neutral
Actor155: tc01
Location: 33,1
Owner: Neutral
Hbox1: hbox
Location: 19,23
Owner: Greece
Hbox2: hbox
Location: 29,23
Owner: Greece
Gun3: gun
Location: 20,23
Owner: Greece
Facing: 512
TurretFacing: 0
Gun4: gun
Location: 28,23
Owner: Greece
Facing: 512
TurretFacing: 0
Gap: gap
Location: 24,22
Owner: Greece
Syrd: syrd
Location: 35,14
Owner: Greece
Gun1: gun
Location: 33,5
Owner: Greece
Facing: 768
TurretFacing: 512
Gun2: gun
Location: 33,9
Owner: Greece
Facing: 768
TurretFacing: 512
Actor169: v07
Location: 66,4
Owner: Greece
Health: 45
Actor170: v03
Location: 64,8
Owner: Greece
Actor171: v01
Location: 71,8
Owner: Greece
Actor172: v05
Location: 61,8
Owner: Greece
Health: 43
Actor173: v06
Location: 68,4
Owner: Greece
Powr1: powr
Location: 20,2
Owner: Greece
Powr2: powr
Location: 25,2
Owner: Greece
Actor179: 2tnk
Location: 73,35
Owner: Greece
Facing: 384
Actor180: 2tnk
Location: 72,34
Owner: Greece
Facing: 384
Actor181: 2tnk
Location: 71,33
Owner: Greece
Facing: 384
Actor182: arty
Location: 74,33
Owner: Greece
Facing: 384
Stance: Defend
Actor183: arty
Location: 73,32
Owner: Greece
Facing: 384
Stance: Defend
Actor186: 3tnk
Location: 56,47
Owner: USSR
Facing: 896
Actor187: 3tnk
Location: 60,49
Owner: USSR
Facing: 896
Actor191: v2rl
Location: 57,49
Owner: USSR
Facing: 896
Actor193: 2tnk
Location: 73,31
Owner: Greece
Facing: 384
Actor194: 2tnk
Location: 75,33
Owner: Greece
Facing: 384
Actor195: 2tnk
Location: 85,18
Owner: Greece
Facing: 384
Actor196: 2tnk
Location: 88,20
Owner: Greece
Facing: 384
Actor197: 2tnk
Location: 22,23
Owner: Greece
Facing: 512
Actor198: 2tnk
Location: 26,23
Owner: Greece
Facing: 512
Actor199: arty
Location: 18,23
Owner: Greece
Facing: 640
Stance: Defend
Actor200: arty
Location: 30,23
Owner: Greece
Facing: 384
Stance: Defend
Actor202: 1tnk
Location: 23,21
Owner: Greece
Facing: 512
Actor203: 1tnk
Location: 25,21
Owner: Greece
Facing: 512
Actor204: 2tnk
Location: 40,6
Owner: Greece
Facing: 256
Actor205: 2tnk
Location: 40,8
Owner: Greece
Facing: 256
Actor206: arty
Location: 40,7
Owner: Greece
Facing: 256
Stance: Defend
Actor207: 1tnk
Location: 77,10
Owner: Greece
Facing: 256
Actor208: 1tnk
Location: 77,11
Owner: Greece
Facing: 256
Actor209: 1tnk
Location: 77,12
Owner: Greece
Facing: 256
BridgeBreaker2: ca
Location: 87,29
Owner: Greece
Facing: 128
BridgeBreaker1: ca
Location: 87,25
Owner: Greece
Facing: 384
ResponseCruiser: ca
Location: 76,22
Owner: Greece
Facing: 128
Actor213: pt
Location: 38,4
Owner: Greece
Facing: 256
Actor214: pt
Location: 38,10
Owner: Greece
Facing: 256
Actor215: dd
Location: 55,15
Owner: Greece
Facing: 256
waypoint0: waypoint
Location: 39,13
Owner: Neutral
Silo4: silo
Owner: Greece
Location: 26,9
Silo3: silo
Owner: Greece
Location: 24,9
Silo1: silo
Owner: Greece
Location: 27,2
Silo2: silo
Owner: Greece
Location: 27,3
waypoint78: waypoint
Location: 83,23
Owner: Neutral
waypoint79: waypoint
Location: 87,19
Owner: Neutral
waypoint80: waypoint
Location: 84,22
Owner: Neutral
waypoint81: waypoint
Location: 76,22
Owner: Neutral
waypoint82: waypoint
Location: 87,29
Owner: Neutral
AGun: agun
Owner: Greece
Location: 25,5
TurretFacing: 368
APCWaypoint1: waypoint
Location: 52,50
Owner: Neutral
APCWaypoint2: waypoint
Location: 58,51
Owner: Neutral
Apwr1: apwr
Location: 18,12
Owner: Greece
Apwr2: apwr
Owner: Greece
Location: 27,6
AttackWaypoint1: waypoint
Owner: Neutral
Location: 24,30
AttackWaypoint2: waypoint
Owner: Neutral
Location: 35,30
Tent: tent
Location: 29,16
Owner: Greece
BaseAttacker1: 1tnk
Location: 76,35
Owner: Greece
Facing: 384
BaseAttacker2: 1tnk
Location: 71,30
Owner: Greece
Facing: 384
CameraBarrier: camera
Location: 70,36
Owner: Neutral
CameraBase1: camera
Location: 34,40
Owner: Neutral
CameraBase2: camera
Location: 24,40
Owner: Neutral
CameraBase3: camera
Location: 30,46
Owner: Neutral
CameraBase4: camera
Location: 48,39
Owner: Neutral
CameraStart: camera
Location: 58,48
Owner: Neutral
CYard: fact
Location: 30,2
Owner: Greece
CYardLocation: waypoint
Owner: Neutral
Location: 31,4
Dome: dome
Location: 23,5
Owner: Greece
EnemyEntry1: waypoint
Owner: Neutral
Location: 10,1
EnemyEntry2: waypoint
Owner: Neutral
Location: 97,37
EnemyRally1: waypoint
Owner: Neutral
Location: 9,23
EnemyRally2: waypoint
Owner: Neutral
Location: 88,37
Harvester: harv
Location: 12,10
Owner: Greece
IntroEnemy1: 1tnk
Location: 63,42
Owner: Greece
Health: 28
Facing: 384
IntroEnemy2: jeep
Location: 64,42
Owner: Greece
Health: 43
Facing: 384
IntroEnemy3: 1tnk
Location: 64,43
Owner: Greece
Health: 50
Facing: 384
Mcv: mcv
Location: 61,45
Owner: USSR
Facing: 640
McvWaypoint: waypoint
Location: 53,53
Owner: Neutral
Proc: proc
Location: 24,9
Owner: Greece
FreeActor: False
Truck1: truk
Location: 54,52
Owner: USSR
Facing: 896
Truck2: truk
Location: 55,51
Owner: USSR
Facing: 896
Weap: weap
Location: 22,15
Owner: Greece
NavyPatrol1: waypoint
Owner: Neutral
Location: 35,18
NavyPatrol2: waypoint
Owner: Neutral
Location: 36,10
NavyPatrol3: waypoint
Owner: Neutral
Location: 57,12
NavyPatrol4: waypoint
Owner: Neutral
Location: 76,17
Rules: ra|rules/campaign-rules.yaml, ra|rules/campaign-tooltips.yaml, ra|rules/campaign-palettes.yaml, rules.yaml
FluentMessages: ra|fluent/lua.ftl, ra|fluent/campaign.ftl, map.ftl

View File

@@ -0,0 +1,154 @@
Player:
PlayerResources:
DefaultCash: 11500
World:
LuaScript:
Scripts: campaign.lua, utils.lua, soviet06a.lua, soviet06a-AI.lua, soviet06a-reinforcements_teams.lua
MissionData:
Briefing: briefing
BriefingVideo: soviet6.vqa
StartVideo: onthprwl.vqa
WinVideo: sitduck.vqa
LossVideo: dpthchrg.vqa
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
APWR:
Buildable:
Prerequisites: ~structures.allies
ARTY:
Buildable:
Prerequisites: ~vehicles.allies, ~techlevel.low
ATEK:
Buildable:
Prerequisites: ~disabled
BRIK:
Buildable:
Prerequisites: ~disabled
TSLA:
Buildable:
Prerequisites: ~disabled
SAM:
Buildable:
Prerequisites: ~disabled
IRON:
Buildable:
Prerequisites: ~disabled
MECH:
Buildable:
Prerequisites: ~disabled
MSLO:
Buildable:
Prerequisites: ~disabled
E3:
Buildable:
Prerequisites: ~tent
E7:
Buildable:
Prerequisites: ~disabled
SHOK:
Buildable:
Prerequisites: ~disabled
SPY:
Buildable:
Prerequisites: ~disabled
THF:
Buildable:
Prerequisites: ~disabled
MIG:
Buildable:
Prerequisites: ~disabled
FTRK:
Buildable:
Prerequisites: ~disabled
2TNK:
Buildable:
Prerequisites: ~vehicles.allies, ~techlevel.low
4TNK:
Buildable:
Prerequisites: ~disabled
APC:
Buildable:
Prerequisites: ~disabled
TRUK:
-SpawnActorOnDeath:
-DeliversCash:
QTNK:
Buildable:
Prerequisites: ~disabled
MCV:
Buildable:
Prerequisites: ~disabled
MSUB:
Buildable:
Prerequisites: ~disabled
STEK:
Buildable:
Prerequisites: ~disabled
PDOX:
Buildable:
Prerequisites: ~disabled
MRJ:
Buildable:
Prerequisites: ~disabled
CA:
Buildable:
Prerequisites: ~disabled
HELI:
Buildable:
Prerequisites: ~disabled
GAP:
Buildable:
Prerequisites: ~disabled
MNLY:
Buildable:
Prerequisites: ~disabled
AFLD:
ParatroopersPower@paratroopers:
DropItems: E1,E1,E1,E1,E1
V01:
SpawnActorOnDeath:
Actor: moneycrate
V05:
SpawnActorOnDeath:
Actor: healcrate

View File

@@ -0,0 +1,239 @@
--[[
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.
]]
InfAttack = { }
ArmorAttack = { }
AttackPaths = { { AttackWaypoint1.Location }, { AttackWaypoint2.Location } }
AlliedInfantryTypes = { "e1", "e1", "e3" }
AlliedArmorTypes = { "jeep", "jeep", "1tnk", "1tnk", "2tnk", "2tnk", "arty" }
ProduceInfantry = function(barracks)
if barracks.IsDead or barracks.Owner ~= Greece then
return
elseif GreeceMoney() <= 299 and IsHarvesterMissing() then
return
end
local delay = Utils.RandomInteger(DateTime.Seconds(3), DateTime.Seconds(9))
local toBuild = { Utils.Random(AlliedInfantryTypes) }
local path = Utils.Random(AttackPaths)
Greece.Build(toBuild, function(units)
InfAttack[#InfAttack + 1] = units[1]
if #InfAttack >= 10 then
SendUnits(InfAttack, path)
InfAttack = { }
Trigger.AfterDelay(DateTime.Minutes(2), function()
ProduceInfantry(barracks)
end)
else
Trigger.AfterDelay(delay, function()
ProduceInfantry(barracks)
end)
end
end)
end
ProduceArmor = function(factory)
local delay = Utils.RandomInteger(DateTime.Seconds(12), DateTime.Seconds(17))
if factory.IsDead or factory.Owner ~= Greece then
return
elseif IsHarvesterMissing() then
ProduceHarvester(factory, delay)
return
end
local toBuild = { Utils.Random(AlliedArmorTypes) }
local path = Utils.Random(AttackPaths)
Greece.Build(toBuild, function(units)
ArmorAttack[#ArmorAttack + 1] = units[1]
if #ArmorAttack >= 6 then
SendUnits(ArmorAttack, path)
ArmorAttack = { }
Trigger.AfterDelay(DateTime.Minutes(3), function()
ProduceArmor(factory)
end)
else
Trigger.AfterDelay(delay, function()
ProduceArmor(factory)
end)
end
end)
end
ProduceHarvester = function(factory, delay)
if GreeceMoney() < Actor.Cost("harv") then
return
end
local toBuild = { "harv" }
Greece.Build(toBuild, function()
Trigger.AfterDelay(delay, function()
ProduceArmor(factory)
end)
end)
end
SendUnits = function(units, path)
Utils.Do(units, function(unit)
if unit.IsDead then
return
end
unit.Patrol(path, false)
IdleHunt(unit)
end)
end
IsHarvesterMissing = function()
return #Greece.GetActorsByType("harv") == 0
end
GreeceMoney = function()
return Greece.Cash + Greece.Resources
end
BaseBlueprints =
{
{ type = "apwr", actor = Apwr1, cost = 500, shape = { 3, 3 }, location = CPos.New(18, 12) },
{ type = "apwr", actor = Apwr2, cost = 500, shape = { 3, 3 }, location = CPos.New(27, 6) },
{ type = "tent", actor = Tent, cost = 400, shape = { 2, 3 }, location = CPos.New(29, 16), onBuilt = ProduceInfantry },
{ type = "proc", actor = Proc, cost = 1400, shape = { 3, 4 }, location = CPos.New(24, 9) },
{ type = "weap", actor = Weap, cost = 2000, shape = { 3, 3 }, location = CPos.New(22, 15), onBuilt = ProduceArmor },
{ type = "powr", actor = Powr1, cost = 300, shape = { 2, 3 }, location = CPos.New(20, 2) },
{ type = "powr", actor = Powr2, cost = 300, shape = { 2, 3 }, location = CPos.New(25, 2) },
{ type = "gun", actor = Gun4, cost = 800, shape = { 1, 1 }, location = CPos.New(28, 23) },
{ type = "hbox", actor = Hbox2, cost = 600, shape = { 1, 1 }, location = CPos.New(29, 23) },
{ type = "gun", actor = Gun3, cost = 800, shape = { 1, 1 }, location = CPos.New(20, 23) },
{ type = "hbox", actor = Hbox1, cost = 600, shape = { 1, 1 }, location = CPos.New(19, 23) },
{ type = "gap", actor = Gap, cost = 800, shape = { 1, 1 }, location = CPos.New(24, 22) }
}
--[[
Similar to the original CnC/RA [BASE] and [STRUCTURES] .INI sections.
Check a list every so often and (re)build structures missing from
that list, in order, if circumstances allow for it.
]]
BuildBase = function()
for _, blueprint in pairs(BaseBlueprints) do
if not blueprint.actor then
BuildBlueprint(blueprint)
return
end
end
Trigger.AfterDelay(DateTime.Seconds(10), BuildBase)
end
BuildBlueprint = function(blueprint)
Trigger.AfterDelay(Actor.BuildTime(blueprint.type), function()
if CYard.IsDead or CYard.Owner ~= Greece then
return
elseif GreeceMoney() <= 299 and IsHarvesterMissing() then
return
end
if IsBuildAreaBlocked(Greece, blueprint) then
Trigger.AfterDelay(DateTime.Seconds(5), function()
BuildBlueprint(blueprint)
end)
return
end
local actor = Actor.Create(blueprint.type, true, { Owner = Greece, Location = blueprint.location })
OnBlueprintBuilt(actor, blueprint)
Trigger.AfterDelay(DateTime.Seconds(10), BuildBase)
end)
end
OnBlueprintBuilt = function(actor, blueprint)
Greece.Cash = Greece.Cash - blueprint.cost
blueprint.actor = actor
MaintainBuilding(actor, blueprint, 0.75)
if blueprint.onBuilt then
-- Build() will not work properly on producers if immediately called.
Trigger.AfterDelay(1, function()
blueprint.onBuilt(actor)
end)
end
end
IsBuildAreaBlocked = function(player, blueprint)
local nw, se = blueprint.northwestEdge, blueprint.southeastEdge
local blockers = Map.ActorsInBox(nw, se, function(actor)
return actor.CenterPosition.Z == 0 and actor.HasProperty("Health") and not IsOwnedSilo(player, actor)
end)
if #blockers == 0 then
return false
end
ScatterBlockers(player, blockers)
return true
end
-- This is used to disregard silos inside the refinery rebuild area.
IsOwnedSilo = function(player, actor)
return actor.Type == "silo" and actor.Owner == player
end
ScatterBlockers = function(player, actors)
Utils.Do(actors, function(actor)
if actor.IsIdle and actor.Owner == player and actor.HasProperty("Scatter") then
actor.Scatter()
end
end)
end
BeginBaseMaintenance = function()
Utils.Do(BaseBlueprints, function(blueprint)
MaintainBuilding(blueprint.actor, blueprint)
end)
Utils.Do(Greece.GetActors(), function(actor)
if actor.HasProperty("StartBuildingRepairs") then
MaintainBuilding(actor, nil, 0.75)
end
end)
end
MaintainBuilding = function(actor, blueprint, repairThreshold)
if blueprint then
Trigger.OnKilled(actor, function() blueprint.actor = nil end)
Trigger.OnSold(actor, function() blueprint.actor = nil end)
if not blueprint.northwestEdge then
PrepareBlueprintEdges(blueprint)
end
end
if repairThreshold then
local original = actor.Owner
Trigger.OnDamaged(actor, function()
if actor.Owner ~= original or actor.Health > actor.MaxHealth * repairThreshold then
return
end
actor.StartBuildingRepairs()
end)
end
end
PrepareBlueprintEdges = function(blueprint)
local shapeX, shapeY = blueprint.shape[1], blueprint.shape[2]
local northwestEdge = Map.CenterOfCell(blueprint.location) + WVec.New(-512, -512, 0)
local southeastEdge = northwestEdge + WVec.New(shapeX * 1024, shapeY * 1024, 0)
blueprint.northwestEdge = northwestEdge
blueprint.southeastEdge = southeastEdge
end

View File

@@ -0,0 +1,68 @@
--[[
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.
]]
EnemyReinforcements =
{
easy =
{
{ "e1", "e1", "e3" },
{ "e1", "e3", "jeep" },
{ "e1", "jeep", "1tnk" }
},
normal =
{
{ "e1", "e1", "e3", "e3" },
{ "e1", "e3", "jeep", "jeep" },
{ "e1", "jeep", "1tnk", "2tnk" }
},
hard =
{
{ "e1", "e1", "e3", "e3", "e1" },
{ "e1", "e3", "jeep", "jeep", "1tnk" },
{ "e1", "jeep", "1tnk", "2tnk", "arty" }
}
}
EnemyAttackDelay =
{
easy = DateTime.Minutes(5),
normal = DateTime.Minutes(2) + DateTime.Seconds(40),
hard = DateTime.Minutes(1) + DateTime.Seconds(30)
}
EnemyPaths =
{
{ EnemyEntry1.Location, EnemyRally1.Location },
{ EnemyEntry2.Location, EnemyRally2.Location }
}
Wave = 0
SendReinforcements = function()
Trigger.AfterDelay(EnemyAttackDelay[Difficulty], function()
if Dome.IsDead or Dome.Owner ~= Greece then
return
end
Wave = Wave + 1
if Wave > 3 then
Wave = 1
end
if Wave == 1 then
local units = Reinforcements.ReinforceWithTransport(Greece, "tran", EnemyReinforcements[Difficulty][Wave], EnemyPaths[1], { EnemyPaths[1][1] })[2]
Utils.Do(units, IdleHunt)
else
local units = Reinforcements.ReinforceWithTransport(Greece, "lst", EnemyReinforcements[Difficulty][Wave], EnemyPaths[2], { EnemyPaths[2][1] })[2]
Utils.Do(units, IdleHunt)
end
SendReinforcements()
end)
end

View File

@@ -0,0 +1,282 @@
--[[
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.
]]
Trigger.OnRemovedFromWorld(Mcv, function()
if McvDeployed or Mcv.IsDead then
return
end
McvDeployed = true
BuildBase()
SendReinforcements()
Trigger.AfterDelay(DateTime.Minutes(1), function()
ProduceInfantry(Tent)
end)
Trigger.AfterDelay(DateTime.Minutes(2), function()
ProduceArmor(Weap)
end)
local baseAttackers = { BaseAttacker1, BaseAttacker2 }
Trigger.AfterDelay(DateTime.Minutes(2), function()
Utils.Do(baseAttackers, IdleHunt)
end)
end)
PrepareReveals = function()
local cameraBarrierCells = { CPos.New(65, 39), CPos.New(65, 40), CPos.New(66, 40), CPos.New(66, 41), CPos.New(67, 41), CPos.New(67, 42), CPos.New(68, 42), CPos.New(68, 43), CPos.New(68, 44) }
local cameraBaseCells = { CPos.New(53, 42), CPos.New(54, 42), CPos.New(54, 41), CPos.New(55, 41), CPos.New(56, 41), CPos.New(56, 40), CPos.New(57, 40), CPos.New(57, 39), CPos.New(58, 39), CPos.New(59, 39), CPos.New(59, 38), CPos.New(60, 38), CPos.New(61, 38) }
local cameraBarrierTriggered = false
local cameraBaseTriggered = false
Trigger.OnEnteredFootprint(cameraBarrierCells, function(a, id)
if cameraBarrierTriggered or a.Owner ~= USSR then
return
end
cameraBarrierTriggered = true
Trigger.RemoveFootprintTrigger(id)
local cameraBarrier = Actor.Create("camera", true, { Owner = USSR, Location = CameraBarrier.Location })
Trigger.AfterDelay(DateTime.Seconds(12), cameraBarrier.Destroy)
end)
Trigger.OnEnteredFootprint(cameraBaseCells, function(a, id)
if cameraBaseTriggered or a.Owner ~= USSR then
return
end
cameraBaseTriggered = true
Trigger.RemoveFootprintTrigger(id)
local cameraBase1 = Actor.Create("camera", true, { Owner = USSR, Location = CameraBase1.Location })
local cameraBase2 = Actor.Create("camera", true, { Owner = USSR, Location = CameraBase2.Location })
local cameraBase3 = Actor.Create("camera", true, { Owner = USSR, Location = CameraBase3.Location })
local cameraBase4 = Actor.Create("camera", true, { Owner = USSR, Location = CameraBase4.Location })
Trigger.AfterDelay(DateTime.Minutes(1), function()
cameraBase1.Destroy()
cameraBase2.Destroy()
cameraBase3.Destroy()
cameraBase4.Destroy()
end)
end)
end
PrepareResponseCruiser = function()
local responseBuildings = { Apwr1, Apwr2, Powr1, Powr2, Weap, Tent }
local responseOrdered = false
Utils.Do(responseBuildings, function(building)
Trigger.OnDamaged(building, function()
if responseOrdered or USSR.IsObjectiveCompleted(DisruptDome) then
return
end
responseOrdered = true
OrderResponseCruiser()
end)
end)
end
OrderResponseCruiser = function()
if ResponseCruiser.IsDead then
return
end
Trigger.OnIdle(ResponseCruiser, function()
ResponseCruiser.AttackMove(waypoint0.Location, 2)
end)
Trigger.OnDamaged(ResponseCruiser, function(_, attacker)
if attacker.IsDead or not ResponseCruiser.CanTarget(attacker) then
return
end
ResponseCruiser.Attack(attacker)
ResponseCruiser.Scatter()
end)
end
PrepareBridgeBreakers = function()
local target = Map.ActorsInCircle(waypoint78.CenterPosition, WDist.New(1536), function(actor)
return actor.Type == "br3"
end)[1]
if not target then
Media.Debug("No bridge segment found.")
return
end
local orderSent = false
Trigger.AfterDelay(DateTime.Seconds(30), function()
orderSent = true
OrderBridgeBreakers(target)
end)
local bridgeEntryCells = { CPos.New(75, 30), CPos.New(76, 30), CPos.New(77, 30) }
Trigger.OnEnteredFootprint(bridgeEntryCells, function(a, id)
if a.Owner ~= USSR then
return
end
Trigger.RemoveFootprintTrigger(id)
if not orderSent then
OrderBridgeBreakers(target, "with bridge reveal")
end
end)
end
OrderBridgeBreakers = function(target, reveal)
if target.IsDead then
return
end
local breakers = { BridgeBreaker1, BridgeBreaker2 }
Utils.Do(breakers, function(breaker)
if breaker.IsDead then
return
end
breaker.Stop()
breaker.Attack(target, true, true)
end)
if not reveal then
return
end
local camera = Actor.Create("camera", true, { Owner = USSR, Location = target.Location })
Trigger.OnKilled(target, function()
Trigger.AfterDelay(DateTime.Seconds(2), camera.Destroy)
end)
end
PrepareObjectives = function()
InitObjectives(USSR)
KillTrucks = AddPrimaryObjective(Greece, "")
EscortConvoy = AddPrimaryObjective(USSR, "escort-convoy")
DisruptDome = AddSecondaryObjective(USSR, "destroy-capture-radar-dome-reinforcements")
SaveAllTrucks = AddSecondaryObjective(USSR, "keep-trucks-alive")
Trigger.OnKilledOrCaptured(Dome, function()
-- Let the capture notification play first.
Trigger.AfterDelay(DateTime.Seconds(2), function()
USSR.MarkCompletedObjective(DisruptDome)
Media.PlaySpeechNotification(USSR, "ObjectiveMet")
end)
end)
end
PrepareTrucks = function()
local trucks = { Truck1, Truck2 }
local goalCells = { CPos.New(83, 7), CPos.New(83, 8), CPos.New(83, 9), CPos.New(83, 10), CPos.New(84, 10), CPos.New(84, 11), CPos.New(84, 12), CPos.New(85, 12), CPos.New(86, 12), CPos.New(87, 12), CPos.New(87, 13), CPos.New(88, 13), CPos.New(89, 13), CPos.New(90, 13), CPos.New(90, 14), CPos.New(90, 15), CPos.New(91, 15), CPos.New(92, 15), CPos.New(93, 15), CPos.New(94, 15) }
local goalTriggered = false
Trigger.OnEnteredFootprint(goalCells, function(a)
if not goalTriggered and a.Owner == USSR and a.Type == "truk" then
goalTriggered = true
USSR.MarkCompletedObjective(EscortConvoy)
USSR.MarkCompletedObjective(SaveAllTrucks)
end
end)
Trigger.OnAllKilled(trucks, function()
Greece.MarkCompletedObjective(KillTrucks)
end)
Trigger.OnAnyKilled(trucks, function()
USSR.MarkFailedObjective(SaveAllTrucks)
end)
end
BeginIntro = function()
local introAttackers = { IntroEnemy1, IntroEnemy2, IntroEnemy3 }
local sovietReinforcements1 = { "e6", "e6", "e6", "e6", "e6" }
local sovietReinforcements2 = { "e4", "e4", "e2", "e2", "e2" }
local sovietReinforcements1Path = { McvWaypoint.Location, APCWaypoint1.Location }
local sovietReinforcements2Path = { McvWaypoint.Location, APCWaypoint2.Location }
Mcv.Move(McvWaypoint.Location)
Utils.Do(introAttackers, IdleHunt)
Reinforcements.ReinforceWithTransport(USSR, "apc", sovietReinforcements1, sovietReinforcements1Path)
Reinforcements.ReinforceWithTransport(USSR, "apc", sovietReinforcements2, sovietReinforcements2Path)
end
PrepareIdleGuards = function()
local lazyUnits = Utils.Where(Greece.GetGroundAttackers(), function(unit)
return unit.Type ~= "ca" and unit.Type ~= "arty"
end)
Utils.Do(lazyUnits, function(unit)
local triggered = false
Trigger.OnDamaged(unit, function()
if triggered then
return
end
triggered = true
IdleHunt(unit)
end)
end)
end
WorldLoaded = function()
USSR = Player.GetPlayer("USSR")
Greece = Player.GetPlayer("Greece")
PrepareReveals()
PrepareObjectives()
Camera.Position = CameraStart.CenterPosition
Harvester.FindResources()
BeginBaseMaintenance()
if Difficulty ~= "easy" then
PrepareResponseCruiser()
Trigger.AfterDelay(1, PrepareBridgeBreakers)
end
if Difficulty == "hard" then
BuildNavyPatrol()
end
PrepareTrucks()
BeginIntro()
PrepareIdleGuards()
end
BuildNavyPatrol = function()
local types = { "dd", "dd" }
local patrolPath = { NavyPatrol1.Location, NavyPatrol2.Location, NavyPatrol3.Location, NavyPatrol4.Location }
Greece.Build(types, function(units)
Utils.Do(units, function(u)
u.Patrol(patrolPath, true, 100)
end)
Trigger.OnAllKilled(units, function()
if not Greece.HasPrerequisites({ "syrd", "dome" }) then
return
end
BuildNavyPatrol()
end)
end)
end
Tick = function()
if USSR.HasNoRequiredUnits() then
Greece.MarkCompletedObjective(KillTrucks)
end
if Greece.Resources >= Greece.ResourceCapacity * 0.75 then
Greece.Cash = Greece.Cash + Greece.Resources - Greece.ResourceCapacity * 0.25
Greece.Resources = Greece.ResourceCapacity * 0.25
end
end