Initial commit: OpenRA game engine
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:
446
mods/ra/maps/intervention/intervention.lua
Normal file
446
mods/ra/maps/intervention/intervention.lua
Normal file
@@ -0,0 +1,446 @@
|
||||
--[[
|
||||
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.
|
||||
]]
|
||||
|
||||
BeachheadTrigger =
|
||||
{
|
||||
CPos.New(120, 90), CPos.New(120, 89), CPos.New(120, 88), CPos.New(121, 88), CPos.New(122, 88), CPos.New(123, 88), CPos.New(124, 88),
|
||||
CPos.New(125, 88), CPos.New(126, 88), CPos.New(126, 89), CPos.New(127, 89), CPos.New(128, 89), CPos.New(128, 90), CPos.New(129, 90),
|
||||
CPos.New(130, 90), CPos.New(130, 91), CPos.New(131, 91), CPos.New(132, 91), CPos.New(133, 91), CPos.New(134, 91), CPos.New(134, 92),
|
||||
CPos.New(135, 92), CPos.New(136, 92), CPos.New(137, 92), CPos.New(137, 93), CPos.New(138, 93), CPos.New(139, 93), CPos.New(140, 93),
|
||||
CPos.New(140, 94), CPos.New(140, 95), CPos.New(140, 96), CPos.New(140, 97), CPos.New(140, 98), CPos.New(140, 99), CPos.New(140, 100),
|
||||
CPos.New(139, 100), CPos.New(139, 101), CPos.New(139, 102), CPos.New(138, 102), CPos.New(138, 103), CPos.New(138, 104),
|
||||
CPos.New(137, 104), CPos.New(137, 105), CPos.New(137, 106), CPos.New(136, 106), CPos.New(136, 107)
|
||||
}
|
||||
|
||||
if Difficulty == "easy" then
|
||||
BaseRaidInterval = DateTime.Minutes(4)
|
||||
BaseFrontAttackInterval = DateTime.Minutes(4) + DateTime.Seconds(30)
|
||||
BaseRearAttackInterval = DateTime.Minutes(8)
|
||||
UBoatPatrolDelay = DateTime.Minutes(3)
|
||||
BaseFrontAttackWpts = { PatrolWpt1.Location, BaseRaidWpt1.Location }
|
||||
elseif Difficulty == "normal" then
|
||||
BaseRaidInterval = DateTime.Minutes(3)
|
||||
BaseFrontAttackInterval = DateTime.Minutes(3) + DateTime.Seconds(30)
|
||||
BaseRearAttackInterval = DateTime.Minutes(8)
|
||||
UBoatPatrolDelay = DateTime.Minutes(2) + DateTime.Seconds(30)
|
||||
BaseFrontAttackWpts = { PatrolWpt1.Location, BaseRaidWpt1.Location }
|
||||
else
|
||||
BaseRaidInterval = DateTime.Minutes(2)
|
||||
BaseFrontAttackInterval = DateTime.Minutes(2) + DateTime.Seconds(30)
|
||||
BaseRearAttackInterval = DateTime.Minutes(5)
|
||||
UBoatPatrolDelay = DateTime.Minutes(2)
|
||||
BaseFrontAttackWpts = { PatrolWpt1.Location }
|
||||
end
|
||||
|
||||
Village = { FarmHouse1, FarmHouse2, FarmHouse3, FarmHouse4, FarmHouse5, FarmHouse6, FarmHouse7, FarmHouse8, FarmHouse9, Church }
|
||||
VillageRaidInterval = DateTime.Minutes(3)
|
||||
VillageRaidAircraft = { "mig.scripted", "mig.scripted" }
|
||||
VillageRaidWpts = { VillageRaidEntrypoint.Location, VillageRaidWpt1.Location, VillageRaidWpt2.Location }
|
||||
|
||||
BaseRaidAircraft = { "mig.scripted", "mig.scripted" }
|
||||
BaseRaidWpts = { BaseRaidEntrypoint.Location, UboatPatrolWpt1.Location, BaseRaidWpt2.Location }
|
||||
|
||||
BaseFrontAttackUnits = { "e3", "e3", "e1", "e1", "e1", "3tnk", "3tnk", "apc" }
|
||||
BaseRearAttackUnits = { "e3", "e3", "e1", "e1", "3tnk", "3tnk", "v2rl" }
|
||||
BaseRearAttackWpts = { GroundAttackWpt1.Location, BaseRearAttackWpt1.Location, BaseRearAttackWpt2.Location, BaseRearAttackWpt3.Location }
|
||||
|
||||
SovietHarvesters = { Harvester1, Harvester2, Harvester3 }
|
||||
HarvesterGuard = { HarvGuard1, HarvGuard2, HarvGuard3 }
|
||||
|
||||
UboatPatrolWpts1 = { UboatPatrolWpt1.Location, UboatPatrolWpt2.Location, UboatPatrolWpt3.Location, UboatPatrolWpt4.Location }
|
||||
UboatPatrolWpts2 = { UboatPatrolWpt4.Location, UboatPatrolWpt2.Location, UboatPatrolWpt1.Location }
|
||||
UBoatPatrolUnits = { "ss" }
|
||||
|
||||
HunterSubs = { "ss", "ss" }
|
||||
|
||||
GroundPatrolWpts = { PatrolWpt1.Location, PatrolWpt2.Location }
|
||||
GroundPatrolUnits =
|
||||
{
|
||||
{ "e1", "e1", "e1", "e3", "e3", "dog" },
|
||||
{ "apc", "apc", "ftrk" },
|
||||
{ "3tnk", "3tnk" }
|
||||
}
|
||||
|
||||
ParadropSovietUnits = function()
|
||||
local powerproxy = Actor.Create("powerproxy.paratroopers", false, { Owner = Soviets })
|
||||
local aircraft = powerproxy.TargetParatroopers(MCVRally.CenterPosition, Angle.New(812))
|
||||
Utils.Do(aircraft, function(a)
|
||||
Trigger.OnPassengerExited(a, function(_, p)
|
||||
IdleHunt(p)
|
||||
end)
|
||||
end)
|
||||
|
||||
powerproxy.Destroy()
|
||||
end
|
||||
|
||||
AirRaid = function(planeTypes, ingress, target)
|
||||
if target == nil then
|
||||
return
|
||||
end
|
||||
|
||||
for i = 1, #planeTypes do
|
||||
Trigger.AfterDelay((i - 1) * DateTime.Seconds(1), function()
|
||||
local start = Map.CenterOfCell(ingress[1]) + WVec.New(0, 0, Actor.CruiseAltitude(planeTypes[i]))
|
||||
local plane = Actor.Create(planeTypes[i], true, { CenterPosition = start, Owner = Soviets, Facing = (Map.CenterOfCell(ingress[2]) - start).Facing })
|
||||
|
||||
Utils.Do(ingress, function(wpt) plane.Move(wpt) end)
|
||||
plane.Attack(target)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
BaseRaid = function()
|
||||
local targets = Utils.Where(Allies.GetActors(), function(actor)
|
||||
return actor.HasProperty("StartBuildingRepairs") and IsInAlliedBaseArea(actor.CenterPosition.X, actor.CenterPosition.Y)
|
||||
end)
|
||||
|
||||
if #targets == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local target = Utils.Random(targets)
|
||||
|
||||
AirRaid(BaseRaidAircraft, BaseRaidWpts, target)
|
||||
|
||||
Trigger.AfterDelay(BaseRaidInterval, BaseRaid)
|
||||
end
|
||||
|
||||
VillageRaid = function()
|
||||
local target = nil
|
||||
Utils.Do(Village, function(tgt)
|
||||
if target == nil and not tgt.IsDead then
|
||||
target = tgt
|
||||
return
|
||||
end
|
||||
end)
|
||||
|
||||
if target == nil then
|
||||
return
|
||||
end
|
||||
|
||||
AirRaid(VillageRaidAircraft, VillageRaidWpts, target)
|
||||
|
||||
Trigger.AfterDelay(VillageRaidInterval, VillageRaid)
|
||||
end
|
||||
|
||||
SendUboatPatrol = function(team)
|
||||
Trigger.AfterDelay(UBoatPatrolDelay, function()
|
||||
Utils.Do(team, function(uboat)
|
||||
if not uboat.IsDead then
|
||||
uboat.PatrolUntil(UboatPatrolWpts1, function()
|
||||
return DateTime.GameTime > DateTime.Minutes(2) + UBoatPatrolDelay
|
||||
end)
|
||||
uboat.Patrol(UboatPatrolWpts2)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
SendGroundPatrol = function(team)
|
||||
Utils.Do(team, function(unit)
|
||||
unit.Patrol(GroundPatrolWpts, true, DateTime.Seconds(3))
|
||||
Trigger.OnIdle(unit, function(actor) actor.Hunt() end)
|
||||
end)
|
||||
Trigger.OnAllKilled(team, function()
|
||||
Build(Utils.Random(GroundPatrolUnits), SendGroundPatrol)
|
||||
end)
|
||||
end
|
||||
|
||||
BaseFrontAttack = function(team)
|
||||
Utils.Do(team, function(unit)
|
||||
unit.Patrol(BaseFrontAttackWpts, false)
|
||||
Trigger.OnIdle(unit, function(actor) actor.Hunt() end)
|
||||
end)
|
||||
Trigger.AfterDelay(BaseFrontAttackInterval, function() Build(BaseFrontAttackUnits, BaseFrontAttack) end)
|
||||
end
|
||||
|
||||
BaseRearAttack = function(team)
|
||||
Utils.Do(team, function(unit)
|
||||
unit.Patrol(BaseRearAttackWpts, false)
|
||||
Trigger.OnIdle(unit, function(actor) actor.Hunt() end)
|
||||
end)
|
||||
Trigger.AfterDelay(BaseRearAttackInterval, function() Build(BaseRearAttackUnits, BaseRearAttack) end)
|
||||
end
|
||||
|
||||
Build = function(units, action)
|
||||
if not Soviets.Build(units, action) then
|
||||
Trigger.AfterDelay(DateTime.Seconds(15), function()
|
||||
Build(units, action)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
SetupWorld = function()
|
||||
Utils.Do(SovietHarvesters, function(harvester)
|
||||
harvester.FindResources()
|
||||
Trigger.OnDamaged(harvester, function(h)
|
||||
Utils.Do(HarvesterGuard, function(g)
|
||||
if not g.IsDead then
|
||||
g.Stop()
|
||||
g.AttackMove(h.Location, 3)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
Utils.Do(Map.NamedActors, function(actor)
|
||||
if actor.Owner == Soviets and actor.HasProperty("StartBuildingRepairs") then
|
||||
Trigger.OnDamaged(actor, function(building)
|
||||
if building.Owner == Soviets then
|
||||
building.StartBuildingRepairs()
|
||||
end
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
||||
WarFactory.RallyPoint = Rallypoint.Location
|
||||
WarFactory.IsPrimaryBuilding = true
|
||||
Barracks.IsPrimaryBuilding = true
|
||||
SubPen.IsPrimaryBuilding = true
|
||||
end
|
||||
|
||||
SetupMissionText = function()
|
||||
TextColorNormal = HSLColor.White
|
||||
TextColorDamaged = HSLColor.Yellow
|
||||
TextColorCritical = HSLColor.Red
|
||||
|
||||
CurrentColor = TextColorNormal
|
||||
local villageHousesLeft = #Village
|
||||
VillagePercentage = 100 - villageHousesLeft * 10
|
||||
|
||||
Utils.Do(Village, function(house)
|
||||
Trigger.OnKilled(house, function()
|
||||
villageHousesLeft = villageHousesLeft - 1
|
||||
VillagePercentage = 100 - villageHousesLeft * 10
|
||||
|
||||
if VillagePercentage > 69 then
|
||||
CurrentColor = TextColorCritical
|
||||
elseif VillagePercentage > 49 then
|
||||
CurrentColor = TextColorDamaged
|
||||
else
|
||||
CurrentColor = TextColorNormal
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
Tick = function()
|
||||
if DateTime.GameTime > 2 then
|
||||
if Soviets.Resources > Soviets.ResourceCapacity * 0.75 then
|
||||
Soviets.Resources = Soviets.Resources - ((Soviets.ResourceCapacity * 0.01) / 25)
|
||||
end
|
||||
|
||||
if Allies.HasNoRequiredUnits() then
|
||||
Allies.MarkFailedObjective(VillageObjective)
|
||||
end
|
||||
|
||||
if CachedVillagePercentage ~= VillagePercentage then
|
||||
VillageDestroyed = UserInterface.GetFluentMessage("percentage-village-destroyed", { ["percentage"] = VillagePercentage })
|
||||
UserInterface.SetMissionText(VillageDestroyed, CurrentColor)
|
||||
CachedVillagePercentage = VillagePercentage
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
WorldLoaded = function()
|
||||
Allies = Player.GetPlayer("Allies")
|
||||
Soviets = Player.GetPlayer("Soviets")
|
||||
|
||||
InitObjectives(Allies)
|
||||
|
||||
SovietObjective = AddPrimaryObjective(Soviets, "")
|
||||
VillageObjective = AddPrimaryObjective(Allies, "save-village")
|
||||
BeachheadObjective = AddPrimaryObjective(Allies, "mcv-main-island")
|
||||
|
||||
BeachheadTriggered = false
|
||||
Trigger.OnExitedFootprint(BeachheadTrigger, function(a, id)
|
||||
if not BeachheadTriggered and a.Owner == Allies and a.Type == "mcv" then
|
||||
BeachheadTriggered = true
|
||||
Trigger.RemoveFootprintTrigger(id)
|
||||
OnBeachheadReached()
|
||||
end
|
||||
end)
|
||||
|
||||
Trigger.OnAllKilled(Village, function()
|
||||
-- There is a small time gap between the HQ capture and victory.
|
||||
-- Ensure aircraft can't trigger defeat within that gap.
|
||||
if not AirForceHQ.IsDead and AirForceHQ.Owner == Allies then
|
||||
return
|
||||
end
|
||||
|
||||
Allies.MarkFailedObjective(VillageObjective)
|
||||
end)
|
||||
|
||||
SetupWorld()
|
||||
SetupMissionText()
|
||||
ReinforceBuilder()
|
||||
Trigger.AfterDelay(VillageRaidInterval, VillageRaid)
|
||||
Trigger.AfterDelay(1, function() Build(UBoatPatrolUnits, SendUboatPatrol) end)
|
||||
Trigger.AfterDelay(1, function() Build(Utils.Random(GroundPatrolUnits), SendGroundPatrol) end)
|
||||
|
||||
Camera.Position = CameraSpot.CenterPosition
|
||||
Trigger.AfterDelay(DateTime.Seconds(5), function() CameraSpot.Destroy() end)
|
||||
end
|
||||
|
||||
ReinforceBuilder = function()
|
||||
Reinforcements.Reinforce(Allies, { "mcv" }, { MCVEntry.Location, MCVRally.Location }, 0, function(mcv)
|
||||
mcv.Deploy()
|
||||
end)
|
||||
|
||||
Trigger.AfterDelay(1, function()
|
||||
CheckBuilder(Allies)
|
||||
|
||||
if Difficulty ~= "easy" then
|
||||
return
|
||||
end
|
||||
|
||||
CheckNavalYard(Allies)
|
||||
local cam = Actor.Create("camera.hq", true, { Owner = Allies, Location = AirForceHQ.Location + CVec.New(1, 1) })
|
||||
Trigger.AfterDelay(1, cam.Destroy)
|
||||
end)
|
||||
end
|
||||
|
||||
CheckBuilder = function(player)
|
||||
if BeachheadTriggered then
|
||||
return
|
||||
end
|
||||
|
||||
local builders = player.GetActorsByTypes( { "mcv", "fact" } )
|
||||
|
||||
Utils.Do(builders, function(builder)
|
||||
Trigger.OnKilled(builder, OnBuilderLost)
|
||||
Trigger.OnSold(builder, OnBuilderLost)
|
||||
|
||||
-- The MCV deploy/undeploy creates a new actor each time,
|
||||
-- so add these triggers to the newer actor as needed.
|
||||
Trigger.OnRemovedFromWorld(builder, function()
|
||||
local transported = builder.Type == "mcv" and IsBuilderTransported(builder)
|
||||
if transported then
|
||||
-- Actors inside transports are temporarily removed from the world.
|
||||
-- In that case, more triggers are not necessary.
|
||||
return
|
||||
end
|
||||
|
||||
CheckBuilder(player)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
OnBuilderLost = function(builder)
|
||||
if BeachheadTriggered then
|
||||
return
|
||||
end
|
||||
|
||||
local speechTime = 36
|
||||
-- Let "Unit lost"/"Naval unit lost" play first.
|
||||
Trigger.AfterDelay(DateTime.Seconds(2), function()
|
||||
Media.PlaySpeechNotification(builder.Owner, "ObjectiveNotReached")
|
||||
end)
|
||||
|
||||
Trigger.AfterDelay(DateTime.Seconds(2) + speechTime, function()
|
||||
builder.Owner.MarkFailedObjective(BeachheadObjective)
|
||||
end)
|
||||
end
|
||||
|
||||
IsBuilderTransported = function(builder)
|
||||
local found = false
|
||||
local boats = builder.Owner.GetActorsByType("lst")
|
||||
|
||||
Utils.Do(boats, function(boat)
|
||||
if found or not boat.HasPassengers then
|
||||
return
|
||||
end
|
||||
|
||||
Utils.Do(boat.Passengers, function(passenger)
|
||||
if passenger == builder then
|
||||
found = true
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
return found
|
||||
end
|
||||
|
||||
CheckNavalYard = function(player)
|
||||
if player.HasPrerequisites({ "syrd" }) then
|
||||
OnNavalYardBuilt()
|
||||
return
|
||||
end
|
||||
|
||||
Trigger.AfterDelay(DateTime.Seconds(1), function()
|
||||
CheckNavalYard(player)
|
||||
end)
|
||||
end
|
||||
|
||||
OnNavalYardBuilt = function()
|
||||
local flare = Actor.Create("flare", true, { Owner = Allies, Location = BeachheadFlare.Location })
|
||||
|
||||
Trigger.AfterDelay(DateTime.Seconds(2), function()
|
||||
Media.PlaySpeechNotification(Allies, "SignalFlareEast")
|
||||
end)
|
||||
|
||||
Trigger.OnObjectiveCompleted(Allies, function(_, objective)
|
||||
if objective ~= BeachheadObjective then
|
||||
return
|
||||
end
|
||||
|
||||
Trigger.AfterDelay(DateTime.Minutes(2), function()
|
||||
if flare.IsInWorld then
|
||||
flare.Destroy()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
IsInAlliedBaseArea = function(x, y)
|
||||
local top, bottom = AlliedAreaTopLeft.CenterPosition, AlliedAreaBottomRight.CenterPosition
|
||||
-- Skip bottom.X since it is on the east edge.
|
||||
return x > top.X and y > top.Y and y < bottom.Y
|
||||
end
|
||||
|
||||
OnBeachheadReached = function()
|
||||
Media.PlaySpeechNotification(Allies, "ObjectiveReached")
|
||||
Allies.MarkCompletedObjective(BeachheadObjective)
|
||||
CaptureObjective = AddPrimaryObjective(Allies, "capture-air-force-hq")
|
||||
|
||||
Actor.Create("mainland", true, { Owner = Allies })
|
||||
|
||||
if AirForceHQ.IsDead then
|
||||
Allies.MarkFailedObjective(CaptureObjective)
|
||||
return
|
||||
end
|
||||
if AirForceHQ.Owner == Allies then
|
||||
Allies.MarkCompletedObjective(CaptureObjective)
|
||||
Allies.MarkCompletedObjective(VillageObjective)
|
||||
return
|
||||
end
|
||||
|
||||
Trigger.OnCapture(AirForceHQ, function()
|
||||
Trigger.AfterDelay(DateTime.Seconds(3), function()
|
||||
Allies.MarkCompletedObjective(CaptureObjective)
|
||||
Allies.MarkCompletedObjective(VillageObjective)
|
||||
end)
|
||||
end)
|
||||
Trigger.OnKilled(AirForceHQ, function() Allies.MarkFailedObjective(CaptureObjective) end)
|
||||
|
||||
Trigger.AfterDelay(BaseFrontAttackInterval, function()
|
||||
Build(BaseFrontAttackUnits, BaseFrontAttack)
|
||||
ParadropSovietUnits()
|
||||
end)
|
||||
Trigger.AfterDelay(BaseRearAttackInterval, function()
|
||||
Build(BaseRearAttackUnits, BaseRearAttack)
|
||||
end)
|
||||
Trigger.AfterDelay(BaseRaidInterval, BaseRaid)
|
||||
|
||||
Trigger.AfterDelay(UBoatPatrolDelay, function()
|
||||
Build(HunterSubs, function(subs)
|
||||
Utils.Do(subs, IdleHunt)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
Reference in New Issue
Block a user