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,45 @@
--[[
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.
]]
AttackGroupSize =
{
easy = 6,
normal = 8,
hard = 10
}
AttackDelays =
{
easy = { DateTime.Seconds(4), DateTime.Seconds(7) },
normal = { DateTime.Seconds(2), DateTime.Seconds(5) },
hard = { DateTime.Seconds(1), DateTime.Seconds(3) }
}
AtreidesInfantryTypes = { "light_inf", "light_inf", "trooper", "trooper", "trooper" }
AtreidesVehicleTypes = { "trike", "trike", "quad" }
AtreidesTankType = { "combat_tank_a" }
ActivateAI = function()
IdlingUnits[Fremen] = { }
IdlingUnits[Atreides] = Utils.Concat(Reinforcements.Reinforce(Atreides, InitialAtreidesReinforcements[1], AtreidesPaths[2]), Reinforcements.Reinforce(Atreides, InitialAtreidesReinforcements[2], AtreidesPaths[3]))
FremenProduction()
DefendAndRepairBase(Atreides, AtreidesBase, 0.75, AttackGroupSize[Difficulty])
DefendAndRepairBase(Fremen, FremenBase, 0.75, AttackGroupSize[Difficulty])
local delay = function() return Utils.RandomInteger(AttackDelays[Difficulty][1], AttackDelays[Difficulty][2] + 1) end
local infantryToBuild = function() return { Utils.Random(AtreidesInfantryTypes) } end
local vehilcesToBuild = function() return { Utils.Random(AtreidesVehicleTypes) } end
local tanksToBuild = function() return AtreidesTankType end
local attackThresholdSize = AttackGroupSize[Difficulty] * 2.5
ProduceUnits(Atreides, ABarracks, delay, infantryToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Atreides, ALightFactory, delay, vehilcesToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
ProduceUnits(Atreides, AHeavyFactory, delay, tanksToBuild, AttackGroupSize[Difficulty], attackThresholdSize)
end

View File

@@ -0,0 +1,204 @@
--[[
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.
]]
AtreidesBase = { AConyard, AOutpost, ARefinery, AHeavyFactory, ALightFactory, AGunt1, AGunt2, ABarracks, ASilo, APower1, APower2, APower3, APower4, APower5, APower6 }
FremenBase = { FGunt1, FGunt2 }
BaseAreaTriggers =
{
{ CPos.New(27, 38), CPos.New(26, 38), CPos.New(26, 39), CPos.New(25, 39), CPos.New(25, 40), CPos.New(25, 41), CPos.New(24, 41), CPos.New(24, 42) },
{ CPos.New(19, 81), CPos.New(19, 82), CPos.New(19, 83), CPos.New(19, 84), CPos.New(19, 85), CPos.New(19, 86), CPos.New(19, 87), CPos.New(19, 88), CPos.New(19, 89), CPos.New(19, 90), CPos.New(19, 91) },
{ CPos.New(10, 78), CPos.New(11, 78), CPos.New(12, 78), CPos.New(13, 78), CPos.New(14, 78), CPos.New(15, 78) }
}
Sietches = { FSietch1, FSietch2 }
FremenReinforcements =
{
easy =
{
{ "combat_tank_a", "combat_tank_a" },
{ "trooper", "trooper", "trooper" },
{ "combat_tank_a", "combat_tank_a" },
{ "combat_tank_a", "light_inf", "light_inf", "trooper", "trooper" },
{ "combat_tank_a", "trike", "trike", "quad", "trooper", "nsfremen" }
},
normal =
{
{ "combat_tank_a", "combat_tank_a" },
{ "trooper", "trooper", "trooper" },
{ "combat_tank_a", "combat_tank_a" },
{ "combat_tank_a", "light_inf", "light_inf", "trooper", "trooper" },
{ "combat_tank_a", "trike", "trike", "quad", "trooper", "nsfremen" },
{ "combat_tank_a", "trike", "combat_tank_a", "quad", "nsfremen", "nsfremen" },
{ "fremen", "fremen", "fremen", "fremen", "trooper", "trooper", "trooper", "trooper" }
},
hard =
{
{ "combat_tank_a", "combat_tank_a" },
{ "trooper", "trooper", "trooper" },
{ "combat_tank_a", "combat_tank_a" },
{ "combat_tank_a", "light_inf", "light_inf", "trooper", "trooper" },
{ "combat_tank_a", "trike", "trike", "quad", "trooper", "nsfremen" },
{ "combat_tank_a", "trike", "combat_tank_a", "quad", "nsfremen", "nsfremen" },
{ "fremen", "fremen", "fremen", "fremen", "trooper", "trooper", "trooper", "trooper" },
{ "combat_tank_a", "combat_tank_a", "combat_tank_a", "combat_tank_a", "missile_tank" },
{ "combat_tank_a", "combat_tank_a", "quad", "quad", "trike", "trike", "trooper", "trooper", "light_inf", "light_inf" }
}
}
FremenAttackDelay =
{
easy = DateTime.Minutes(3),
normal = DateTime.Minutes(2) + DateTime.Seconds(20),
hard = DateTime.Minutes(1)
}
FremenAttackWaves =
{
easy = 5,
normal = 7,
hard = 9
}
AtreidesHunters = { "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper" }
FremenHunters =
{
{ "fremen", "fremen", "fremen" },
{ "combat_tank_a", "combat_tank_a", "combat_tank_a" },
{ "missile_tank", "missile_tank", "missile_tank" }
}
InitialAtreidesReinforcements =
{
{ "trooper", "trooper", "trooper", "trooper", "light_inf", "light_inf", "light_inf", "light_inf" },
{ "combat_tank_a", "combat_tank_a", "quad", "trike" }
}
AtreidesPaths =
{
{ AtreidesEntry1.Location, AtreidesRally1.Location },
{ AtreidesEntry2.Location, AtreidesRally2.Location },
{ AtreidesEntry3.Location, AtreidesRally3.Location }
}
FremenPaths =
{
{ FremenEntry4.Location, FremenRally4.Location },
{ FremenEntry5.Location, FremenRally5.Location },
{ FremenEntry6.Location, FremenRally6.Location }
}
FremenHunterPaths =
{
{ FremenEntry1.Location, FremenRally1.Location },
{ FremenEntry2.Location, FremenRally2.Location },
{ FremenEntry3.Location, FremenRally3.Location }
}
HarkonnenReinforcements = { "combat_tank_h", "combat_tank_h" }
HarkonnenPath = { HarkonnenEntry.Location, HarkonnenRally.Location }
FremenInterval =
{
easy = { DateTime.Minutes(1) + DateTime.Seconds(30), DateTime.Minutes(2) },
normal = { DateTime.Minutes(2) + DateTime.Seconds(20), DateTime.Minutes(2) + DateTime.Seconds(40) },
hard = { DateTime.Minutes(3) + DateTime.Seconds(40), DateTime.Minutes(4) }
}
FremenProduction = function()
if SietchesAreDestroyed then
return
end
local delay = Utils.RandomInteger(FremenInterval[Difficulty][1], FremenInterval[Difficulty][2] + 1)
Fremen.Build({ "nsfremen" }, function()
Trigger.AfterDelay(delay, FremenProduction)
end)
end
Tick = function()
if Harkonnen.HasNoRequiredUnits() then
Atreides.MarkCompletedObjective(KillHarkonnen)
end
if Atreides.HasNoRequiredUnits() and not Harkonnen.IsObjectiveCompleted(KillAtreides) then
Media.DisplayMessage(UserInterface.GetFluentMessage("atreides-annihilated"), Mentat)
Harkonnen.MarkCompletedObjective(KillAtreides)
end
if Fremen.HasNoRequiredUnits() and not Harkonnen.IsObjectiveCompleted(KillFremen) then
Media.DisplayMessage(UserInterface.GetFluentMessage("fremen-annihilated"), Mentat)
Harkonnen.MarkCompletedObjective(KillFremen)
end
if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[Atreides] then
local units = Atreides.GetActorsByType("harvester")
if #units > 0 then
LastHarvesterEaten[Atreides] = false
ProtectHarvester(units[1], Atreides, AttackGroupSize[Difficulty])
end
end
end
WorldLoaded = function()
Atreides = Player.GetPlayer("Atreides")
Fremen = Player.GetPlayer("Fremen")
Harkonnen = Player.GetPlayer("Harkonnen")
InitObjectives(Harkonnen)
KillAtreides = AddPrimaryObjective(Harkonnen, "destroy-atreides")
KillFremen = AddPrimaryObjective(Harkonnen, "destroy-fremen")
KillHarkonnen = AddPrimaryObjective(Atreides, "")
Camera.Position = HConyard.CenterPosition
FremenAttackLocation = HConyard.Location
Trigger.OnAllKilledOrCaptured(AtreidesBase, function()
Utils.Do(Atreides.GetGroundAttackers(), IdleHunt)
end)
Trigger.OnAllKilled(Sietches, function()
SietchesAreDestroyed = true
end)
local path = function() return Utils.Random(FremenPaths) end
local waveCondition = function() return Harkonnen.IsObjectiveCompleted(KillFremen) end
local huntFunction = function(unit)
unit.AttackMove(FremenAttackLocation)
IdleHunt(unit)
end
SendCarryallReinforcements(Fremen, 0, FremenAttackWaves[Difficulty], FremenAttackDelay[Difficulty], path, FremenReinforcements[Difficulty], waveCondition, huntFunction)
Actor.Create("upgrade.barracks", true, { Owner = Atreides })
Actor.Create("upgrade.light", true, { Owner = Atreides })
Trigger.AfterDelay(0, ActivateAI)
Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds(15), function()
Media.PlaySpeechNotification(Harkonnen, "Reinforce")
Reinforcements.Reinforce(Harkonnen, HarkonnenReinforcements, HarkonnenPath)
end)
Trigger.AfterDelay(DateTime.Seconds(15), function()
Media.DisplayMessage(UserInterface.GetFluentMessage("fremen-spotted-north-southwest"), Mentat)
end)
local atreidesCondition = function() return Harkonnen.IsObjectiveCompleted(KillAtreides) end
TriggerCarryallReinforcements(Harkonnen, Atreides, BaseAreaTriggers[1], AtreidesHunters, AtreidesPaths[1], atreidesCondition)
local fremenCondition = function() return Harkonnen.IsObjectiveCompleted(KillFremen) end
TriggerCarryallReinforcements(Harkonnen, Fremen, BaseAreaTriggers[1], FremenHunters[1], FremenHunterPaths[3], fremenCondition)
TriggerCarryallReinforcements(Harkonnen, Fremen, BaseAreaTriggers[2], FremenHunters[2], FremenHunterPaths[2], fremenCondition)
TriggerCarryallReinforcements(Harkonnen, Fremen, BaseAreaTriggers[3], FremenHunters[3], FremenHunterPaths[1], fremenCondition)
end

Binary file not shown.

View File

@@ -0,0 +1,5 @@
## rules.yaml
briefing =
The native Fremen must be dealt with. Assemble a strike force to lead a sweep through the mountains. Seek out the Fremen hold, and destroy it. If any House responds, destroy it.
Tanks have been deployed to grind the Fremen beneath their treads. Demonstrate the power of House Harkonnen.

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

View File

@@ -0,0 +1,382 @@
MapFormat: 12
RequiresMod: d2k
Title: Harkonnen 04
Author: Westwood Studios
Tileset: ARRAKIS
MapSize: 74,94
Bounds: 2,2,70,90
Visibility: MissionSelector
Categories: Campaign
LockPreview: True
Players:
PlayerReference@Neutral:
Name: Neutral
OwnsWorld: True
NonCombatant: True
PlayerReference@Creeps:
Name: Creeps
NonCombatant: True
Enemies: Harkonnen, Atreides
PlayerReference@Harkonnen:
Name: Harkonnen
Playable: True
LockFaction: True
Faction: harkonnen
LockColor: True
Color: D64A42
Enemies: Atreides, Fremen, Creeps
PlayerReference@Atreides:
Name: Atreides
LockFaction: True
Faction: atreides
LockColor: True
Color: 5A7394
Allies: Fremen
Enemies: Harkonnen, Creeps
Bot: campaign
PlayerReference@Fremen:
Name: Fremen
LockFaction: True
Faction: fremen
LockColor: True
Color: 848484
Allies: Atreides
Enemies: Harkonnen, Creeps
Bot: campaign
Actors:
Actor0: spicebloom.spawnpoint
Location: 52,4
Owner: Neutral
Actor1: spicebloom.spawnpoint
Location: 13,5
Owner: Neutral
Actor2: wormspawner
Location: 48,5
Owner: Creeps
Actor3: spicebloom.spawnpoint
Location: 66,6
Owner: Neutral
Actor4: nsfremen
Location: 26,11
Owner: Fremen
Actor5: nsfremen
Location: 27,12
Owner: Fremen
FSietch1: sietch
Location: 24,13
Owner: Fremen
Actor7: wall
Location: 59,14
Owner: Fremen
FGunt1: medium_gun_turret
Location: 61,14
Owner: Fremen
Actor9: wall
Location: 63,14
Owner: Fremen
Actor10: wall
Location: 59,15
Owner: Fremen
Actor11: wall
Location: 60,15
Owner: Fremen
Actor12: wall
Location: 61,15
Owner: Fremen
Actor13: wall
Location: 62,15
Owner: Fremen
Actor14: wall
Location: 63,15
Owner: Fremen
Actor15: spicebloom.spawnpoint
Location: 19,16
Owner: Neutral
Actor16: nsfremen
Location: 23,16
Owner: Fremen
Actor17: nsfremen
Location: 27,16
Owner: Fremen
Actor18: nsfremen
Location: 22,17
Owner: Fremen
Actor19: nsfremen
Location: 25,17
Owner: Fremen
Actor20: spicebloom.spawnpoint
Location: 28,19
Owner: Neutral
Actor21: spicebloom.spawnpoint
Location: 4,20
Owner: Neutral
Actor22: spicebloom.spawnpoint
Location: 52,20
Owner: Neutral
Actor23: spicebloom.spawnpoint
Location: 70,22
Owner: Neutral
Actor24: spicebloom.spawnpoint
Location: 33,24
Owner: Neutral
Actor25: spicebloom.spawnpoint
Location: 58,30
Owner: Neutral
Actor26: spicebloom.spawnpoint
Location: 34,39
Owner: Neutral
Actor27: wormspawner
Location: 41,40
Owner: Creeps
Actor28: combat_tank_h
Location: 66,43
Owner: Harkonnen
Actor29: light_inf
Location: 63,44
Owner: Harkonnen
Actor30: combat_tank_h
Location: 68,44
Owner: Harkonnen
Actor31: trooper
Location: 64,46
Owner: Harkonnen
HConyard: construction_yard
Location: 66,46
Owner: Harkonnen
Actor33: light_inf
Location: 61,47
Owner: Harkonnen
Actor34: light_inf
Location: 63,49
Owner: Harkonnen
Actor35: spicebloom.spawnpoint
Location: 34,50
Owner: Neutral
Actor36: light_inf
Location: 65,50
Owner: Harkonnen
Actor37: spicebloom.spawnpoint
Location: 6,52
Owner: Neutral
Actor38: spicebloom.spawnpoint
Location: 28,57
Owner: Neutral
ALightFactory: light_factory
Location: 39,69
Owner: Atreides
AConyard: construction_yard
Location: 11,70
Owner: Atreides
Actor41: wind_trap
Location: 16,70
Owner: Atreides
Actor42: wall
Location: 33,70
Owner: Atreides
Actor43: wall
Location: 34,70
Owner: Atreides
Actor44: wall
Location: 35,70
Owner: Atreides
Actor45: wall
Location: 21,71
Owner: Atreides
Actor46: wall
Location: 33,71
Owner: Atreides
ASilo: silo
Location: 43,71
Owner: Atreides
Actor48: wall
Location: 21,72
Owner: Atreides
Actor49: wall
Location: 22,72
Owner: Atreides
AGunt1: medium_gun_turret
Location: 23,72
Owner: Atreides
AGunt2: medium_gun_turret
Location: 29,72
Owner: Atreides
Actor52: wall
Location: 30,72
Owner: Atreides
Actor53: wall
Location: 31,72
Owner: Atreides
Actor54: wall
Location: 32,72
Owner: Atreides
Actor55: wall
Location: 33,72
Owner: Atreides
AOutpost: outpost
Location: 42,73
Owner: Atreides
APower1: wind_trap
Location: 4,74
Owner: Atreides
APower2: wind_trap
Location: 6,74
Owner: Atreides
ABarracks: barracks
Location: 9,74
Owner: Atreides
AHeavyFactory: heavy_factory
Location: 12,74
Owner: Atreides
APower3: wind_trap
Location: 16,74
Owner: Atreides
Actor62: harvester
Location: 30,74
Owner: Atreides
ARefinery: refinery
Location: 32,75
Owner: Atreides
Actor64: light_inf
Location: 29,76
Owner: Atreides
APower4: wind_trap
Location: 37,76
Owner: Atreides
APower5: wind_trap
Location: 39,76
Owner: Atreides
Actor67: light_inf
Location: 46,76
Owner: Atreides
APower6: wind_trap
Location: 42,78
Owner: Atreides
Actor69: light_inf
Location: 44,79
Owner: Atreides
FSietch2: sietch
Location: 13,82
Owner: Fremen
Actor71: wall
Location: 19,82
Owner: Fremen
Actor72: wall
Location: 20,82
Owner: Fremen
Actor73: wall
Location: 21,82
Owner: Fremen
Actor74: fremen
Location: 19,83
Owner: Fremen
Actor75: wall
Location: 21,83
Owner: Fremen
Actor76: wall
Location: 21,84
Owner: Fremen
Actor77: fremen
Location: 16,85
Owner: Fremen
Actor78: wall
Location: 21,85
Owner: Fremen
Actor79: wall
Location: 20,86
Owner: Fremen
FGunt2: medium_gun_turret
Location: 21,86
Owner: Fremen
Actor81: fremen
Location: 14,87
Owner: Fremen
Actor82: fremen
Location: 19,88
Owner: Fremen
Actor83: spicebloom.spawnpoint
Location: 29,88
Owner: Neutral
Actor84: spicebloom.spawnpoint
Location: 5,89
Owner: Neutral
Actor85: fremen
Location: 13,90
Owner: Fremen
Actor86: fremen
Location: 22,90
Owner: Fremen
HarkonnenRally: waypoint
Owner: Neutral
Location: 70,42
HarkonnenEntry: waypoint
Owner: Neutral
Location: 71,42
FremenRally1: waypoint
Owner: Neutral
Location: 11,86
FremenEntry1: waypoint
Owner: Neutral
Location: 11,91
FremenRally2: waypoint
Owner: Neutral
Location: 24,82
FremenEntry2: waypoint
Owner: Neutral
Location: 24,91
FremenRally3: waypoint
Owner: Neutral
Location: 17,39
FremenEntry3: waypoint
Owner: Neutral
Location: 2,39
FremenRally4: waypoint
Owner: Neutral
Location: 69,14
FremenEntry4: waypoint
Owner: Neutral
Location: 71,14
FremenRally5: waypoint
Owner: Neutral
Location: 62,24
FremenEntry5: waypoint
Owner: Neutral
Location: 71,24
FremenRally6: waypoint
Owner: Neutral
Location: 58,28
FremenEntry6: waypoint
Owner: Neutral
Location: 71,28
AtreidesRally1: waypoint
Owner: Neutral
Location: 22,38
AtreidesEntry1: waypoint
Owner: Neutral
Location: 2,38
AtreidesRally2: waypoint
Owner: Neutral
Location: 26,74
AtreidesEntry2: waypoint
Owner: Neutral
Location: 39,91
AtreidesRally3: waypoint
Owner: Neutral
Location: 22,76
AtreidesEntry3: waypoint
Owner: Neutral
Location: 22,91
Rules: d2k|rules/campaign-rules.yaml, d2k|rules/campaign-tooltips.yaml, d2k|rules/campaign-palettes.yaml, rules.yaml
FluentMessages: d2k|fluent/lua.ftl, d2k|fluent/campaign.ftl, map.ftl

View File

@@ -0,0 +1,82 @@
Player:
PlayerResources:
DefaultCash: 5000
World:
LuaScript:
Scripts: campaign.lua, utils.lua, harkonnen04.lua, harkonnen04-AI.lua
MissionData:
Briefing: briefing
BriefingVideo: H_BR04_E.VQA
MapOptions:
TechLevel: low
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: easy
carryall.reinforce:
Cargo:
MaxWeight: 10
sietch:
Exit:
ExitCell: 0,2
Production:
Produces: Infantry
nsfremen:
Buildable:
Prerequisites: ~sietch
AutoTarget:
InitialStanceAI: AttackAnything
concreteb:
Buildable:
Prerequisites: ~disabled
medium_gun_turret:
Buildable:
Prerequisites: ~disabled
outpost:
Buildable:
Prerequisites: barracks
quad:
Buildable:
Prerequisites: upgrade.light
trooper:
Buildable:
Prerequisites: upgrade.barracks
engineer:
Buildable:
Prerequisites: upgrade.barracks
repair_pad:
Buildable:
Prerequisites: heavy_factory
mcv:
Buildable:
Prerequisites: repair_pad
upgrade.conyard:
Buildable:
Prerequisites: ~disabled
upgrade.heavy:
Buildable:
Prerequisites: ~disabled
fremen:
AutoTarget:
InitialStanceAI: AttackAnything
MustBeDestroyed: