Fork from OpenRA/OpenRA with one-click launch script (start-ra.cmd) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
651 lines
19 KiB
Lua
651 lines
19 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.
|
|
]]
|
|
|
|
ProductionTypes = { "hand", "pyle", "afld", "weap", "hpad" }
|
|
PowerTypes = { "nuk2", "nuke" }
|
|
|
|
NodCYards = { NodCYard, NodOutPostCYard }
|
|
NodBase = { NodNuke1, NodProc1, NodHand, NodAfld, NodProc2, NodHpad1, NodNuke2, NodHq, NodGun3, NodGun4, NodNuke3, NodObli1, NodObli2, NodNuke4, NodObli3, NodObli4, NodNuke5, NodGun1, NodGun2, NodGun5, NodNuke6, NodGun6, NodNuke7, NodNuke8, NodSilo1, NodSilo2, NodSilo3, NodSilo4 }
|
|
NodRebuildList = { }
|
|
BuildingSizes = { nuk2 = CVec.New(2,3), proc = CVec.New(3,4), hand = CVec.New(2,3), afld = CVec.New(4,3), hpad = CVec.New(2,3), hq = CVec.New(2,3), obli = CVec.New(1,1), gun = CVec.New(1,1), silo = CVec.New(2,1) }
|
|
|
|
ProductionBuildings = { infantry = NodHand, vehicle = NodAfld, aircraft = NodHpad1 }
|
|
ProductionQueue = { infantry = { }, vehicle = { }, aircraft = { } }
|
|
NewTeam = { }
|
|
InitPatrolTeam = { Pat1, Pat2, Pat3 }
|
|
InitPatrolTeamAlive = true
|
|
PatrolTeam = { Pat1, Pat2, Pat3 }
|
|
BaseDefenseTeam = { Def1, Def2, Def3, Def4, Def5, Def6, Def7, Def8, Def9, Def10 }
|
|
StealthTeam = { }
|
|
TeamJob = "attack"
|
|
|
|
AT1 = { "e1", "e1", "e1", "e1", "e3", "e3", "e3", "e3", "e4", "e4", "e5", "e5" }
|
|
AT2 = { "e3", "e3", "e3", "e4", "e4", "vehicle", "ftnk", "ltnk", "ltnk", "aircraft", "heli" }
|
|
AT3 = { "vehicle", "mlrs", "bggy", "bggy", "ltnk", "ltnk", "ltnk", "arty" }
|
|
AT4 = { "vehicle", "ftnk", "ftnk", "ltnk", "ltnk", "ltnk", "aircraft", "heli", "heli" }
|
|
AT5 = { "e5", "e5", "e5", "e5", "vehicle", "bike", "bike", "ltnk", "arty" }
|
|
AT6 = { "vehicle", "ftnk", "ltnk", "ltnk", "arty", "arty", "mlrs", "stnk" }
|
|
AT7 = { "e1", "e1", "e1", "e5", "e5", "e5", "vehicle", "arty", "bike", "bike", "aircraft", "heli", "heli" }
|
|
AT8 = { "e5", "e5", "e5", "vehicle", "bike", "bike", "bike", "stnk", "stnk", "stnk" }
|
|
AT9 = { "e5", "e5", "e5", "e3", "e3", "vehicle", "ltnk", "ltnk", "arty" }
|
|
AT10 = { "vehicle", "stnk", "stnk", "stnk", "stnk", "stnk" }
|
|
AttackTeams = { AT1, AT2, AT3, AT4, AT5, AT6, AT7, AT8, AT9, AT10 }
|
|
|
|
PT1 = { "vehicle", "stnk", "stnk" }
|
|
PT2 = { "vehicle", "bike", "bike", "bike" }
|
|
PT3 = { "aircraft", "heli", "heli" }
|
|
PatrolTeams = { PT1, PT2, PT3, PT1, PT2, PT3 }
|
|
|
|
DT1 = { "vehicle", "ftnk", "ltnk", "ltnk", "arty", "arty", "aircraft", "heli", "heli", "heli" }
|
|
DT2 = { "e5", "e5", "e5", "e3", "e3", "vehicle", "arty", "arty", "bggy", "bggy", "bike" }
|
|
DT3 = { "vehicle", "bike", "bike", "bike", "bggy", "bggy", "aircraft", "heli", "heli" }
|
|
DefenseTeams = { DT1, DT2, DT3, DT1, DT2, DT3 }
|
|
|
|
ST1 = { "vehicle", "stnk", "stnk" }
|
|
ST2 = { "vehicle", "stnk", "stnk", "stnk" }
|
|
StealthTeams = { ST1, ST2, ST1, ST2 }
|
|
|
|
AP1 = { waypoint10.Location, waypoint7.Location, waypoint14.Location }
|
|
AP2 = { waypoint5.Location, waypoint7.Location, waypoint14.Location }
|
|
AP3 = { waypoint10.Location, waypoint7.Location, waypoint8.Location }
|
|
AP4 = { waypoint5.Location, waypoint7.Location, waypoint8.Location }
|
|
AP5 = { waypoint10.Location, waypoint7.Location, waypoint9.Location, waypoint2.Location, waypoint8.Location }
|
|
AP6 = { waypoint5.Location, waypoint7.Location, waypoint9.Location, waypoint2.Location, waypoint8.Location }
|
|
AttackPaths = { AP1, AP2, AP3, AP4, AP5, AP6 }
|
|
|
|
PatrolPath = { waypoint13.Location, waypoint6.Location, waypoint2.Location, waypoint9.Location }
|
|
|
|
SP1 = { waypoint7.Location, CPos.New(14,29), CPos.New(15,15), CPos.New(49,14), CPos.New(60,38), waypoint4.Location }
|
|
SP2 = { waypoint7.Location, CPos.New(14,29), CPos.New(15,15), CPos.New(27,13), waypoint9.Location }
|
|
SneakPaths = { SP1 }
|
|
|
|
ABP1 = { CPos.New(41,22), CPos.New(60,22), CPos.New(60,43), waypoint4.Location }
|
|
ABP2 = { CPos.New(28,27), waypoint10.Location, waypoint11.Location, waypoint12.Location }
|
|
ApacheBackdoorPaths = { ABP1, ABP2, ABP1, ABP2 }
|
|
|
|
InitAI = function()
|
|
Utils.Do(NodBase, function(b)
|
|
GuardBuilding(b)
|
|
Trigger.OnKilled(b, function(bd)
|
|
AddToRebuildQueue(bd)
|
|
CheckBase()
|
|
end)
|
|
end)
|
|
RepairNamedActors(Nod, 0.75)
|
|
AiProcsNumber = 2
|
|
if ProcUpgrade then
|
|
ProcUpg = Actor.Create(ProcUpgrade, true, { Owner = Nod })
|
|
end
|
|
AiAnyhqPrerequisite = Actor.Create("AiAnyhqPrerequisite", true, { Owner = Nod })
|
|
AiTmplPrerequisite = Actor.Create("AiTmplPrerequisite", true, { Owner = Nod })
|
|
Trigger.OnKilled(NodHand, function()
|
|
ProductionQueue["infantry"] = { }
|
|
CheckTeamCompleted()
|
|
end)
|
|
Trigger.OnKilled(NodAfld, function()
|
|
ProductionQueue["vehicle"] = { }
|
|
CheckTeamCompleted()
|
|
end)
|
|
Trigger.OnKilled(NodHpad1, function()
|
|
ProductionQueue["aircraft"] = { }
|
|
CheckTeamCompleted()
|
|
end)
|
|
StartGuard()
|
|
Trigger.OnAnyKilled(InitPatrolTeam, function()
|
|
InitPatrolTeamAlive = false
|
|
end)
|
|
Trigger.AfterDelay(DateTime.Seconds(ProduceBuildingsDelay), function()
|
|
CheckBase()
|
|
Trigger.AfterDelay(DateTime.Seconds(NukeDelay), function()
|
|
LaunchNuke(true)
|
|
end)
|
|
Trigger.AfterDelay(DateTime.Seconds(ProduceUnitsDelay), function()
|
|
if InitPatrolTeamAlive then
|
|
StartPatrol()
|
|
else
|
|
table.insert(UniqueTeamsQueue, { team = PatrolTeams, job = "patrol" })
|
|
end
|
|
if Difficulty == "easy" then
|
|
StealthTeams = { ST1 }
|
|
end
|
|
table.insert(UniqueTeamsQueue, { team = StealthTeams, job = "sneakAttack" })
|
|
Trigger.AfterDelay(DateTime.Seconds(Utils.RandomInteger(90,270) + ProductionCooldownSeconds), ApacheBackdoor)
|
|
CheckProduction()
|
|
ReduceProdCD()
|
|
ApacheGuard(ApacheG, NodHpad2, CPos.New(3,32), CPos.New(25,60), true)
|
|
ApacheGuard(OutpostApacheG, NodOutPostHpad, CPos.New(24,18), CPos.New(50,38), true)
|
|
end)
|
|
end)
|
|
end
|
|
|
|
-- Ai units logic
|
|
ApacheBackdoor = function()
|
|
if NodOutPostHpad.IsDead or NodOutPostHpad.Owner ~= Nod then
|
|
return
|
|
end
|
|
if not CheckProduction then
|
|
Trigger.AfterDelay(DateTime.Seconds(10), ApacheBackdoor)
|
|
end
|
|
local path = Utils.Random(ApacheBackdoorPaths)
|
|
NodOutPostHpad.Build({ "heli", "heli" }, function(team)
|
|
Utils.Do(team, function(h)
|
|
h.Stance = "AttackAnything"
|
|
for i = 1, #path do
|
|
if i < #path then
|
|
h.Move(path[i], 2)
|
|
else
|
|
h.AttackMove(path[i], 2)
|
|
end
|
|
end
|
|
IdleHunt(h)
|
|
end)
|
|
end)
|
|
Trigger.AfterDelay(DateTime.Seconds(Utils.RandomInteger(90,270) + ProductionCooldownSeconds), ApacheBackdoor)
|
|
end
|
|
|
|
ApacheGuard = function(apache, hpad, topleft, botright, init)
|
|
if apache.IsDead then
|
|
return
|
|
end
|
|
if init then
|
|
Trigger.OnKilled(apache, function()
|
|
Trigger.AfterDelay(DateTime.Seconds(Utils.RandomInteger(120,220)), function()
|
|
ApacheRebuild(hpad, topleft, botright)
|
|
end)
|
|
end)
|
|
end
|
|
local targets = Map.ActorsInBox(Map.CenterOfCell(topleft), Map.CenterOfCell(botright), function(a) return a.Owner == GDI and a.Type ~= "camera.small" end)
|
|
if #targets > 0 then
|
|
apache.Hunt()
|
|
else
|
|
if not hpad.IsDead then
|
|
apache.Stop()
|
|
apache.ReturnToBase(hpad)
|
|
end
|
|
end
|
|
Trigger.AfterDelay(Utils.RandomInteger(25,50), function()
|
|
ApacheGuard(apache, hpad, topleft, botright, false)
|
|
end)
|
|
end
|
|
|
|
ApacheRebuild = function(hpad, topleft, botright)
|
|
if hpad.IsDead and hpad.Owner == Nod then
|
|
return
|
|
end
|
|
if CheckProduction() then
|
|
hpad.Build({ "heli" }, function(h)
|
|
ApacheGuard(h[1], hpad, topleft, botright, true)
|
|
end)
|
|
else
|
|
Trigger.AfterDelay(250, function()
|
|
ApacheRebuild(hpad, topleft, botright)
|
|
end)
|
|
end
|
|
end
|
|
|
|
GuardBuilding = function(building)
|
|
Trigger.OnDamaged(building, function(_, atk, _)
|
|
if atk.Type ~= "player" and not atk.IsDead and atk.Owner == GDI then
|
|
Utils.Do(BaseDefenseTeam, function(guard)
|
|
if not guard.IsDead and not building.IsDead then
|
|
if guard.Stance == "Defend" then
|
|
guard.Stop()
|
|
guard.Stance = "AttackAnything"
|
|
guard.AttackMove(atk.Location, 3)
|
|
Trigger.OnIdle(guard, function()
|
|
guard.AttackMove(CPos.New(10,48))
|
|
guard.Stance = "Defend"
|
|
Trigger.ClearAll(guard)
|
|
end)
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
end)
|
|
end
|
|
|
|
MoveAsGroup = function(team, path, i, loop)
|
|
if i == 1 and not loop then
|
|
Utils.Do(team, function(u)
|
|
Trigger.OnDamaged(u, function(_, atk, _)
|
|
if atk.Owner == GDI then
|
|
Trigger.AfterDelay(2, function()
|
|
Utils.Do(team, function(u)
|
|
if not u.IsDead then
|
|
Trigger.Clear(u, "OnDamaged")
|
|
IdleHunt(u)
|
|
end
|
|
end)
|
|
end)
|
|
end
|
|
end)
|
|
end)
|
|
end
|
|
Utils.Do(team, function(a)
|
|
if not a.IsDead then
|
|
a.Stance = "AttackAnything"
|
|
a.AttackMove(path[i], 3)
|
|
Trigger.OnIdle(a, function()
|
|
Trigger.Clear(a, "OnIdle")
|
|
a.Stance = "Defend"
|
|
local ii = 0
|
|
local regrouped = false
|
|
Utils.Do(team, function(a)
|
|
if a.IsDead or a.Stance == "Defend" then
|
|
ii = ii + 1
|
|
if ii == #team then
|
|
regrouped = true
|
|
end
|
|
end
|
|
end)
|
|
if regrouped then
|
|
if i == #path then
|
|
if loop == true then
|
|
i = 1
|
|
else
|
|
Trigger.AfterDelay(5, function()
|
|
Utils.Do(team, function(a)
|
|
if not a.IsDead then
|
|
a.Stance = "AttackAnything"
|
|
IdleHunt(a)
|
|
end
|
|
end)
|
|
end)
|
|
return
|
|
end
|
|
else
|
|
i = i + 1
|
|
end
|
|
Trigger.AfterDelay(20, function()
|
|
MoveAsGroup(team, path, i, loop)
|
|
end)
|
|
end
|
|
end)
|
|
end
|
|
end)
|
|
end
|
|
|
|
SendStealthTanks = function()
|
|
Trigger.OnAllKilled(StealthTeam, function()
|
|
Trigger.AfterDelay(DateTime.Seconds(Utils.RandomInteger(90,270) + ProductionCooldownSeconds), function()
|
|
table.insert(UniqueTeamsQueue, { team = StealthTeams, job = "sneakAttack" })
|
|
end)
|
|
end)
|
|
local SneakPath = Utils.Random(SneakPaths)
|
|
Utils.Do(StealthTeam, function(u)
|
|
Trigger.OnDamaged(u, function()
|
|
u.Stop()
|
|
u.Hunt()
|
|
end)
|
|
u.Stance = "AttackAnything"
|
|
for i = 1, #SneakPath do
|
|
if i < #SneakPath then
|
|
u.Move(SneakPath[i], 2)
|
|
else
|
|
u.AttackMove(SneakPath[i], 2)
|
|
end
|
|
end
|
|
IdleHunt(u)
|
|
end)
|
|
end
|
|
|
|
StartGuard = function()
|
|
Trigger.OnAllKilled(BaseDefenseTeam, function()
|
|
table.insert(UniqueTeamsQueue, { team = DefenseTeams, job = "defend" })
|
|
end)
|
|
Utils.Do(BaseDefenseTeam, function(guard)
|
|
guard.Stance = "Defend"
|
|
Trigger.OnKilled(guard, function()
|
|
if #Utils.Where(BaseDefenseTeam, function(g) return g.IsDead == false end) < 6 then
|
|
Trigger.AfterDelay(5, function()
|
|
Utils.Do(BaseDefenseTeam, function(a)
|
|
if not a.IsDead then
|
|
a.Stance = "AttackAnything"
|
|
Trigger.Clear(a, "OnKilled")
|
|
IdleHunt(a)
|
|
end
|
|
end)
|
|
end)
|
|
end
|
|
end)
|
|
end)
|
|
end
|
|
|
|
StartPatrol = function()
|
|
Trigger.OnAllKilled(PatrolTeam, function()
|
|
Trigger.AfterDelay(DateTime.Seconds(Utils.RandomInteger(60, 150)), function()
|
|
table.insert(UniqueTeamsQueue, { team = PatrolTeams, job = "patrol" })
|
|
end)
|
|
end)
|
|
Utils.Do(PatrolTeam, function(a)
|
|
a.Move(CPos.New(3,28))
|
|
Trigger.OnKilled(a, function()
|
|
Utils.Do(PatrolTeam, function(a)
|
|
if not a.IsDead then
|
|
a.Stop()
|
|
IdleHunt(a)
|
|
end
|
|
end)
|
|
end)
|
|
end)
|
|
MoveAsGroup(PatrolTeam, PatrolPath, 1, true)
|
|
end
|
|
|
|
-- Building logic
|
|
AddToRebuildQueue = function(b)
|
|
local index = #NodRebuildList + 1
|
|
if b.Type == "proc" then
|
|
index = 1
|
|
elseif Utils.Any(ProductionTypes, function(pt) return pt == b.Type end) then
|
|
for i = 1, #NodRebuildList do
|
|
if NodRebuildList[i].type ~= "proc" then
|
|
index = i
|
|
break
|
|
end
|
|
end
|
|
elseif Utils.Any(PowerTypes, function(pt) return pt == b.Type end) then
|
|
for i = 1, #NodRebuildList do
|
|
local lastIndex = #NodRebuildList - (i - 1)
|
|
if NodRebuildList[lastIndex].type ~= "silo" or lastIndex == 1 then
|
|
index = lastIndex
|
|
break
|
|
end
|
|
end
|
|
elseif b.Type ~= "silo" then
|
|
for i = 1, #NodRebuildList do
|
|
local lastIndex = #NodRebuildList - (i - 1)
|
|
if NodRebuildList[lastIndex].type ~= "silo" and Utils.Any(PowerTypes, function(pt) return pt == b.Type end) or lastIndex == 1 then
|
|
index = lastIndex
|
|
break
|
|
end
|
|
end
|
|
end
|
|
table.insert(NodRebuildList, index, { type = b.Type, pos = b.Location, power = b.Power, blocked = false })
|
|
end
|
|
|
|
CheckBuildablePlace = function(b)
|
|
local blockingActors = Map.ActorsInBox(WPos.New(b.pos.X * 1024, b.pos.Y * 1024, 0), WPos.New((b.pos.X + BuildingSizes[b.type].X) * 1024, (b.pos.Y + BuildingSizes[b.type].Y) * 1024, 0), function(a) return a.Owner == GDI end)
|
|
if #blockingActors > 0 then
|
|
b.blocked = true
|
|
return false
|
|
else
|
|
b.blocked = false
|
|
return true
|
|
end
|
|
end
|
|
|
|
CheckBase = function()
|
|
|
|
if Utils.All(NodCYards, function(cy) return cy.IsDead or cy.Owner ~= Nod end) then
|
|
return
|
|
end
|
|
|
|
local queuedProcs = 0
|
|
for i = 1, #NodRebuildList do
|
|
if queuedProcs >= AiProcsNumber and Nod.Resources < 4000 then
|
|
break
|
|
elseif NodRebuildList[i].type == "proc" then
|
|
queuedProcs = queuedProcs + 1
|
|
end
|
|
|
|
if NodRebuildList[i].blocked then
|
|
CheckBuildablePlace(NodRebuildList[i])
|
|
elseif Nod.PowerProvided - Nod.PowerDrained + NodRebuildList[i].power > 0 or Utils.Any(PowerTypes, function(pt) return pt == NodRebuildList[i].type end) or NodRebuildList[i].type == "proc" then
|
|
BuildBuilding(NodRebuildList[i], NodCYards)
|
|
break
|
|
end
|
|
end
|
|
|
|
if not CheckProgrammed then
|
|
CheckProgrammed = true
|
|
Trigger.AfterDelay(250, function()
|
|
CheckProgrammed = false
|
|
CheckBase()
|
|
end)
|
|
end
|
|
|
|
end
|
|
|
|
BuildBuilding = function(building, cyards)
|
|
if CyardIsBuilding or Nod.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
|
|
Nod.Resources = Nod.Resources - Actor.Cost(building.type)
|
|
|
|
Trigger.AfterDelay(Actor.BuildTime(building.type), function()
|
|
CyardIsBuilding = false
|
|
|
|
if Utils.All(cyards, function(cy) return cy.IsDead or cy.Owner ~= Nod end) then
|
|
Nod.Resources = Nod.Resources + Actor.Cost(building.type)
|
|
return
|
|
end
|
|
|
|
if CheckBuildablePlace(building) == false then
|
|
CheckBase()
|
|
return
|
|
end
|
|
|
|
local newBuilding = Actor.Create(building.type, true, { Owner = Nod, Location = building.pos })
|
|
for i = 1, #NodRebuildList do
|
|
if NodRebuildList[i].pos == building.pos then
|
|
table.remove(NodRebuildList, i)
|
|
break
|
|
end
|
|
end
|
|
Trigger.OnKilled(newBuilding, function(b)
|
|
AddToRebuildQueue(b)
|
|
CheckBase()
|
|
end)
|
|
RepairBuilding(Nod, newBuilding, 0.75)
|
|
GuardBuilding(newBuilding)
|
|
|
|
if newBuilding.Type == "hand" then
|
|
ProductionBuildings["infantry"] = newBuilding
|
|
Trigger.OnKilled(newBuilding, function()
|
|
ProductionQueue["infantry"] = { }
|
|
CheckTeamCompleted()
|
|
end)
|
|
|
|
RestartUnitProduction()
|
|
elseif newBuilding.Type == "afld" then
|
|
ProductionBuildings["vehicle"] = newBuilding
|
|
Trigger.OnKilled(newBuilding, function()
|
|
ProductionQueue["vehicle"] = { }
|
|
CheckTeamCompleted()
|
|
WaitingAirDrop = false
|
|
end)
|
|
RestartUnitProduction()
|
|
NeedHarv = false
|
|
elseif newBuilding.Type == "hpad" then
|
|
ProductionBuildings["aircraft"] = newBuilding
|
|
Trigger.OnKilled(newBuilding, function()
|
|
ProductionQueue["aircraft"] = { }
|
|
CheckTeamCompleted()
|
|
end)
|
|
RestartUnitProduction()
|
|
end
|
|
|
|
Trigger.AfterDelay(50, function() CheckBase() end)
|
|
end)
|
|
|
|
end
|
|
|
|
-- Units production logic
|
|
UniqueTeamsQueue = { }
|
|
ProductionCooldown = false
|
|
CheckProduction = function()
|
|
if Utils.All(ProductionBuildings, function(b) return b.IsDead end) then
|
|
return
|
|
elseif #Nod.GetActorsByType("proc") < 1 and Nod.Resources < 6000 then
|
|
RestartUnitProduction()
|
|
return
|
|
elseif not ProductionBuildings["vehicle"].IsDead and not ProductionBuildings["vehicle"].IsProducing("harv") and CheckForHarvester() then
|
|
NeedHarv = true
|
|
WaitingAirDrop = true
|
|
ProductionBuildings["vehicle"].Build({ "harv" }, function()
|
|
Trigger.AfterDelay(2, function()
|
|
WaitingAirDrop = false
|
|
end)
|
|
CheckProduction()
|
|
if Utils.RandomInteger(0,2) == 1 then
|
|
Trigger.AfterDelay(DateTime.Seconds(5), function()
|
|
if not ProductionBuildings["vehicle"].IsDead then
|
|
ProductionBuildings["vehicle"].Build({ "harv" })
|
|
end
|
|
end)
|
|
end
|
|
end)
|
|
RestartUnitProduction()
|
|
return
|
|
end
|
|
NeedHarv = false
|
|
|
|
if Producing and #ProductionQueue["infantry"] + #ProductionQueue["vehicle"] + #ProductionQueue["aircraft"] < 1 then
|
|
Producing = false
|
|
end
|
|
if ProductionCooldown and #UniqueTeamsQueue < 1 or Nod.Resources < 4000 then
|
|
RestartUnitProduction()
|
|
return false
|
|
else
|
|
ProduceUnits()
|
|
return true
|
|
end
|
|
end
|
|
|
|
ReduceProdCD = function()
|
|
Trigger.AfterDelay(DateTime.Minutes(2), function()
|
|
ProductionCooldownSeconds = ProductionCooldownSeconds - 1
|
|
if ProductionCooldownSeconds > 10 then
|
|
ReduceProdCD()
|
|
end
|
|
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("e1") 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("harv") and not WaitingAirDrop then
|
|
ProductionBuildings["vehicle"].Build({ ProductionQueue["vehicle"][1] }, function(u)
|
|
if u[1].Type == "harv" then
|
|
return
|
|
end
|
|
table.insert(NewTeam, u[1])
|
|
table.remove(ProductionQueue["vehicle"], 1)
|
|
WaitingAirDrop = false
|
|
CheckTeamCompleted()
|
|
end)
|
|
WaitingAirDrop = true
|
|
end
|
|
if #ProductionQueue["aircraft"] > 0 and not ProductionBuildings["aircraft"].IsDead and not ProductionBuildings["aircraft"].IsProducing("tran") 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)
|
|
ProductionCooldown = true
|
|
Trigger.AfterDelay(DateTime.Seconds(ProductionCooldownSeconds), function() ProductionCooldown = false end)
|
|
elseif TeamJob == "patrol" then
|
|
TeamJob = "attack"
|
|
PatrolTeam = NewTeam
|
|
StartPatrol()
|
|
elseif TeamJob == "defend" then
|
|
TeamJob = "attack"
|
|
BaseDefenseTeam = NewTeam
|
|
StartGuard()
|
|
elseif TeamJob == "sneakAttack" then
|
|
TeamJob = "attack"
|
|
StealthTeam = NewTeam
|
|
SendStealthTanks()
|
|
end
|
|
Producing = false
|
|
NewTeam = { }
|
|
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 == Nod 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 = Nod.GetActorsByType("harv")
|
|
return #harv < MinHarvs
|
|
end
|