Add GDI Covert Operations - Twist of Fate - scg41ea
This commit is contained in:
@@ -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.
|
||||
|
||||
BIN
mods/cnc/maps/twist-of-fate/map.bin
Normal file
BIN
mods/cnc/maps/twist-of-fate/map.bin
Normal file
Binary file not shown.
BIN
mods/cnc/maps/twist-of-fate/map.png
Normal file
BIN
mods/cnc/maps/twist-of-fate/map.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
1147
mods/cnc/maps/twist-of-fate/map.yaml
Normal file
1147
mods/cnc/maps/twist-of-fate/map.yaml
Normal file
File diff suppressed because it is too large
Load Diff
107
mods/cnc/maps/twist-of-fate/rules.yaml
Normal file
107
mods/cnc/maps/twist-of-fate/rules.yaml
Normal 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
|
||||
650
mods/cnc/maps/twist-of-fate/twist-of-fate-AI.lua
Normal file
650
mods/cnc/maps/twist-of-fate/twist-of-fate-AI.lua
Normal 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
|
||||
329
mods/cnc/maps/twist-of-fate/twist-of-fate.lua
Normal file
329
mods/cnc/maps/twist-of-fate/twist-of-fate.lua
Normal 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
|
||||
3
mods/cnc/maps/twist-of-fate/weapons.yaml
Normal file
3
mods/cnc/maps/twist-of-fate/weapons.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
IonCannon:
|
||||
Warhead@1Dam_impact: SpreadDamage
|
||||
Falloff: 1000, 60, 40, 20
|
||||
@@ -36,6 +36,7 @@ Nod Campaign:
|
||||
nod10b
|
||||
|
||||
Covert Operations:
|
||||
twist-of-fate
|
||||
eviction-notice
|
||||
|
||||
Funpark Campaign:
|
||||
|
||||
Reference in New Issue
Block a user