353 lines
10 KiB
Lua
353 lines
10 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.
|
|
]]
|
|
|
|
CapturableStructures = { "weap", "pyle", "hq", "nuke", "nuk2", "silo", "proc" , "fact" }
|
|
|
|
ClearPathCameras = { Cam1, Cam2, Cam3, Cam4, Cam5 }
|
|
NodSams = { NodSam1, NodSam2, NodSam3, NodSam4, NodSam5, NodSam6, NodSam7 }
|
|
NodGuns = { Actor68, Actor69, NodGun4, Actor66 }
|
|
OldGDIBase = { OldGDIProc, OldGDIWeap, OldGDIPyle, OldGDIGtwr1, OldGDIGtwr2, OldGDIGtwr3 }
|
|
|
|
HeliTransEngineers = { "e6", "e6", "e6", "e6", "e6" }
|
|
|
|
CenterNodBaseEntrance = { CPos.New(35,22), CPos.New(33,23), CPos.New(34,23), CPos.New(35,23), CPos.New(36,23), CPos.New(33,24), CPos.New(34,24), CPos.New(35,24), CPos.New(33,25), CPos.New(34,25), CPos.New(32,27), CPos.New(33,27), CPos.New(32,28), CPos.New(33,28), CPos.New(31,29), CPos.New(32,29), CPos.New(33,29), CPos.New(31,30), CPos.New(32,30), CPos.New(33,30) }
|
|
|
|
GoDemolitionMan = function(rmbo)
|
|
if rmbo.IsDead then
|
|
return
|
|
end
|
|
|
|
local structures = Utils.Where(Map.ActorsInCircle(rmbo.CenterPosition , WDist.FromCells(6)), function(u) return u.HasProperty("StartBuildingRepairs") and u.Owner == GDI end)
|
|
if #structures > 0 then
|
|
rmbo.Stop()
|
|
rmbo.Demolish(Utils.Random(structures))
|
|
rmbo.Hunt()
|
|
Trigger.AfterDelay(DateTime.Seconds(10), function() GoDemolitionMan(rmbo) end)
|
|
end
|
|
end
|
|
|
|
EngineersSent = false
|
|
SendEngTeam = function()
|
|
if not EngineersSent then
|
|
EngineersSent = true
|
|
local cargo = Reinforcements.ReinforceWithTransport(Nod, "tran", HeliTransEngineers, { CPos.New(0,32), waypoint11.Location }, { CPos.New(0,32) })[2]
|
|
Utils.Do(cargo, function(engs)
|
|
engs.Move(CPos.New(39,52))
|
|
Trigger.OnIdle(engs, CaptureStructures)
|
|
end)
|
|
end
|
|
end
|
|
|
|
CaptureStructures = function(actor)
|
|
local structures = GDI.GetActorsByTypes(CapturableStructures)
|
|
local distance = 500
|
|
local captst = nil
|
|
Utils.Do(structures, function(st)
|
|
if not actor.IsDead and not st.IsDead and distance > (math.abs((actor.Location - st.Location).X) + math.abs((actor.Location - st.Location).Y)) then
|
|
distance = math.abs((actor.Location - st.Location).X) + math.abs((actor.Location - st.Location).Y)
|
|
captst = st
|
|
end
|
|
end)
|
|
|
|
if captst then
|
|
actor.Capture(captst)
|
|
end
|
|
end
|
|
|
|
LaunchNuke = function(loop)
|
|
if NukeDelay == 0 then
|
|
return
|
|
end
|
|
|
|
local targets = GDI.GetActorsByTypes({ "nuk2", "atwr", "weap", "proc" })
|
|
if #targets < 1 then
|
|
targets = GDI.GetGroundAttackers()
|
|
end
|
|
|
|
if not NodTmpl.IsDead then
|
|
Media.PlaySpeechNotification(GDI, "NuclearWarheadApproaching")
|
|
NodTmpl.ActivateNukePower(Utils.Random(targets).Location)
|
|
end
|
|
|
|
if loop then
|
|
Trigger.AfterDelay(DateTime.Seconds(NukeDelay), function() LaunchNuke(true) end)
|
|
end
|
|
end
|
|
|
|
SendNodAirstrike = function(loop)
|
|
if AstkDelay == 0 then
|
|
return
|
|
end
|
|
|
|
local target = GetAirstrikeTarget(GDI)
|
|
if target then
|
|
NodAirSupport.TargetAirstrike(target, Angle.SouthEast)
|
|
if loop then
|
|
Trigger.AfterDelay(DateTime.Seconds(AstkDelay), function() SendNodAirstrike(true) end)
|
|
end
|
|
else
|
|
Trigger.AfterDelay(DateTime.Seconds(20), function() SendNodAirstrike(loop) end)
|
|
end
|
|
end
|
|
|
|
SendEasyReinforcements = function(i)
|
|
local team = { }
|
|
if i < 4 then
|
|
team = ReinforceTeams[i]
|
|
else
|
|
team = ReinforceTeams[Utils.RandomInteger(1, 4)]
|
|
end
|
|
|
|
Media.PlaySpeechNotification(GDI, "Reinforce")
|
|
Reinforcements.Reinforce(GDI, team, { CPos.New(56,2), waypoint0.Location }, 25, function(a)
|
|
a.Move(waypoint1.Location, 2)
|
|
a.Move(waypoint2.Location, 2)
|
|
a.Move(CPos.New(49,44), 2)
|
|
end)
|
|
|
|
Trigger.AfterDelay(DateTime.Seconds(ReinforceDelay), function()
|
|
SendEasyReinforcements(i + 1)
|
|
end)
|
|
end
|
|
|
|
CheckObjectives = function()
|
|
if Nod.HasNoRequiredUnits() then GDI.MarkCompletedObjective(EliminateAllNod) end
|
|
if GDI.HasNoRequiredUnits() then GDI.MarkFailedObjective(EliminateAllNod) end
|
|
Trigger.AfterDelay(50, CheckObjectives)
|
|
end
|
|
|
|
CompleteCaptureCommCenterObjective = function()
|
|
GDI.MarkCompletedObjective(CaptureCommCenter)
|
|
if not NodCYard.IsDead and NodCYard.Owner == Nod then
|
|
Trigger.Clear(NodCYard, "OnDamaged")
|
|
Trigger.AfterDelay(1, function()
|
|
RepairBuilding(Nod, NodCYard, 0.75)
|
|
NodCYard.StartBuildingRepairs()
|
|
end)
|
|
end
|
|
|
|
Media.DisplayMessage(UserInterface.Translate("communications-center-captured-sams-located"))
|
|
local activeSams = Nod.GetActorsByType("sam")
|
|
local miniCams = { }
|
|
if #activeSams > 0 then
|
|
Utils.Do(activeSams, function(s)
|
|
table.insert(miniCams, Actor.Create("camera.mini", true, { Owner = GDI, Location = s.Location }))
|
|
table.insert(miniCams, Actor.Create("camera.mini", true, { Owner = GDI, Location = CPos.New(s.Location.X + 1, s.Location.Y) }))
|
|
end)
|
|
|
|
Trigger.AfterDelay(1, function()
|
|
Utils.Do(miniCams, function(c)
|
|
c.Destroy()
|
|
end)
|
|
end)
|
|
end
|
|
end
|
|
|
|
WorldLoaded = function()
|
|
Camera.Position = DefaultCameraPosition.CenterPosition
|
|
GDI = Player.GetPlayer("GDI")
|
|
Nod = Player.GetPlayer("Nod")
|
|
|
|
if Difficulty == "hard" then
|
|
ProduceBuildingsDelay = 50
|
|
ProduceUnitsDelay = 10
|
|
ProductionCooldownSeconds = 30
|
|
MinHarvs = 3
|
|
AstkDelay = 180
|
|
NukeDelay = 900
|
|
ProcUpgrade = "AIHProcUpgrade"
|
|
Nod.Resources = 3000
|
|
GDI.Cash = 3000
|
|
MCVReinf = { "mcv" }
|
|
end
|
|
|
|
if Difficulty == "normal" then
|
|
ProduceBuildingsDelay = 70
|
|
ProduceUnitsDelay = 15
|
|
ProductionCooldownSeconds = 55
|
|
MinHarvs = 3
|
|
AstkDelay = 220
|
|
NukeDelay = 1200
|
|
Nod.Resources = 3000
|
|
GDI.Cash = 4000
|
|
ProcUpgrade = "AINProcUpgrade"
|
|
MCVReinf = { "mtnk", "mcv" }
|
|
end
|
|
|
|
if Difficulty == "easy" then
|
|
ProduceBuildingsDelay = 100
|
|
ProduceUnitsDelay = 35
|
|
ProductionCooldownSeconds = 85
|
|
MinHarvs = 2
|
|
AstkDelay = 250
|
|
NukeDelay = 1500
|
|
Nod.Resources = 2000
|
|
GDI.Cash = 5000
|
|
MCVReinf = { "mtnk", "mtnk", "mcv", "mtnk" }
|
|
RT1 = { "jeep", "jeep", "apc" }
|
|
RT2 = { "mtnk", "msam" }
|
|
RT3 = { "htnk" }
|
|
ReinforceTeams = { RT1, RT2, RT3 }
|
|
ReinforceDelay = 240
|
|
Actor137.Teleport(CPos.New(57,6))
|
|
Actor203.Destroy()
|
|
end
|
|
|
|
GDI.PlayLowPowerNotification = false
|
|
|
|
InitObjectives(GDI)
|
|
ClearPath = AddPrimaryObjective(GDI, "clear-path")
|
|
Trigger.AfterDelay(DateTime.Seconds(5), function()
|
|
EliminateAllNod = AddPrimaryObjective(GDI, "eliminate-nod")
|
|
end)
|
|
|
|
InitAI()
|
|
CheckObjectives()
|
|
|
|
Flare = Actor.Create("flare", true, { Owner = GDI, Location = DefaultFlareLocation.Location })
|
|
|
|
Trigger.AfterDelay(1, function()
|
|
AmbushTeam = Map.ActorsInBox(Map.CenterOfCell(CPos.New(46,5)), Map.CenterOfCell(CPos.New(60,53)), function(a) return a.Owner == Nod and a.Type ~= "stnk" end)
|
|
Trigger.OnAllKilled(AmbushTeam, function()
|
|
GDI.MarkCompletedObjective(ClearPath)
|
|
|
|
Trigger.AfterDelay(DateTime.Seconds(2), function()
|
|
Trigger.AfterDelay(DateTime.Seconds(30), function()
|
|
Flare.Destroy()
|
|
end)
|
|
|
|
Media.PlaySpeechNotification(GDI, "Reinforce")
|
|
Reinforcements.Reinforce(GDI, MCVReinf, { CPos.New(56,2), waypoint0.Location }, 25, function(a)
|
|
a.Move(waypoint1.Location, 2)
|
|
a.Move(waypoint2.Location, 2)
|
|
a.Move(CPos.New(49,44), 2)
|
|
if a.HasProperty("Deploy") then
|
|
a.Move(CPos.New(48,51))
|
|
a.Deploy()
|
|
|
|
Trigger.OnRemovedFromWorld(a, function()
|
|
if not a.IsDead then
|
|
GDI.PlayLowPowerNotification = true
|
|
end
|
|
end)
|
|
end
|
|
end)
|
|
|
|
Utils.Do(ClearPathCameras, function(c)
|
|
c.Destroy()
|
|
end)
|
|
|
|
if Difficulty == "easy" then
|
|
Trigger.AfterDelay(DateTime.Seconds(ReinforceDelay), function()
|
|
SendEasyReinforcements(1)
|
|
end)
|
|
end
|
|
end)
|
|
Trigger.AfterDelay(DateTime.Seconds(8), function()
|
|
RecoverOldBase = AddSecondaryObjective(GDI, "recover-old-base")
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
NodAirSupport = Actor.Create("Astk.proxy", true, { Owner = Nod })
|
|
Trigger.AfterDelay(DateTime.Seconds(AstkDelay), function()
|
|
if AstkDelay > 0 then
|
|
SendNodAirstrike(true)
|
|
Trigger.AfterDelay(DateTime.Seconds(15), function()
|
|
Media.DisplayMessage(UserInterface.Translate("air-strikes-intel-report"))
|
|
Trigger.AfterDelay(DateTime.Seconds(8), function()
|
|
CaptureCommCenter = AddSecondaryObjective(GDI, "capture-nod-communications-center")
|
|
if NodAstkHq.IsDead then
|
|
GDI.MarkFailedObjective(CaptureCommCenter)
|
|
return
|
|
end
|
|
|
|
if NodAstkHq.Owner == GDI then
|
|
Trigger.AfterDelay(DateTime.Seconds(4), CompleteCaptureCommCenterObjective)
|
|
end
|
|
end)
|
|
end)
|
|
end
|
|
end)
|
|
|
|
Trigger.OnKilled(NodOutPostCYard, function()
|
|
SendNodAirstrike(false)
|
|
if not RecoverOldBase then
|
|
RecoverOldBase = AddSecondaryObjective(GDI, "recover-old-base")
|
|
end
|
|
GDI.MarkFailedObjective(RecoverOldBase)
|
|
end)
|
|
|
|
Trigger.OnCapture(NodOutPostCYard, function()
|
|
Trigger.ClearAll(NodOutPostCYard)
|
|
Utils.Do(OldGDIBase, function(building)
|
|
if not building.IsDead then
|
|
building.Owner = GDI
|
|
end
|
|
end)
|
|
|
|
GDI.MarkCompletedObjective(RecoverOldBase)
|
|
table.insert(SneakPaths, SP2)
|
|
table.insert(SneakPaths, SP1)
|
|
table.insert(SneakPaths, SP2)
|
|
end)
|
|
|
|
Utils.Do(NodGuns, function(g)
|
|
Trigger.OnKilled(g, function()
|
|
SendEngTeam()
|
|
Utils.Do(NodGuns, function(gun) if not gun.IsDead then Trigger.Clear(gun, "OnKilled") end end)
|
|
end)
|
|
end)
|
|
|
|
RamboSent = false
|
|
Trigger.OnEnteredFootprint(CenterNodBaseEntrance, function(a, id)
|
|
if a.Owner == GDI and not RamboSent then
|
|
RamboSent = true
|
|
local cargo = Reinforcements.ReinforceWithTransport(Nod, "tran", { "rmbo" }, { CPos.New(0,32), waypoint12.Location }, { CPos.New(0,32) })[2]
|
|
Trigger.OnIdle(cargo[1], function()
|
|
Trigger.Clear(cargo[1], "OnIdle")
|
|
Media.PlaySpeechNotification(GDI, "BaseAttack")
|
|
Trigger.AfterDelay(5, function() GoDemolitionMan(cargo[1]) end)
|
|
end)
|
|
Trigger.RemoveFootprintTrigger(id)
|
|
end
|
|
end)
|
|
|
|
Trigger.OnDamaged(NodCYard, function(_, atk, _)
|
|
if atk.Owner == GDI and not NukeLaunched then
|
|
NukeLaunched = true
|
|
LaunchNuke(false)
|
|
Trigger.Clear(NodCYard, "OnDamaged")
|
|
Trigger.AfterDelay(1, function()
|
|
RepairBuilding(Nod, NodCYard, 0.75)
|
|
NodCYard.StartBuildingRepairs()
|
|
end)
|
|
end
|
|
end)
|
|
|
|
Trigger.OnKilledOrCaptured(NodTmpl, function()
|
|
NukeDelay = 0
|
|
end)
|
|
|
|
Trigger.OnCapture(NodAstkHq, function()
|
|
AstkDelay = 0
|
|
Trigger.ClearAll(NodAstkHq)
|
|
if CaptureCommCenter then
|
|
CompleteCaptureCommCenterObjective()
|
|
end
|
|
end)
|
|
|
|
Trigger.OnKilled(NodAstkHq, function()
|
|
if CaptureCommCenter then
|
|
GDI.MarkFailedObjective(CaptureCommCenter)
|
|
end
|
|
AstkDelay = 0
|
|
end)
|
|
end
|