--[[ 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. ]] GDInuke1 = { type = "nuk2", pos = CPos.New(6,3), blocked = false } GDIproc1 = { type = "proc", pos = CPos.New(8,12), blocked = false } GDIpyle = { type = "pyle", pos = CPos.New(17,4), blocked = false } GDIweap = { type = "weap", pos = CPos.New(10,9), blocked = false } GDIproc2 = { type = "proc", pos = CPos.New(12,3), blocked = false } GDInuke2 = { type = "nuk2", pos = CPos.New(4,11), blocked = false } GDInuke3 = { type = "nuk2", pos = CPos.New(3,14), blocked = false } GDIdef1 = { type = "atwr", pos = CPos.New(8,5), blocked = false } GDIdef2 = { type = "atwr", pos = CPos.New(6,10), blocked = false } GDIdef3 = { type = "atwr", pos = CPos.New(6,16), blocked = false } GDIdef4 = { type = "gtwr", pos = CPos.New(9,8), blocked = false } GDInuke4 = { type = "nuk2", pos = CPos.New(13,12), blocked = false } GDIdef5 = { type = "atwr", pos = CPos.New(15,10), blocked = false } GDIdef6 = { type = "atwr", pos = CPos.New(13,16), blocked = false } GDInuke5 = { type = "nuk2", pos = CPos.New(11,14), blocked = false } GDIsilo1 = { type = "silo", pos = CPos.New(3,6), blocked = false } GDIsilo2 = { type = "silo", pos = CPos.New(5,17), blocked = false } GDIdef7 = { type = "atwr", pos = CPos.New(19,5), blocked = false } GDIdef8 = { type = "atwr", pos = CPos.New(10,21), blocked = false } GDIsilo3 = { type = "silo", pos = CPos.New(17,2), blocked = false } GDIsilo4 = { type = "silo", pos = CPos.New(9,17), blocked = false } GDIdef9 = { type = "atwr", pos = CPos.New(18,20), blocked = false } GDIhpad1 = { type = "hpad", pos = CPos.New(3,18), blocked = false } GDIBase = { GDINuke1, GDIPyle, GDIWeap, GDINuke2, GDINuke3, GDIDef1, GDIDef2, GDIDef3, GDIDef4, GDINuke4, GDIDef5, GDIDef6, GDINuke5, GDISilo1, GDISilo2, GDIDef7, GDIDef8, GDISilo3, GDISilo4, GDIDef9 } GDIRebuildList = { GDInuke1, GDIproc1, GDIpyle, GDIweap, GDIproc2, GDInuke2, GDInuke3, GDIdef1, GDIdef2, GDIdef3, GDIdef4, GDInuke4, GDIdef5, GDIdef6, GDInuke5, GDIsilo1, GDIsilo2, GDIdef7, GDIdef8, GDIsilo3, GDIsilo4, GDIdef9 } BSizes = { nuk2 = CVec.New(2,3), proc = CVec.New(3,4), pyle = CVec.New(2,3), weap = CVec.New(3,3), atwr = CVec.New(1,1), gtwr = CVec.New(1,1), silo = CVec.New(2,1), hpad = CVec.New(2,2) } ProductionBuildings = { infantry = GDIPyle, vehicle = GDIWeap, aircraft = GDICYard } ProductionQueue = { infantry = { }, vehicle = { }, aircraft = { } } NewTeam = { } TeamJob = "attack" AT1 = { "e2", "e2", "e2", "e3", "e3", "vehicle", "jeep", "jeep", "apc" } AT2 = { "e2", "e2", "e2", "e3", "e3", "e1", "e1", "e1", "e1" } AT3 = { "vehicle", "mtnk", "mtnk", "jeep", "jeep" } AT4 = { "e3", "e3", "e1", "e1", "e1", "vehicle", "mtnk", "mtnk", "msam" } AT5 = { "vehicle", "jeep", "jeep", "jeep", "apc", "apc" } AT6 = { "e3", "e3", "e1", "e1", "e1", "vehicle", "htnk" } AT7 = { "vehicle", "htnk", "htnk", "mtnk" } AT8 = { "vehicle", "htnk", "htnk", "msam" } AT9 = { "vehicle", "mtnk", "msam", "apc", "apc" } AT10 = { "e2", "e2", "e2", "e2", "e2", "e2", "e2", "e2", "e2", "e2" } OT1 = { "aircraft", "orca", "orca" } OT2 = { "aircraft", "orca", "orca", "orca", "orca" } AttackTeams = { AT1, AT2, AT3, AT4, AT5, AT6, AT7, AT8, AT9, AT10 } PT1 = { "vehicle", "htnk" } PT2 = { "vehicle", "mtnk", "mtnk" } PT3 = { "e2", "e2", "e2", "e3", "e3" } PatrolTeams = { PT1, PT2, PT3 } DT1 = { "vehicle", "mtnk", "mtnk", "msam", "msam" } DT2 = { "e3", "e3", "e1", "e1", "e1", "vehicle", "mtnk", "mtnk", "msam" } DT3 = { "vehicle", "htnk", "htnk", "msam" } DefenseTeams = { DT1, DT2, DT3 } AddOrcasTo = { AT1, AT2, AT5, AT6, AT9, DT1, DT2, DT3 } AP1 = { waypoint5.Location, waypoint9.Location, waypoint8.Location, waypoint13.Location } AP2 = { waypoint2.Location, waypoint5.Location, waypoint4.Location, waypoint6.Location } AP3 = { waypoint2.Location, waypoint3.Location, waypoint4.Location, waypoint6.Location } AP4 = { waypoint5.Location, waypoint9.Location, waypoint14.Location, PlayerStart.Location, waypoint13.Location } AP5 = { waypoint5.Location, waypoint9.Location, waypoint6.Location } AttackPaths = { AP1, AP2, AP3, AP4, AP5 } InitAi = function() if Difficulty == "hard" then PBDelay = 115 PUDelay = 30 ICDelay = 800 ProdCDSecs = 30 GDI.Resources = 10000 MinHarvs = 3 ProcUpgrade = "AIHProcUpgrade" CivsBuildingsToDestroy = 8 end if Difficulty == "normal" then PBDelay = 140 PUDelay = 50 ICDelay = 1000 ProdCDSecs = 40 GDI.Resources = 7000 MinHarvs = 2 ProcUpgrade = "AINProcUpgrade" CivsBuildingsToDestroy = 11 end if Difficulty == "easy" then PBDelay = 180 PUDelay = 70 ICDelay = 1200 ProdCDSecs = 50 GDI.Resources = 5000 MinHarvs = 2 Nod.Resources = 3000 CivsBuildingsToDestroy = 13 end RepairNamedActors(GDI, 0.75) SetAutoRebuild() Trigger.OnKilled(GDIPyle, function() ProductionQueue["infantry"] = { } end) Trigger.OnKilled(GDIWeap, function() ProductionQueue["vehicle"] = { } end) if ProcUpgrade then ProcUpg = Actor.Create(ProcUpgrade, true, { Owner = GDI }) end Trigger.AfterDelay(DateTime.Seconds(PBDelay), function() CheckBase() Trigger.AfterDelay(DateTime.Seconds(PUDelay), function() ProduceUnits() ReduceProdCD() end) Trigger.AfterDelay(DateTime.Seconds(ICDelay), function() FireIonCannon(270) end) if not GDIAdvComCenter.IsDead then IonCannonOnline = true Media.DisplayMessage(UserInterface.GetFluentMessage("destroy-ion-cannon-advice")) DestroyIonCannon = AddSecondaryObjective(Nod, "quickly-destroy-ion-cannon") end end) end ReduceProdCD = function() Trigger.AfterDelay(DateTime.Minutes(2), function() ProdCDSecs = ProdCDSecs - 1 if ProdCDSecs > 10 then ReduceProdCD() end end) end PrepareOrcas = function() table.insert(GDIRebuildList, 11, GDIhpad1) Utils.Do(AddOrcasTo, function(t) Utils.Do(OT1, function(u) table.insert(t, u) end) end) table.insert(AttackTeams, OT2) table.insert(PatrolTeams, OT1) end --Building logic SetAutoRebuild = function() Utils.Do(GDIBase, function(b) Trigger.OnKilled(b, CheckBase) end) end CheckBase = function() if GDICYard.IsDead then return end for i = 1, #GDIRebuildList do if GDIRebuildList[i].blocked then CheckBuildablePlace(GDIRebuildList[i]) else local building = GDI.GetActorsByType(GDIRebuildList[i].type) if #building < 1 then BuildBuilding(GDIRebuildList[i], GDICYard) return end for ii = 1, #building do if not building[ii].IsDead and building[ii].Location == GDIRebuildList[i].pos then break end if ii == #building then BuildBuilding(GDIRebuildList[i], GDICYard) return end end end end if not CheckProgrammed then CheckProgrammed = true Trigger.AfterDelay(250, function() CheckProgrammed = false CheckBase() end) end end CheckBuildablePlace = function(b) local actors = Map.ActorsInBox(WPos.New(b.pos.X * 1024, b.pos.Y * 1024, 0), WPos.New((b.pos.X + BSizes[b.type].X) * 1024, (b.pos.Y + BSizes[b.type].Y) * 1024, 0), function(a) return a.Owner == Nod end) if #actors > 0 then b.blocked = true return false else b.blocked = false return true end end BuildBuilding = function(building, cyard) if CyardIsBuilding or GDI.Resources < Actor.Cost(building.type) then if Dontspam == true then return end Dontspam = true Trigger.AfterDelay(DateTime.Seconds(10), function() Dontspam = false CheckBase() end) return end CyardIsBuilding = true GDI.Resources = GDI.Resources - Actor.Cost(building.type) Trigger.AfterDelay(Actor.BuildTime(building.type), function() CyardIsBuilding = false if cyard.IsDead or cyard.Owner ~= GDI then GDI.Resources = GDI.Resources + Actor.Cost(building.type) return end if CheckBuildablePlace(building) == false then CheckBase() return end local newbuilding = Actor.Create(building.type, true, { Owner = GDI, Location = building.pos }) Trigger.OnKilled(newbuilding, function() CheckBase() end) RepairBuilding(GDI, newbuilding, 0.75) GuardBuilding(newbuilding) if newbuilding.Type == "pyle" then ProductionBuildings["infantry"] = newbuilding Trigger.OnKilled(newbuilding, function() ProductionQueue["infantry"] = { } end) RestartUnitProduction() elseif newbuilding.Type == "weap" then ProductionBuildings["vehicle"] = newbuilding Trigger.OnKilled(newbuilding, function() ProductionQueue["vehicle"] = { } end) RestartUnitProduction() NeedHarv = false elseif newbuilding.Type == "hpad" then ProductionBuildings["aircraft"] = newbuilding Trigger.OnKilled(newbuilding, function() ProductionQueue["aircraft"] = { } end) RestartUnitProduction() end Trigger.AfterDelay(50, CheckBase) end) end --Units production logic UniqueTeamsQueue = { } ProdCooldown = false CheckProduction = function() if #GDI.GetActorsByType("proc") < 1 and GDI.Resources < 6000 then Trigger.AfterDelay(250, CheckProduction) return elseif ProductionBuildings["infantry"].IsDead and ProductionBuildings["vehicle"].IsDead and ProductionBuildings["aircraft"].IsDead then return elseif not ProductionBuildings["vehicle"].IsDead and CheckForHarvester() then NeedHarv = true ProductionBuildings["vehicle"].Build( { "harv" }, function() CheckProduction() Trigger.AfterDelay(DateTime.Seconds(5), function() if not ProductionBuildings["vehicle"].IsDead then ProductionBuildings["vehicle"].Build( { "harv" } ) end end) end) return end NeedHarv = false if #ProductionQueue["infantry"] + #ProductionQueue["vehicle"] + #ProductionQueue["aircraft"] < 1 and Producing then Producing = false end if ProdCooldown or GDI.Resources < 4000 then RestartUnitProduction() else ProduceUnits() end end ProduceUnits = function() if NeedHarv then RestartUnitProduction() return end if not Producing then NewTeam = { } CreateUnitsGroup() if #ProductionQueue["infantry"] + #ProductionQueue["vehicle"] + #ProductionQueue["aircraft"] > 0 then Producing = true else RestartUnitProduction() return end end if #ProductionQueue["infantry"] > 0 and not ProductionBuildings["infantry"].IsDead and not ProductionBuildings["infantry"].IsProducing("e2") then ProductionBuildings["infantry"].Build( { ProductionQueue["infantry"][1] }, function(u) table.insert(NewTeam, u[1]) table.remove(ProductionQueue["infantry"], 1) CheckTeamCompleted() end) end if #ProductionQueue["vehicle"] > 0 and not ProductionBuildings["vehicle"].IsDead and not ProductionBuildings["vehicle"].IsProducing("mtnk") then ProductionBuildings["vehicle"].Build( { ProductionQueue["vehicle"][1] }, function(u) table.insert(NewTeam, u[1]) table.remove(ProductionQueue["vehicle"], 1) CheckTeamCompleted() end) end if #ProductionQueue["aircraft"] > 0 and not ProductionBuildings["aircraft"].IsDead and not ProductionBuildings["aircraft"].IsProducing("orca") then ProductionBuildings["aircraft"].Build( { ProductionQueue["aircraft"][1] }, function(u) table.insert(NewTeam, u[1]) table.remove(ProductionQueue["aircraft"], 1) CheckTeamCompleted() end) end RestartUnitProduction() end CheckTeamCompleted = function() if #ProductionQueue["infantry"] + #ProductionQueue["vehicle"] + #ProductionQueue["aircraft"] < 1 and #NewTeam > 0 then NewTeam = Utils.Where(NewTeam, function(u) return not u.IsDead end) if TeamJob == "attack" then SendAttackGroup(NewTeam) elseif TeamJob == "patrol" then TeamJob = "attack" PatrolTeam = NewTeam StartPatrol() elseif TeamJob == "defend" then TeamJob = "attack" BaseDefenseTeam = NewTeam StartGuard() end Producing = false ProdCooldown = true NewTeam = { } Trigger.AfterDelay(DateTime.Seconds(ProdCDSecs), function() ProdCooldown = false end) else ProduceUnits() end end SendAttackGroup = function(team) MoveAsGroup(team, Utils.Random(AttackPaths), 1, false) end CreateUnitsGroup = function() local team = AttackTeams if #UniqueTeamsQueue > 0 then team = UniqueTeamsQueue[1].team TeamJob = UniqueTeamsQueue[1].job table.remove(UniqueTeamsQueue, 1) end local pb = "infantry" Utils.Do(Utils.Random(team), function(u) if u == "vehicle" or u == "aircraft" then pb = u elseif ProductionBuildings[pb] and not ProductionBuildings[pb].IsDead and ProductionBuildings[pb].Owner == GDI then table.insert(ProductionQueue[pb], u) end end) end RestartUnitProduction = function() if not Restarting then Restarting = true else return end Trigger.AfterDelay(DateTime.Seconds(5), function() Restarting = false CheckProduction() end) end CheckForHarvester = function() local harv = GDI.GetActorsByType("harv") return #harv < MinHarvs end