Add GDI Covert Operations - Twist of Fate - scg41ea

This commit is contained in:
yamismo
2023-04-20 20:00:07 +02:00
committed by abcdefg30
parent e487c3366d
commit b1fd392486
9 changed files with 2248 additions and 1 deletions

View File

@@ -25,7 +25,7 @@ kill-creatures = Kill all creatures in the area.
## gdi01
establish-beachhead = Establish a beachhead.
## gdi01, gdi02, gdi03, gdi04c, gdi05abc
## gdi01, gdi02, gdi03, gdi04c, gdi05abc, twist-of-fate
eliminate-nod = Eliminate all Nod forces in the area.
## gdi02, nod09
@@ -150,3 +150,13 @@ nod-soldier = Nod Soldier
civilians-runs = Hey, those civilians... where are they going?
destroy-ion-cannon-advise = The GDI are preparing their ion cannon. Don't let them get used to it.
village-destruction-warning = Be careful, commander. The GDI won't stand still while we burn the entire village.
## twist-of-fate
clear-path = Repel the ambush and clear the way
for our MCV.
recover-old-base = Capture the Construction Yard in our recon
post to regain control.
air-strikes-intel-report = Nod airstrikes are being directed by a Communications Center, located northwest. We may gain useful information from its capture.
capture-nod-communications-center = Capture the Nod Communications Center to
the northwest.
communications-center-captured-sams-located = Our engineers located Nod SAM sites. They also disarmed an unusual trap on the Construction Yard to the south.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,107 @@
World:
MissionData:
StartVideo: airstrk.vqa
LossVideo: obel.vqa
WinVideo: paratrop.vqa
Briefing: We had set up a small recon post in Nod territory, but they captured and reinforced it.\n\nGetting that post back would be a major coup.\n\nAn MCV and armed convoy are on their way to aid you in establishing a new base.\n\nOnce established, eliminate all Nod forces in the area.
LuaScript:
Scripts: campaign.lua, utils.lua, twist-of-fate.lua, twist-of-fate-AI.lua
ScriptLobbyDropdown@difficulty:
ID: difficulty
Label: dropdown-difficulty.label
Description: dropdown-difficulty.description
Values:
easy: options-difficulty.easy
normal: options-difficulty.normal
hard: options-difficulty.hard
Default: normal
Player:
PlayerResources:
DefaultCash: 0
CAMERA.mini:
Inherits: CAMERA
RevealsShroud:
Range: 1c512
Type: CenterPosition
RenderSpritesEditorOnly:
Image: camera
FLARE:
RevealsShroud:
Range: 7c0
PROC:
GrantConditionOnPrerequisite@AIN:
Condition: ain
Prerequisites: diffnorm
GrantConditionOnPrerequisite@AIH:
Condition: aih
Prerequisites: diffhard
ResourceValueMultiplier@AIN:
Modifier: 150
RequiresCondition: ain
ResourceValueMultiplier@AIH:
Modifier: 200
RequiresCondition: aih
AIHProcUpgrade:
ProvidesPrerequisite:
Prerequisite: diffhard
StoresResources:
Capacity: 25000
Interactable:
AlwaysVisible:
AINProcUpgrade:
ProvidesPrerequisite:
Prerequisite: diffnorm
StoresResources:
Capacity: 15000
Interactable:
AlwaysVisible:
AiAnyhqPrerequisite:
ProvidesPrerequisite:
Prerequisite: anyhq
Interactable:
AlwaysVisible:
AiTmplPrerequisite:
ProvidesPrerequisite:
Prerequisite: tmpl
Interactable:
AlwaysVisible:
Astk.proxy:
AlwaysVisible:
AirstrikePower:
StartFullyCharged: True
Prerequisites: ~techlevel.superweapons
Icon: airstrike
ChargeInterval: 5250
SquadSize: 3
QuantizedFacings: 8
Name: Air Strike
Description: Deploy an aerial napalm strike.\nBurns buildings and infantry along a line.
EndChargeSpeechNotification: AirstrikeReady
SelectTargetSpeechNotification: SelectTarget
InsufficientPowerSpeechNotification: InsufficientPower
IncomingSpeechNotification: EnemyPlanesApproaching
EndChargeTextNotification: Airstrike ready.
SelectTargetTextNotification: Select target.
InsufficientPowerTextNotification: Insufficient power.
IncomingTextNotification: Enemy planes approaching.
UnitType: a10
DisplayBeacon: True
BeaconPoster: airstrike
BeaconPosterPalette: beaconposter
DisplayRadarPing: True
CameraActor: camera
ArrowSequence: arrow
ClockSequence: clock
CircleSequence: circles
UseDirectionalTarget: True
DirectionArrowAnimation: airstrikedirection
SupportPowerPaletteOrder: 10

View File

@@ -0,0 +1,650 @@
--[[
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

View File

@@ -0,0 +1,329 @@
--[[
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
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()
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

View File

@@ -0,0 +1,3 @@
IonCannon:
Warhead@1Dam_impact: SpreadDamage
Falloff: 1000, 60, 40, 20

View File

@@ -36,6 +36,7 @@ Nod Campaign:
nod10b
Covert Operations:
twist-of-fate
eviction-notice
Funpark Campaign: