Files
OpenRA/mods/d2k/maps/atreides-05/atreides05.lua
RoosterDragon 0bfa53b58d Teach CheckTranslationReference about translations in Lua scripts
Using the glory of regex, we can scrape any Lua script files that a map includes and locate calls to the UserInterface.Translate method. We can then treat them in the same way as C# fields marked with a TranslationReferenceAttribute. This allows the lint check to validate the translation invoked in the .lua script has a matching entry in the translation .ftl files, with all the required arguments (if any).

We can also locate any calls to AddPrimaryObjective or AddSecondaryObjective defined by the utils.lua script, which also accept translation keys.

The are a couple of restrictions:
- When linting the map, we don't check for keys in the ftl file that are unused. This is because the linter doesn't load all the keys when checking maps.
- In order to validate translation arguments with the regex, we require the Lua script to pass the table of arguments inline at the callsite. If it does not, we raise a warning so the user can adjust the code.
2024-07-22 17:27:58 +02:00

431 lines
16 KiB
Lua

--[[
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.
]]
HarkonnenBase = { HarkonnenConstructionYard, HarkonnenWindTrap1, HarkonnenWindTrap2, HarkonnenWindTrap3, HarkonnenWindTrap4, HarkonnenWindTrap5, HarkonnenWindTrap6, HarkonnenWindTrap7, HarkonnenWindTrap8, HarkonnenSilo1, HarkonnenSilo2, HarkonnenSilo3, HarkonnenSilo4, HarkonnenGunTurret1, HarkonnenGunTurret2, HarkonnenGunTurret3, HarkonnenGunTurret4, HarkonnenGunTurret5, HarkonnenGunTurret6, HarkonnenGunTurret7, HarkonnenHeavyFactory, HarkonnenRefinery, HarkonnenOutpost, HarkonnenLightFactory }
SmugglerBase = { SmugglerWindTrap1, SmugglerWindTrap2 }
HarkonnenReinforcements =
{
easy =
{
{ "combat_tank_h", "trooper", "trooper", "trooper", "trooper" },
{ "trooper", "trooper", "trooper", "trooper", "trooper" },
{ "combat_tank_h", "light_inf", "light_inf", "trooper", "trooper" },
{ "combat_tank_h", "light_inf", "light_inf", "light_inf", "trooper", "trooper" },
{ "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper" }
},
normal =
{
{ "combat_tank_h", "trooper", "trooper", "trooper", "trooper" },
{ "trooper", "trooper", "trooper", "trooper", "trooper" },
{ "combat_tank_h", "light_inf", "light_inf", "trooper", "trooper" },
{ "combat_tank_h", "light_inf", "light_inf", "light_inf", "trooper", "trooper" },
{ "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper" },
{ "combat_tank_h", "trike", "combat_tank_h", "light_inf", "trooper", "trooper", "quad" },
{ "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper", "quad", "quad" }
},
hard =
{
{ "combat_tank_h", "trooper", "trooper", "trooper", "trooper" },
{ "trooper", "trooper", "trooper", "trooper", "trooper" },
{ "combat_tank_h", "light_inf", "light_inf", "trooper", "trooper" },
{ "combat_tank_h", "light_inf", "light_inf", "light_inf", "trooper", "trooper" },
{ "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper" },
{ "combat_tank_h", "trike", "combat_tank_h", "light_inf", "trooper", "trooper", "quad" },
{ "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper", "quad", "quad" },
{ "combat_tank_h", "combat_tank_h", "trike", "light_inf", "light_inf", "trooper", "trooper", "quad", "quad" },
{ "combat_tank_h", "combat_tank_h", "combat_tank_h", "combat_tank_h", "combat_tank_h", "combat_tank_h" }
}
}
HarkonnenInfantryReinforcements =
{
normal =
{
{ "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper", "trooper" }
},
hard =
{
{ "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper", "trooper" },
{ "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper", "trooper" }
}
}
InfantryPath = { HarkonnenEntry3.Location }
HarkonnenAttackDelay =
{
easy = DateTime.Minutes(3),
normal = DateTime.Minutes(2) + DateTime.Seconds(20),
hard = DateTime.Minutes(1)
}
HarkonnenAttackWaves =
{
easy = 5,
normal = 7,
hard = 9
}
MercenaryReinforcements =
{
easy =
{
{ "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf" },
{ "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike" },
{ "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" }
},
normal =
{
{ "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike" },
{ "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf" },
{ "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" },
{ "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper" },
{ "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike", "trike", "trike", "trike" },
{ "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" }
},
hard =
{
{ "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf" },
{ "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike" },
{ "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" },
{ "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike", "trike", "trike", "trike" },
{ "combat_tank_o", "combat_tank_o", "quad", "quad", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper" },
{ "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" },
{ "combat_tank_o", "combat_tank_o", "quad", "quad", "trike", "trike", "light_inf", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper" },
{ "trike", "trike", "quad", "quad", "quad", "trike", "trike", "trike", "trike", "trike", "trike", "quad", "quad" },
{ "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "combat_tank_o", "trike", "trike", "quad", "quad", "light_inf", "light_inf", "light_inf", "trooper", "trooper", "trooper", "trooper" }
}
}
MercenaryAttackDelay =
{
easy = DateTime.Minutes(2) + DateTime.Seconds(40),
normal = DateTime.Minutes(1) + DateTime.Seconds(50),
hard = DateTime.Minutes(1) + DateTime.Seconds(10)
}
MercenaryAttackWaves =
{
easy = 3,
normal = 6,
hard = 9
}
MercenarySpawn = { HarkonnenRally4.Location + CVec.New(2, -2) }
-- Ordos tanks because those were intended for the Smugglers not the Atreides
ContrabandReinforcements = { "mcv", "quad", "quad", "combat_tank_o", "combat_tank_o", "combat_tank_o" }
SmugglerReinforcements = { "quad", "quad", "trike", "trike" }
InitialHarkonnenReinforcements = { "trooper", "trooper", "quad", "quad", "trike", "trike", "trike", "light_inf" }
HarkonnenPaths =
{
{ HarkonnenEntry1.Location, HarkonnenRally1.Location },
{ HarkonnenEntry1.Location, HarkonnenRally3.Location },
{ HarkonnenEntry1.Location, HarkonnenRally2.Location },
{ HarkonnenEntry1.Location, HarkonnenRally4.Location },
{ HarkonnenEntry2.Location }
}
AtreidesReinforcements = { "trike", "combat_tank_a" }
AtreidesPath = { AtreidesEntry.Location, AtreidesRally.Location }
ContrabandTimes =
{
easy = DateTime.Minutes(10),
normal = DateTime.Minutes(5),
hard = DateTime.Minutes(2) + DateTime.Seconds(30)
}
Wave = 0
SendHarkonnen = function()
Trigger.AfterDelay(HarkonnenAttackDelay[Difficulty], function()
if Atreides.IsObjectiveCompleted(KillHarkonnen) then
return
end
Wave = Wave + 1
if InfantryReinforcements and Wave % 4 == 0 then
local inf = Reinforcements.Reinforce(Harkonnen, HarkonnenInfantryReinforcements[Difficulty][Wave/4], InfantryPath)
Utils.Do(inf, function(unit)
unit.AttackMove(HarkonnenAttackLocation)
IdleHunt(unit)
end)
end
local entryPath = Utils.Random(HarkonnenPaths)
local units = Reinforcements.ReinforceWithTransport(Harkonnen, "carryall.reinforce", HarkonnenReinforcements[Difficulty][Wave], entryPath, { entryPath[1] })[2]
Utils.Do(units, function(unit)
unit.AttackMove(HarkonnenAttackLocation)
IdleHunt(unit)
end)
if Wave < HarkonnenAttackWaves[Difficulty] then
SendHarkonnen()
return
end
Trigger.AfterDelay(DateTime.Seconds(3), function() LastHarkonnenArrived = true end)
end)
end
MercWave = 0
SendMercenaries = function()
Trigger.AfterDelay(MercenaryAttackDelay[Difficulty], function()
MercWave = MercWave + 1
Media.DisplayMessage(UserInterface.Translate("incoming-mercenary-force"), Mentat)
local units = Reinforcements.Reinforce(Mercenary, MercenaryReinforcements[Difficulty][MercWave], MercenarySpawn)
Utils.Do(units, function(unit)
unit.AttackMove(MercenaryAttackLocation1)
unit.AttackMove(MercenaryAttackLocation2)
IdleHunt(unit)
end)
if MercWave < MercenaryAttackWaves[Difficulty] then
SendMercenaries()
return
end
Trigger.AfterDelay(DateTime.Seconds(3), function() LastMercenariesArrived = true end)
end)
end
SendContraband = function(owner)
ContrabandArrived = true
UserInterface.SetMissionText(UserInterface.Translate("contraband-has-arrived"), Atreides.Color)
local units = SmugglerReinforcements
if owner == Atreides then
units = ContrabandReinforcements
end
Reinforcements.ReinforceWithTransport(owner, "frigate", units, { ContrabandEntry.Location, Starport.Location + CVec.New(1, 1) }, { ContrabandExit.Location })
Trigger.AfterDelay(DateTime.Seconds(3), function()
if owner == Atreides then
Atreides.MarkCompletedObjective(CaptureStarport)
Media.DisplayMessage(UserInterface.Translate("contraband-confiscated"), Mentat)
else
Atreides.MarkFailedObjective(CaptureStarport)
Media.DisplayMessage(UserInterface.Translate("contraband-not-confiscated"), Mentat)
end
end)
Trigger.AfterDelay(DateTime.Seconds(5), function()
UserInterface.SetMissionText("")
end)
end
SmugglersAttack = function()
Utils.Do(SmugglerBase, function(building)
if not building.IsDead and building.Owner == Smuggler then
building.Sell()
end
end)
Trigger.AfterDelay(DateTime.Seconds(1), function()
Utils.Do(Smuggler.GetGroundAttackers(), function(unit)
IdleHunt(unit)
end)
end)
end
AttackNotifier = 0
Tick = function()
if Atreides.HasNoRequiredUnits() then
Harkonnen.MarkCompletedObjective(KillAtreides)
end
if LastHarkonnenArrived and not Atreides.IsObjectiveCompleted(KillHarkonnen) and Harkonnen.HasNoRequiredUnits() then
Media.DisplayMessage(UserInterface.Translate("harkonnen-annihilated"), Mentat)
Atreides.MarkCompletedObjective(KillHarkonnen)
end
if LastMercenariesArrived and not Atreides.IsObjectiveCompleted(KillSmuggler) and Smuggler.HasNoRequiredUnits() and Mercenary.HasNoRequiredUnits() then
Media.DisplayMessage(UserInterface.Translate("smugglers-annihilated"), Mentat)
Atreides.MarkCompletedObjective(KillSmuggler)
end
if LastHarvesterEaten[Harkonnen] and DateTime.GameTime % DateTime.Seconds(10) == 0 then
local units = Harkonnen.GetActorsByType("harvester")
if #units > 0 then
LastHarvesterEaten[Harkonnen] = false
ProtectHarvester(units[1], Harkonnen, AttackGroupSize[Difficulty])
end
end
AttackNotifier = AttackNotifier - 1
if TimerTicks and not ContrabandArrived then
TimerTicks = TimerTicks - 1
if (TimerTicks % DateTime.Seconds(1)) == 0 then
local contrabandArrivesIn = UserInterface.Translate("contraband-arrives-in", { ["time"] = Utils.FormatTime(TimerTicks)})
UserInterface.SetMissionText(contrabandArrivesIn, Atreides.Color)
end
if TimerTicks <= 0 then
SendContraband(Smuggler)
end
end
end
WorldLoaded = function()
Harkonnen = Player.GetPlayer("Harkonnen")
Smuggler = Player.GetPlayer("Smugglers")
Mercenary = Player.GetPlayer("Mercenaries")
Atreides = Player.GetPlayer("Atreides")
InfantryReinforcements = Difficulty ~= "easy"
InitObjectives(Atreides)
KillAtreides = AddPrimaryObjective(Harkonnen, "")
CaptureBarracks = AddPrimaryObjective(Atreides, "capture-barracks-sietch-tabr")
KillHarkonnen = AddSecondaryObjective(Atreides, "annihilate-harkonnen-units-reinforcements")
CaptureStarport = AddSecondaryObjective(Atreides, "capture-smuggler-starport-confiscate-contraband")
Camera.Position = ARefinery.CenterPosition
HarkonnenAttackLocation = AtreidesRally.Location
MercenaryAttackLocation1 = Starport.Location + CVec.New(-16, 0)
MercenaryAttackLocation2 = Starport.Location
Trigger.AfterDelay(DateTime.Seconds(2), function()
TimerTicks = ContrabandTimes[Difficulty]
local time = Utils.FormatTime(TimerTicks)
local contrabandApproaching = UserInterface.Translate("contraband-approaching-starport-north-in", { ["time"] = time })
Media.DisplayMessage(contrabandApproaching, Mentat)
end)
Trigger.OnAllKilledOrCaptured(HarkonnenBase, function()
Utils.Do(Harkonnen.GetGroundAttackers(), IdleHunt)
end)
Trigger.OnKilled(Starport, function()
if not Atreides.IsObjectiveCompleted(CaptureStarport) then
ContrabandArrived = true
UserInterface.SetMissionText(UserInterface.Translate("starport-destroyed-no-contraband"), Atreides.Color)
Atreides.MarkFailedObjective(CaptureStarport)
SmugglersAttack()
Trigger.AfterDelay(DateTime.Seconds(15), function()
UserInterface.SetMissionText("")
end)
end
if DefendStarport then
Atreides.MarkFailedObjective(DefendStarport)
end
end)
Trigger.OnDamaged(Starport, function(_, attacker)
if Starport.Owner ~= Smuggler or attacker.IsDead or attacker.Owner ~= Atreides then
return
end
if AttackNotifier <= 0 then
AttackNotifier = DateTime.Seconds(10)
Media.DisplayMessage(UserInterface.Translate("do-not-destroy-starport"), Mentat)
local defenders = Smuggler.GetGroundAttackers()
if #defenders > 0 then
Utils.Do(defenders, function(unit)
unit.Guard(Starport)
end)
end
end
end)
Trigger.OnCapture(Starport, function()
DefendStarport = AddSecondaryObjective(Atreides, "defend-captured-starport")
Trigger.ClearAll(Starport)
Trigger.AfterDelay(0, function()
Trigger.OnRemovedFromWorld(Starport, function()
Atreides.MarkFailedObjective(DefendStarport)
end)
end)
if not ContrabandArrived then
SendContraband(Atreides)
end
SmugglersAttack()
end)
Trigger.OnKilled(HarkonnenBarracks, function()
Atreides.MarkFailedObjective(CaptureBarracks)
end)
Trigger.OnDamaged(HarkonnenBarracks, function()
if AttackNotifier <= 0 and HarkonnenBarracks.Health < HarkonnenBarracks.MaxHealth * 3/4 then
AttackNotifier = DateTime.Seconds(10)
Media.DisplayMessage(UserInterface.Translate("do-not-destroy-barracks"), Mentat)
end
end)
Trigger.OnCapture(HarkonnenBarracks, function()
Media.DisplayMessage(UserInterface.Translate("hostages-released"), Mentat)
if DefendStarport then
Atreides.MarkCompletedObjective(DefendStarport)
end
Trigger.AfterDelay(DateTime.Seconds(3), function()
Atreides.MarkCompletedObjective(CaptureBarracks)
end)
end)
SendHarkonnen()
Actor.Create("upgrade.barracks", true, { Owner = Harkonnen })
Actor.Create("upgrade.light", true, { Owner = Harkonnen })
Actor.Create("upgrade.heavy", true, { Owner = Harkonnen })
Trigger.AfterDelay(0, ActivateAI)
Trigger.AfterDelay(DateTime.Minutes(1), function()
Media.PlaySpeechNotification(Atreides, "Reinforce")
Reinforcements.ReinforceWithTransport(Atreides, "carryall.reinforce", AtreidesReinforcements, AtreidesPath, { AtreidesPath[1] })
end)
local smugglerWaypoint = SmugglerWaypoint1.Location
Trigger.OnEnteredFootprint({ smugglerWaypoint + CVec.New(-2, 0), smugglerWaypoint + CVec.New(-1, 0), smugglerWaypoint, smugglerWaypoint + CVec.New(1, -1), smugglerWaypoint + CVec.New(2, -1), SmugglerWaypoint3.Location }, function(a, id)
if not Warned and a.Owner == Atreides and a.Type ~= "carryall" then
Warned = true
Trigger.RemoveFootprintTrigger(id)
Media.DisplayMessage(UserInterface.Translate("stay-away-from-starport"), UserInterface.Translate("smuggler-leader"))
end
end)
Trigger.OnEnteredFootprint({ SmugglerWaypoint2.Location }, function(a, id)
if not Paid and a.Owner == Atreides and a.Type ~= "carryall" then
Paid = true
Trigger.RemoveFootprintTrigger(id)
Media.DisplayMessage(UserInterface.Translate("were-warned-will-pay"), UserInterface.Translate("smuggler-leader"))
Utils.Do(Smuggler.GetGroundAttackers(), function(unit)
unit.AttackMove(SmugglerWaypoint2.Location)
end)
Trigger.AfterDelay(DateTime.Seconds(3), function()
KillSmuggler = AddSecondaryObjective(Atreides, "destroy-smugglers-mercenaries")
SendMercenaries()
end)
end
end)
Trigger.OnEnteredProximityTrigger(HarkonnenBarracks.CenterPosition, WDist.New(5 * 1024), function(a, id)
if a.Owner == Atreides and a.Type ~= "carryall" then
Trigger.RemoveProximityTrigger(id)
Media.DisplayMessage(UserInterface.Translate("capture-harkonnen-barracks-release-hostages"), Mentat)
StopInfantryProduction = true
end
end)
end