Files
OpenRA/mods/ra/maps/intervention/intervention.lua

447 lines
13 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.
]]
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