diff --git a/mods/cnc/languages/lua/en.ftl b/mods/cnc/languages/lua/en.ftl index 96940fb6ed..928fdfad7a 100644 --- a/mods/cnc/languages/lua/en.ftl +++ b/mods/cnc/languages/lua/en.ftl @@ -111,7 +111,7 @@ infiltrate-barracks-factory-conyard = Infiltrate the barracks, weapon factory an ## nod07a find-nod-base = Find the Nod base. -## nod07ab, nod08ab, nod09 +## nod07ab, nod08ab, nod09, eviction-notice eliminate-gdi-forces = Eliminate all GDI forces in the area. ## nod07c @@ -140,3 +140,13 @@ destroy-tech-center = Destroy the GDI R&D center. destroy-capture-warfactory = Destroy or capture the Weapons Factory. destroy-mammoth-tanks = Destroy the Mammoth tanks in the R&D base. keep-commando-alive = Keep your Commando alive. + +## eviction-notice +take-civilians-money-crates = Find all the civilians' money. + They won't need it anymore. +quickly-destroy-ion-cannon = Disable GDI Ion Cannon before + it fires two times. +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. diff --git a/mods/cnc/maps/eviction-notice/eviction-notice-AI.lua b/mods/cnc/maps/eviction-notice/eviction-notice-AI.lua new file mode 100644 index 0000000000..4c7263440f --- /dev/null +++ b/mods/cnc/maps/eviction-notice/eviction-notice-AI.lua @@ -0,0 +1,407 @@ +--[[ + Copyright (c) The OpenRA Developers and Contributors + This file is part of OpenRA, which is free software. It is made + available to you under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. For more + information, see COPYING. +]] + +GDInuke1 = { type = "nuk2", pos = CPos.New(6,3), blocked = false } +GDIproc1 = { type = "proc", pos = CPos.New(8,12), blocked = false } +GDIpyle = { type = "pyle", pos = CPos.New(17,4), blocked = false } +GDIweap = { type = "weap", pos = CPos.New(10,9), blocked = false } +GDIproc2 = { type = "proc", pos = CPos.New(12,3), blocked = false } +GDInuke2 = { type = "nuk2", pos = CPos.New(4,11), blocked = false } +GDInuke3 = { type = "nuk2", pos = CPos.New(3,14), blocked = false } +GDIdef1 = { type = "atwr", pos = CPos.New(8,5), blocked = false } +GDIdef2 = { type = "atwr", pos = CPos.New(6,10), blocked = false } +GDIdef3 = { type = "atwr", pos = CPos.New(6,16), blocked = false } +GDIdef4 = { type = "gtwr", pos = CPos.New(9,8), blocked = false } +GDInuke4 = { type = "nuk2", pos = CPos.New(13,12), blocked = false } +GDIdef5 = { type = "atwr", pos = CPos.New(15,10), blocked = false } +GDIdef6 = { type = "atwr", pos = CPos.New(13,16), blocked = false } +GDInuke5 = { type = "nuk2", pos = CPos.New(11,14), blocked = false } +GDIsilo1 = { type = "silo", pos = CPos.New(3,6), blocked = false } +GDIsilo2 = { type = "silo", pos = CPos.New(5,17), blocked = false } +GDIdef7 = { type = "atwr", pos = CPos.New(19,5), blocked = false } +GDIdef8 = { type = "atwr", pos = CPos.New(10,21), blocked = false } +GDIsilo3 = { type = "silo", pos = CPos.New(17,2), blocked = false } +GDIsilo4 = { type = "silo", pos = CPos.New(9,17), blocked = false } +GDIdef9 = { type = "atwr", pos = CPos.New(18,20), blocked = false } +GDIhpad1 = { type = "hpad", pos = CPos.New(3,18), blocked = false } + +GDIBase = { GDINuke1, GDIPyle, GDIWeap, GDINuke2, GDINuke3, GDIDef1, GDIDef2, GDIDef3, GDIDef4, + GDINuke4, GDIDef5, GDIDef6, GDINuke5, GDISilo1, GDISilo2, GDIDef7, GDIDef8, GDISilo3, GDISilo4, GDIDef9 } +GDIRebuildList = { GDInuke1, GDIproc1, GDIpyle, GDIweap, GDIproc2, GDInuke2, GDInuke3, GDIdef1, GDIdef2, GDIdef3, GDIdef4, + GDInuke4, GDIdef5, GDIdef6, GDInuke5, GDIsilo1, GDIsilo2, GDIdef7, GDIdef8, GDIsilo3, GDIsilo4, GDIdef9 } +BSizes = { nuk2 = CVec.New(2,3), proc = CVec.New(3,4), pyle = CVec.New(2,3), weap = CVec.New(3,3), atwr = CVec.New(1,1), gtwr = CVec.New(1,1), silo = CVec.New(2,1), hpad = CVec.New(2,2) } + +ProductionBuildings = { infantry = GDIPyle, vehicle = GDIWeap, aircraft = GDICYard } + +ProductionQueue = { infantry = { }, vehicle = { }, aircraft = { } } +NewTeam = { } +TeamJob = "attack" +AT1 = { "e2", "e2", "e2", "e3", "e3", "vehicle", "jeep", "jeep", "apc" } +AT2 = { "e2", "e2", "e2", "e3", "e3", "e1", "e1", "e1", "e1" } +AT3 = { "vehicle", "mtnk", "mtnk", "jeep", "jeep" } +AT4 = { "e3", "e3", "e1", "e1", "e1", "vehicle", "mtnk", "mtnk", "msam" } +AT5 = { "vehicle", "jeep", "jeep", "jeep", "apc", "apc" } +AT6 = { "e3", "e3", "e1", "e1", "e1", "vehicle", "htnk" } +AT7 = { "vehicle", "htnk", "htnk", "mtnk" } +AT8 = { "vehicle", "htnk", "htnk", "msam" } +AT9 = { "vehicle", "mtnk", "msam", "apc", "apc" } +AT10 = { "e2", "e2", "e2", "e2", "e2", "e2", "e2", "e2", "e2", "e2" } +OT1 = { "aircraft", "orca", "orca" } +OT2 = { "aircraft", "orca", "orca", "orca", "orca" } +AttackTeams = { AT1, AT2, AT3, AT4, AT5, AT6, AT7, AT8, AT9, AT10 } + +PT1 = { "vehicle", "htnk" } +PT2 = { "vehicle", "mtnk", "mtnk" } +PT3 = { "e2", "e2", "e2", "e3", "e3" } +PatrolTeams = { PT1, PT2, PT3 } + +DT1 = { "vehicle", "mtnk", "mtnk", "msam", "msam" } +DT2 = { "e3", "e3", "e1", "e1", "e1", "vehicle", "mtnk", "mtnk", "msam" } +DT3 = { "vehicle", "htnk", "htnk", "msam" } +DefenseTeams = { DT1, DT2, DT3 } + +AddOrcasTo = { AT1, AT2, AT5, AT6, AT9, DT1, DT2, DT3 } + +AP1 = { waypoint5.Location, waypoint9.Location, waypoint8.Location, waypoint13.Location } +AP2 = { waypoint2.Location, waypoint5.Location, waypoint4.Location, waypoint6.Location } +AP3 = { waypoint2.Location, waypoint3.Location, waypoint4.Location, waypoint6.Location } +AP4 = { waypoint5.Location, waypoint9.Location, waypoint14.Location, PlayerStart.Location, waypoint13.Location } +AP5 = { waypoint5.Location, waypoint9.Location, waypoint6.Location } +AttackPaths = { AP1, AP2, AP3, AP4, AP5 } + +InitAi = function() + + if Difficulty == "hard" then + PBDelay = 115 + PUDelay = 30 + ICDelay = 800 + ProdCDSecs = 30 + GDI.Resources = 10000 + MinHarvs = 3 + ProcUpgrade = "AIHProcUpgrade" + CivsBuildingsToDestroy = 8 + end + + if Difficulty == "normal" then + PBDelay = 140 + PUDelay = 50 + ICDelay = 1000 + ProdCDSecs = 40 + GDI.Resources = 7000 + MinHarvs = 2 + ProcUpgrade = "AINProcUpgrade" + CivsBuildingsToDestroy = 11 + end + + if Difficulty == "easy" then + PBDelay = 180 + PUDelay = 70 + ICDelay = 1200 + ProdCDSecs = 50 + GDI.Resources = 5000 + MinHarvs = 2 + Nod.Resources = 3000 + CivsBuildingsToDestroy = 13 + end + + RepairNamedActors(GDI, 0.75) + SetAutoRebuild() + + Trigger.OnKilled(GDIPyle, function() + ProductionQueue["infantry"] = { } + end) + Trigger.OnKilled(GDIWeap, function() + ProductionQueue["vehicle"] = { } + end) + + if ProcUpgrade then + ProcUpg = Actor.Create(ProcUpgrade, true, { Owner = GDI }) + end + + Trigger.AfterDelay(DateTime.Seconds(PBDelay), function() + + CheckBase() + + Trigger.AfterDelay(DateTime.Seconds(PUDelay), function() + ProduceUnits() + ReduceProdCD() + end) + + Trigger.AfterDelay(DateTime.Seconds(ICDelay), function() + FireIonCannon(270) + end) + + if not GDIAdvComCenter.IsDead then + IonCannonOnline = true + Media.DisplayMessage(UserInterface.Translate("destroy-ion-cannon-advise")) + DestroyIonCannon = AddSecondaryObjective(Nod, "quickly-destroy-ion-cannon") + end + end) + +end + +ReduceProdCD = function() + Trigger.AfterDelay(DateTime.Minutes(2), function() + ProdCDSecs = ProdCDSecs - 1 + if ProdCDSecs > 10 then + ReduceProdCD() + end + end) +end + +PrepareOrcas = function() + table.insert(GDIRebuildList, 11, GDIhpad1) + Utils.Do(AddOrcasTo, function(t) + Utils.Do(OT1, function(u) + table.insert(t, u) + end) + end) + table.insert(AttackTeams, OT2) + table.insert(PatrolTeams, OT1) +end + +--Building logic +SetAutoRebuild = function() + Utils.Do(GDIBase, function(b) + Trigger.OnKilled(b, CheckBase) + end) +end + +CheckBase = function() + if GDICYard.IsDead then return end + for i = 1, #GDIRebuildList do + if GDIRebuildList[i].blocked then + CheckBuildablePlace(GDIRebuildList[i]) + else + local building = GDI.GetActorsByType(GDIRebuildList[i].type) + if #building < 1 then + BuildBuilding(GDIRebuildList[i], GDICYard) + return + end + for ii = 1, #building do + if not building[ii].IsDead and building[ii].Location == GDIRebuildList[i].pos then + break + end + if ii == #building then + BuildBuilding(GDIRebuildList[i], GDICYard) + return + end + end + end + end + if not CheckProgrammed then + CheckProgrammed = true + Trigger.AfterDelay(250, function() + CheckProgrammed = false + CheckBase() + end) + end +end + +CheckBuildablePlace = function(b) + local actors = Map.ActorsInBox(WPos.New(b.pos.X * 1024, b.pos.Y * 1024, 0), WPos.New((b.pos.X + BSizes[b.type].X) * 1024, (b.pos.Y + BSizes[b.type].Y) * 1024, 0), function(a) return a.Owner == Nod end) + if #actors > 0 then + b.blocked = true + return false + else + b.blocked = false + return true + end +end + +BuildBuilding = function(building, cyard) + if CyardIsBuilding or GDI.Resources < Actor.Cost(building.type) then + if Dontspam == true then + return + end + Dontspam = true + Trigger.AfterDelay(DateTime.Seconds(10), function() + Dontspam = false + CheckBase() + end) + return + end + + CyardIsBuilding = true + + GDI.Resources = GDI.Resources - Actor.Cost(building.type) + Trigger.AfterDelay(Actor.BuildTime(building.type), function() + CyardIsBuilding = false + + if cyard.IsDead or cyard.Owner ~= GDI then + GDI.Resources = GDI.Resources + Actor.Cost(building.type) + return + end + + if CheckBuildablePlace(building) == false then + CheckBase() + return + end + + local newbuilding = Actor.Create(building.type, true, { Owner = GDI, Location = building.pos }) + Trigger.OnKilled(newbuilding, function() CheckBase() end) + RepairBuilding(GDI, newbuilding, 0.75) + GuardBuilding(newbuilding) + + if newbuilding.Type == "pyle" then + ProductionBuildings["infantry"] = newbuilding + Trigger.OnKilled(newbuilding, function() ProductionQueue["infantry"] = { } end) + RestartUnitProduction() + elseif newbuilding.Type == "weap" then + ProductionBuildings["vehicle"] = newbuilding + Trigger.OnKilled(newbuilding, function() ProductionQueue["vehicle"] = { } end) + RestartUnitProduction() + NeedHarv = false + elseif newbuilding.Type == "hpad" then + ProductionBuildings["aircraft"] = newbuilding + Trigger.OnKilled(newbuilding, function() ProductionQueue["aircraft"] = { } end) + RestartUnitProduction() + end + + Trigger.AfterDelay(50, CheckBase) + end) + +end + +--Units production logic +UniqueTeamsQueue = { } +ProdCooldown = false +CheckProduction = function() + if #GDI.GetActorsByType("proc") < 1 and GDI.Resources < 6000 then + Trigger.AfterDelay(250, CheckProduction) + return + elseif ProductionBuildings["infantry"].IsDead and ProductionBuildings["vehicle"].IsDead and ProductionBuildings["aircraft"].IsDead then + return + elseif not ProductionBuildings["vehicle"].IsDead and CheckForHarvester() then + NeedHarv = true + ProductionBuildings["vehicle"].Build( { "harv" }, function() + CheckProduction() + Trigger.AfterDelay(DateTime.Seconds(5), function() + if not ProductionBuildings["vehicle"].IsDead then + ProductionBuildings["vehicle"].Build( { "harv" } ) + end + end) + end) + return + end + NeedHarv = false + + if #ProductionQueue["infantry"] + #ProductionQueue["vehicle"] + #ProductionQueue["aircraft"] < 1 and Producing then + Producing = false + end + if ProdCooldown or GDI.Resources < 4000 then + RestartUnitProduction() + else + ProduceUnits() + end + +end + +ProduceUnits = function() + if NeedHarv then + RestartUnitProduction() + return + end + if not Producing then + NewTeam = { } + CreateUnitsGroup() + if #ProductionQueue["infantry"] + #ProductionQueue["vehicle"] + #ProductionQueue["aircraft"] > 0 then + Producing = true + else + RestartUnitProduction() + return + end + end + + if #ProductionQueue["infantry"] > 0 and not ProductionBuildings["infantry"].IsDead and not ProductionBuildings["infantry"].IsProducing("e2") then + ProductionBuildings["infantry"].Build( { ProductionQueue["infantry"][1] }, function(u) + table.insert(NewTeam, u[1]) + table.remove(ProductionQueue["infantry"], 1) + CheckTeamCompleted() + end) + end + if #ProductionQueue["vehicle"] > 0 and not ProductionBuildings["vehicle"].IsDead and not ProductionBuildings["vehicle"].IsProducing("mtnk") then + ProductionBuildings["vehicle"].Build( { ProductionQueue["vehicle"][1] }, function(u) + table.insert(NewTeam, u[1]) + table.remove(ProductionQueue["vehicle"], 1) + CheckTeamCompleted() + end) + end + if #ProductionQueue["aircraft"] > 0 and not ProductionBuildings["aircraft"].IsDead and not ProductionBuildings["aircraft"].IsProducing("orca") then + ProductionBuildings["aircraft"].Build( { ProductionQueue["aircraft"][1] }, function(u) + table.insert(NewTeam, u[1]) + table.remove(ProductionQueue["aircraft"], 1) + CheckTeamCompleted() + end) + end + + RestartUnitProduction() + +end + +CheckTeamCompleted = function() + if #ProductionQueue["infantry"] + #ProductionQueue["vehicle"] + #ProductionQueue["aircraft"] < 1 and #NewTeam > 0 then + NewTeam = Utils.Where(NewTeam, function(u) return not u.IsDead end) + if TeamJob == "attack" then + SendAttackGroup(NewTeam) + elseif TeamJob == "patrol" then + TeamJob = "attack" + PatrolTeam = NewTeam + StartPatrol() + elseif TeamJob == "defend" then + TeamJob = "attack" + BaseDefenseTeam = NewTeam + StartGuard() + end + Producing = false + ProdCooldown = true + NewTeam = { } + Trigger.AfterDelay(DateTime.Seconds(ProdCDSecs), function() ProdCooldown = false end) + else + ProduceUnits() + end +end + +SendAttackGroup = function(team) + MoveAsGroup(team, Utils.Random(AttackPaths), 1, false) +end + +CreateUnitsGroup = function() + local team = AttackTeams + if #UniqueTeamsQueue > 0 then + team = UniqueTeamsQueue[1].team + TeamJob = UniqueTeamsQueue[1].job + table.remove(UniqueTeamsQueue, 1) + end + local pb = "infantry" + Utils.Do(Utils.Random(team), function(u) + if u == "vehicle" or u == "aircraft" then + pb = u + elseif ProductionBuildings[pb] and not ProductionBuildings[pb].IsDead and ProductionBuildings[pb].Owner == GDI then + table.insert(ProductionQueue[pb], u) + end + end) +end + +RestartUnitProduction = function() + if not Restarting then + Restarting = true + else + return + end + Trigger.AfterDelay(DateTime.Seconds(5), function() + Restarting = false + CheckProduction() + end) +end + +CheckForHarvester = function() + local harv = GDI.GetActorsByType("harv") + return #harv < MinHarvs +end diff --git a/mods/cnc/maps/eviction-notice/eviction-notice.lua b/mods/cnc/maps/eviction-notice/eviction-notice.lua new file mode 100644 index 0000000000..01d0c8edb3 --- /dev/null +++ b/mods/cnc/maps/eviction-notice/eviction-notice.lua @@ -0,0 +1,349 @@ +--[[ + 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. +]] + +WelcomeTeam = { Wel1, Wel2, Wel3, Wel4, Wel5 } + +Civilians = { Actor111, Actor112, Actor113, Actor114, Actor115, Actor116, Actor117, Actor118, Actor119, Actor120, Actor121 } +RunForHelpCivs = { Actor109, Actor110 } +CiviliansBuildings = { Actor35, Actor36, Actor37, Actor38, Actor39, Actor40, Actor41, Actor42, Actor43, Actor44, Actor45, Actor54, Actor55, Actor56, Actor57, Actor58 } +OilDerricks = { Actor49, Actor50, Actor51, Actor52 } +CivsMoneyBuildings = { Actor37, Actor41, Actor42, Actor44, Actor58 } + +ReinforcementsMammoths = { "htnk", "htnk" } +ReinforcementsEngineers = { "e6", "e6", "e6", "e6", "e6" } +CiviliansHelpTeam = { "mtnk", "mtnk", "msam" } +BaseDefenseTeam = { Def1, Def2, Def3, Def4 } +PatrolTeam = { Actor103, Actor122, Actor123 } +PatrolPath = { waypoint2.Location, waypoint3.Location, waypoint4.Location, waypoint5.Location } + +CapturableStructures = { "afld", "hand", "hq", "nuke", "silo", "proc", "sam" } +IonCannonTargets = { { "obli", "gun", "gtwr" }, { "harv" } } + +WelcomeTeamCellTrigger = { CPos.New(17,59), CPos.New(18,59), CPos.New(19,59), CPos.New(17,60), CPos.New(18,60), CPos.New(19,60), CPos.New(25,53), CPos.New(25,54), CPos.New(25,55), CPos.New(26,53), CPos.New(26,54), CPos.New(26,55) } +CivsGDIHelpCellTrigger = { CPos.New(13,7) } +GDIBaseEntranceCells = { CPos.New(16,5), CPos.New(16,6), CPos.New(16,7), CPos.New(16,8), CPos.New(17,4), CPos.New(17,5), CPos.New(17,6), CPos.New(17,7), CPos.New(17,8), CPos.New(18,4), CPos.New(18,5), CPos.New(19,4), CPos.New(8,15), CPos.New(9,15), CPos.New(10,15), CPos.New(11,15), CPos.New(12,15), CPos.New(13,15), CPos.New(14,15), CPos.New(9,16), CPos.New(10,16), CPos.New(11,16), CPos.New(12,16), CPos.New(13,16), CPos.New(14,16) } +InnerGDIBaseEntranceCells = { CPos.New(7,5), CPos.New(7,6), CPos.New(7,7), CPos.New(8,6), CPos.New(8,7), CPos.New(9,6), CPos.New(9,7) } + +CaptureStructures = function(actor) + local structures = Nod.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 + +SendGDIAirstrike = function() + if not GDIhq.IsDead and GDIhq.Owner == GDI then + local target = GetAirstrikeTarget(Nod) + if target then + GDIhq.TargetAirstrike(target, Angle.SouthEast) + else + Trigger.AfterDelay(DateTime.Seconds(5), SendGDIAirstrike) + end + end +end + +OilDerricksAstkSent = false +OilDerricksAirstrike = function() + if not OilDerricksAstkSent then + SendGDIAirstrike() + OilDerricksAstkSent = true + end +end + +CivsRunning = false +RunForHelp = function() + if not CivsRunning then + Utils.Do(RunForHelpCivs, function(actor) + actor.Move(CPos.New(53,45)) + actor.Move(waypoint6.Location) + actor.Move(waypoint4.Location) + actor.Move(waypoint9.Location) + actor.Move(waypoint2.Location) + actor.Move(waypoint12.Location) + actor.Move(waypoint6.Location) + end) + Trigger.OnEnteredFootprint(CivsGDIHelpCellTrigger, function(a, id) + if a == RunForHelpCivs[1] or a == RunForHelpCivs[2] then + Reinforcements.Reinforce(GDI, CiviliansHelpTeam, { CPos.New(2,9), CPos.New(3,9) }, 30, function(a) + a.AttackMove(waypoint2.Location) + a.AttackMove(waypoint9.Location) + a.AttackMove(waypoint8.Location) + IdleHunt(a) + end) + Trigger.RemoveFootprintTrigger(id) + end + end) + CivsRunning = true + local cam = Actor.Create("camera", true, { Owner = Nod, Location = CPos.New(53,44) }) + Trigger.AfterDelay(125, cam.Destroy) + Media.DisplayMessage(UserInterface.Translate("civilians-runs"), UserInterface.Translate("nod-soldier")) + end +end + +CivsBuildingsToDestroy = 0 +CheckVillageDestruction = function() + CivsBuildingsToDestroy = CivsBuildingsToDestroy - 1 + if CivsBuildingsToDestroy == 2 then + Media.DisplayMessage(UserInterface.Translate("village-destruction-warning")) + elseif CivsBuildingsToDestroy == 0 then + Reinforcements.Reinforce(GDI, ReinforcementsMammoths, { CPos.New(2,9), CPos.New(3,9) }, 40, function(a) + a.AttackMove(waypoint11.Location) + a.AttackMove(waypoint5.Location) + a.AttackMove(waypoint4.Location) + a.AttackMove(waypoint6.Location) + IdleHunt(a) + end) + end +end + +GuardBase = function() + Utils.Do(GDIBase, function(building) + GuardBuilding(building) + end) +end + +GuardBuilding = function(building) + Trigger.OnDamaged(building, function(slf, atk, dmg) + if atk.Type ~= "player" and not atk.IsDead and atk.Owner == Nod 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(waypoint12.Location, 3) + guard.Stance = "Defend" + Trigger.ClearAll(guard) + end) + end + end + end) + end + end) +end + +StartGuard = function() + Trigger.OnAllKilled(BaseDefenseTeam, function() + table.insert(UniqueTeamsQueue, { team = DefenseTeams, job = "defend" }) + end) + Utils.Do(BaseDefenseTeam, function(guard) + guard.Stance = "Defend" + end) +end + +StartPatrol = function() + Trigger.OnAllKilled(PatrolTeam, function() + table.insert(UniqueTeamsQueue, { team = PatrolTeams, job = "patrol" }) + end) + Utils.Do(PatrolTeam, function(a) + 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 + +MoveAsGroup = function(team, path, i, loop) + if i == 1 and not loop then + Utils.Do(team, function(u) + Trigger.OnDamaged(u, function() + Utils.Do(team, function(u) + if not u.IsDead then + Trigger.Clear(u, "OnDamaged") + IdleHunt(u) + end + end) + end) + end) + end + Utils.Do(team, function(a) + if not a.IsDead then + a.Stance = "AttackAnything" + a.AttackMove(path[i], 2) + Trigger.OnIdle(a, function() + Trigger.Clear(a, "OnIdle") + a.Stance = "Defend" + local teamNumber = 0 + local regrouped = false + Utils.Do(team, function(a) + if a.IsDead or a.Stance == "Defend" then + teamNumber = teamNumber + 1 + if teamNumber == #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 + +IonCannonOnline = false +ICShotsCount = 0 +FireIonCannon = function(timer) + if IonCannonOnline then + local ii = Utils.RandomInteger(1, 4) + local targets = { } + if ii < 3 then + targets = Nod.GetActorsByTypes(IonCannonTargets[ii]) + else + targets = Nod.GetGroundAttackers() + end + if #targets > 0 then + local rand = Utils.RandomInteger(1, #targets + 1) + if not targets[rand].IsDead then + GDIAdvComCenter.ActivateIonCannon(targets[rand].Location) + if ICShotsCount < 2 then + ICShotsCount = ICShotsCount + 1 + if ICShotsCount > 1 then + Nod.MarkFailedObjective(DestroyIonCannon) + Trigger.ClearAll(GDIAdvComCenter) + end + end + Trigger.AfterDelay(DateTime.Seconds(timer), function() FireIonCannon(timer) end) + return + end + end + Trigger.AfterDelay(DateTime.Seconds(1), function() FireIonCannon(timer) end) + end +end + +CheckObjectives = function() + if GDI.HasNoRequiredUnits() then Nod.MarkCompletedObjective(EliminateAllGDI) end + if Nod.HasNoRequiredUnits() then Nod.MarkFailedObjective(EliminateAllGDI) end + Trigger.AfterDelay(25, CheckObjectives) +end + +WorldLoaded = function() + Nod = Player.GetPlayer("Nod") + GDI = Player.GetPlayer("GDI") + Camera.Position = PlayerStart.CenterPosition + Flare = Actor.Create("flare", true, { Owner = Nod, Location = DefaultFlareLocation.Location }) + Trigger.AfterDelay(DateTime.Minutes(1), Flare.Destroy) + InitObjectives(Nod) + EliminateAllGDI = AddPrimaryObjective(Nod, "eliminate-gdi-forces") + FindAllCivMoney = AddSecondaryObjective(Nod, "take-civilians-money-crates") + CheckObjectives() + InitAi() + + Trigger.OnEnteredFootprint(WelcomeTeamCellTrigger, function(a, id) + if a.Owner == Nod then + Utils.Do(WelcomeTeam, function(a) + if not a.IsDead then + a.AttackMove(PlayerStart.Location) + IdleHunt(a) + end + end) + Trigger.RemoveFootprintTrigger(id) + end + end) + + Trigger.OnAllKilled(Civilians, function() + local cargo = Reinforcements.ReinforceWithTransport(GDI, "tran", ReinforcementsEngineers, { CPos.New(0,32), waypoint10.Location }, { CPos.New(0,32) })[2] + Utils.Do(cargo, function(engs) + if engs.Type == "e6" then + Trigger.OnIdle(engs, CaptureStructures) + end + end) + end) + + Utils.Do(CiviliansBuildings, function(b) + Trigger.OnKilled(b, CheckVillageDestruction) + end) + + Utils.Do(OilDerricks, function(actor) + Trigger.OnKilledOrCaptured(actor, OilDerricksAirstrike) + end) + + Utils.Do(RunForHelpCivs, function(actor) + Trigger.OnDiscovered(actor, RunForHelp) + end) + + Trigger.OnEnteredFootprint(GDIBaseEntranceCells, function(a, id) + if a.Owner == Nod and not BombTriggered then + BombTriggered = true + Trigger.AfterDelay(25, SendGDIAirstrike) + Trigger.AfterDelay(150, SendGDIAirstrike) + Trigger.AfterDelay(275, SendGDIAirstrike) + Trigger.RemoveFootprintTrigger(id) + end + end) + + Trigger.OnCapture(GDIhq, function() + GDIhq.GrantCondition("captured") + end) + + Trigger.OnEnteredFootprint(InnerGDIBaseEntranceCells, function(a, id) + if a.Owner == Nod and not InnerBaseEntered then + InnerBaseEntered = true + Reinforcements.Reinforce(GDI, ReinforcementsMammoths, { CPos.New(2,9), CPos.New(3,9) }, 40, IdleHunt) + Trigger.RemoveFootprintTrigger(id) + end + end) + + Trigger.AfterDelay(5, function() + StartPatrol() + GuardBase() + StartGuard() + end) + + Trigger.OnAllKilled(CivsMoneyBuildings, function() + Trigger.AfterDelay(1, function() + Trigger.OnAllRemovedFromWorld(Utils.Where(Map.ActorsInWorld, function(a) return a.Type == "moneycrate" or a.Type == "smallmcrate" end), function() + Nod.MarkCompletedObjective(FindAllCivMoney) + end) + end) + end) + + Trigger.OnKilledOrCaptured(GDIAdvComCenter, function() + if IonCannonOnline then + IonCannonOnline = false + else + DestroyIonCannon = AddSecondaryObjective(Nod, "quickly-destroy-ion-cannon") + end + Nod.MarkCompletedObjective(DestroyIonCannon) + PrepareOrcas() + end) +end diff --git a/mods/cnc/maps/eviction-notice/map.bin b/mods/cnc/maps/eviction-notice/map.bin new file mode 100644 index 0000000000..c9a6ba7619 Binary files /dev/null and b/mods/cnc/maps/eviction-notice/map.bin differ diff --git a/mods/cnc/maps/eviction-notice/map.png b/mods/cnc/maps/eviction-notice/map.png new file mode 100644 index 0000000000..d8fb00c429 Binary files /dev/null and b/mods/cnc/maps/eviction-notice/map.png differ diff --git a/mods/cnc/maps/eviction-notice/map.yaml b/mods/cnc/maps/eviction-notice/map.yaml new file mode 100644 index 0000000000..664e7b544f --- /dev/null +++ b/mods/cnc/maps/eviction-notice/map.yaml @@ -0,0 +1,649 @@ +MapFormat: 12 + +RequiresMod: cnc + +Title: Nod - Eviction Notice + +Author: Westwood Studios + +Tileset: DESERT + +MapSize: 64,64 + +Bounds: 2,2,60,60 + +Visibility: MissionSelector + +Categories: Campaign + +Players: + PlayerReference@Neutral: + Name: Neutral + OwnsWorld: True + NonCombatant: True + Faction: gdi + PlayerReference@Civilians: + Name: Civilians + Bot: campaign + NonCombatant: True + Faction: gdi + Enemies: Nod + PlayerReference@Creeps: + Name: Creeps + NonCombatant: True + Faction: Random + PlayerReference@GDI: + Name: GDI + Bot: campaign + Faction: gdi + Color: F5D378 + Allies: GDI + Enemies: Nod + PlayerReference@Nod: + Name: Nod + AllowBots: False + Playable: True + Required: True + LockFaction: True + Faction: nod + LockColor: True + Color: FE1100 + LockSpawn: True + LockTeam: True + Enemies: GDI, Civilians + +Actors: + Actor3: t09 + Location: 42,36 + Owner: Neutral + Actor4: t09 + Location: 38,30 + Owner: Neutral + Actor5: t18 + Location: 40,31 + Owner: Neutral + Actor6: rock4 + Location: 40,20 + Owner: Neutral + Actor7: rock3 + Location: 45,21 + Owner: Neutral + Actor8: rock6 + Location: 25,23 + Owner: Neutral + Actor9: t04 + Location: 55,1 + Owner: Neutral + Actor10: t08 + Location: 21,57 + Owner: Neutral + Actor11: t13.transformable + Location: 5,57 + Owner: Neutral + Actor12: t13.transformable + Location: 9,53 + Owner: Neutral + Actor13: t13.transformable + Location: 6,35 + Owner: Neutral + Actor14: t13.transformable + Location: 4,42 + Owner: Neutral + Actor15: t13.transformable + Location: 58,17 + Owner: Neutral + Actor16: t13.transformable + Location: 57,26 + Owner: Neutral + Actor17: t13.transformable + Location: 13,19 + Owner: Neutral + Actor18: t13.transformable + Location: 40,12 + Owner: Neutral + Actor19: t13.transformable + Location: 27,15 + Owner: Neutral + Actor20: t13.transformable + Location: 27,3 + Owner: Neutral + Actor21: t13.transformable + Location: 35,16 + Owner: Neutral + Actor22: t13.transformable + Location: 34,11 + Owner: Neutral + Actor23: t13.transformable + Location: 12,24 + Owner: Neutral + Actor24: rock6 + Location: 28,42 + Owner: Neutral + Actor25: rock7 + Location: 34,44 + Owner: Neutral + Actor26: rock4 + Location: 38,47 + Owner: Neutral + Actor27: rock4 + Location: 25,39 + Owner: Neutral + Actor28: t13.transformable + Location: 32,43 + Owner: Neutral + Actor29: t13.transformable + Location: 51,5 + Owner: Neutral + Actor30: t13.transformable + Location: 57,3 + Owner: Neutral + Actor31: t13.transformable + Location: 56,9 + Owner: Neutral + Actor32: t13.transformable + Location: 26,42 + Owner: Neutral + Actor33: t13.transformable + Location: 35,40 + Owner: Neutral + Actor34: t13.transformable + Location: 29,45 + Owner: Neutral + Actor35: v23 + Location: 52,52 + Owner: Civilians + Actor36: v22 + Location: 55,43 + Owner: Civilians + Actor37: v24 + Location: 58,55 + Owner: Civilians + Actor38: v31 + Location: 44,57 + Owner: Civilians + Actor39: v30 + Location: 54,47 + Owner: Civilians + Actor40: v27 + Location: 50,58 + Owner: Civilians + Actor41: v25 + Location: 50,53 + Owner: Civilians + Actor42: v26 + Location: 47,49 + Owner: Civilians + Actor43: v22 + Location: 51,50 + Owner: Civilians + Actor44: v21 + Location: 47,55 + Owner: Civilians + Actor45: v20 + Location: 52,55 + Owner: Civilians + GDICYard: fact + Location: 3,3 + Owner: GDI + GDIAdvComCenter: eye + Location: 3,18 + Owner: GDI + Actor49: v19 + Location: 60,41 + Owner: Civilians + Actor50: v19 + Location: 59,41 + Owner: Civilians + Actor51: v19 + Location: 59,42 + Owner: Civilians + Actor52: v19 + Location: 60,42 + Owner: Civilians + Actor54: v29 + Location: 60,44 + Owner: Civilians + Actor55: v28 + Location: 58,46 + Owner: Civilians + Actor56: v23 + Location: 52,44 + Owner: Civilians + Actor57: v29 + Location: 52,59 + Owner: Civilians + Actor58: v21 + Location: 42,30 + Owner: Civilians + GDIhq: hq + Location: 15,3 + Owner: GDI + GDIDef13: gtwr + Location: 20,6 + Owner: GDI + GDIDef10: gtwr + Location: 17,9 + Owner: GDI + GDIDef11: gtwr + Location: 15,23 + Owner: GDI + GDIDef12: gtwr + Location: 12,23 + Owner: GDI + GDINuke1: nuk2 + Location: 6,3 + Owner: GDI + GDIPyle: pyle + Location: 17,4 + Owner: GDI + GDISilo1: silo + Location: 3,6 + Owner: GDI + GDISilo3: silo + Location: 17,2 + Owner: GDI + GDINuke2: nuk2 + Location: 4,11 + Owner: GDI + GDIWeap: weap + Location: 10,9 + Owner: GDI + GDINuke3: nuk2 + Location: 3,14 + Owner: GDI + GDIDef7: atwr + Location: 19,5 + Owner: GDI + GDIDef5: atwr + Location: 15,10 + Owner: GDI + GDIDef6: atwr + Location: 13,16 + Owner: GDI + GDISilo2: silo + Location: 5,17 + Owner: GDI + GDISilo4: silo + Location: 9,17 + Owner: GDI + GDIDef1: atwr + Location: 8,5 + Owner: GDI + GDIDef2: atwr + Location: 6,10 + Owner: GDI + GDIDef3: atwr + Location: 6,16 + Owner: GDI + GDIDef4: gtwr + Location: 9,8 + Owner: GDI + GDIDef8: atwr + Location: 10,21 + Owner: GDI + GDIDef9: atwr + Location: 18,20 + Owner: GDI + GDINuke4: nuk2 + Location: 13,12 + Owner: GDI + GDINuke5: nuk2 + Location: 11,14 + Owner: GDI + Actor84: mcv + Location: 24,60 + Owner: Nod + Facing: 0 + Actor85: mtnk + Location: 57,20 + Owner: GDI + Facing: 384 + Actor86: mtnk + Location: 60,20 + Owner: GDI + Facing: 512 + Actor87: mtnk + Location: 13,33 + Owner: GDI + Facing: 896 + Actor88: mtnk + Location: 26,21 + Owner: GDI + Facing: 384 + Actor89: jeep + Location: 35,22 + Owner: GDI + Facing: 512 + Actor90: jeep + Location: 42,31 + Owner: GDI + Facing: 640 + Actor91: htnk + Location: 12,56 + Owner: GDI + Facing: 640 + Actor92: htnk + Location: 16,37 + Owner: GDI + Facing: 896 + Actor93: ftnk.nohusk + Location: 23,61 + Owner: Nod + Facing: 384 + Actor94: ftnk.nohusk + Owner: Nod + Location: 24,59 + Facing: 0 + Actor95: ftnk.nohusk + Location: 25,61 + Owner: Nod + Facing: 640 + Actor96: ftnk.nohusk + Location: 22,59 + Owner: Nod + Facing: 256 + Actor97: ftnk.nohusk + Location: 26,59 + Owner: Nod + Facing: 768 + Actor98: ftnk.nohusk + Location: 24,58 + Owner: Nod + Actor99: mtnk + Location: 18,52 + Owner: GDI + Facing: 640 + Actor100: htnk + Location: 20,47 + Owner: GDI + TurretFacing: 0 + Facing: 640 + Actor101: mtnk + Location: 5,49 + Owner: GDI + Facing: 640 + Actor102: jeep + Location: 26,26 + Owner: GDI + Facing: 512 + Actor103: mtnk + Location: 23,6 + Owner: GDI + Facing: 768 + Actor104: htnk + Location: 37,46 + Owner: GDI + Facing: 640 + Actor105: mtnk + Location: 19,9 + Owner: GDI + Facing: 640 + Actor106: mtnk + Location: 37,13 + Owner: GDI + Facing: 640 + Actor107: mtnk + Location: 51,12 + Owner: GDI + Facing: 384 + Actor108: mtnk + Location: 49,11 + Owner: GDI + Facing: 640 + Actor109: c8 + Location: 59,45 + Owner: Civilians + Facing: 512 + SubCell: 1 + Actor110: c5 + Location: 59,45 + Owner: Civilians + Facing: 640 + SubCell: 4 + Actor111: c7 + Location: 60,47 + Owner: Civilians + SubCell: 3 + Facing: 384 + Actor112: c7 + Location: 43,51 + Owner: Civilians + Facing: 256 + SubCell: 2 + Actor113: c4 + Location: 53,57 + Owner: Civilians + Facing: 512 + SubCell: 4 + Actor114: c3 + Location: 47,53 + Owner: Civilians + Facing: 896 + SubCell: 0 + Actor115: c3 + Location: 58,42 + Owner: Civilians + Facing: 512 + SubCell: 3 + Actor116: c2 + Location: 57,56 + Owner: Civilians + Facing: 256 + SubCell: 0 + Actor117: c2 + Location: 48,58 + Owner: Civilians + Facing: 384 + SubCell: 0 + Actor118: c2 + Location: 51,51 + Owner: Civilians + Facing: 256 + SubCell: 1 + Actor119: c1 + Location: 57,46 + Owner: Civilians + Facing: 256 + SubCell: 1 + Actor120: c1 + Location: 46,50 + Owner: Civilians + Facing: 512 + SubCell: 2 + Actor121: c1 + Location: 45,56 + Owner: Civilians + Facing: 128 + SubCell: 1 + Actor122: e2 + Location: 25,6 + Owner: GDI + Facing: 768 + SubCell: 3 + Actor123: e2 + Location: 24,7 + Owner: GDI + Facing: 640 + SubCell: 2 + Actor124: e2 + Location: 26,48 + Owner: GDI + Facing: 640 + SubCell: 1 + Actor125: e2 + Location: 25,48 + Owner: GDI + Facing: 384 + SubCell: 0 + Actor126: e2 + Location: 32,50 + Owner: GDI + SubCell: 3 + Facing: 256 + Actor127: e2 + Location: 33,52 + Owner: GDI + SubCell: 1 + Facing: 768 + Actor128: e2 + Location: 32,51 + Owner: GDI + SubCell: 3 + Facing: 512 + Actor129: e1 + Location: 19,6 + Owner: GDI + Facing: 640 + SubCell: 0 + Actor130: e1 + Location: 18,10 + Owner: GDI + Facing: 384 + SubCell: 2 + Actor131: e1 + Location: 21,7 + Owner: GDI + Facing: 768 + SubCell: 2 + Actor133: e2 + Location: 16,59 + Owner: GDI + SubCell: 1 + Facing: 896 + Actor134: e2 + Location: 15,60 + Owner: GDI + SubCell: 4 + Facing: 384 + Actor136: e2 + Location: 16,58 + Owner: GDI + SubCell: 0 + TurretFacing: 0 + Facing: 640 + Actor137: e1 + Location: 46,54 + Owner: Nod + Health: 60 + SubCell: 2 + DefaultChinookTarget: waypoint + Location: 32,32 + Owner: Neutral + DefaultCameraPosition: waypoint + Location: 17,54 + Owner: Neutral + DefaultFlareLocation: waypoint + Location: 47,54 + Owner: Neutral + waypoint13: waypoint + Owner: Neutral + Location: 29,51 + waypoint12: waypoint + Location: 13,7 + Owner: Neutral + waypoint11: waypoint + Location: 13,23 + Owner: Neutral + waypoint10: waypoint + Location: 56,56 + Owner: Neutral + waypoint9: waypoint + Location: 21,31 + Owner: Neutral + waypoint8: waypoint + Location: 22,51 + Owner: Neutral + waypoint7: waypoint + Location: 48,52 + Owner: Neutral + waypoint6: waypoint + Location: 53,37 + Owner: Neutral + waypoint5: waypoint + Location: 23,24 + Owner: Neutral + waypoint4: waypoint + Location: 46,23 + Owner: Neutral + waypoint3: waypoint + Location: 49,5 + Owner: Neutral + waypoint2: waypoint + Location: 23,7 + Owner: Neutral + waypoint1: waypoint + Location: 2,9 + Owner: Neutral + PlayerStart: waypoint + Location: 24,60 + Owner: Neutral + Wel1: apc + Owner: GDI + Location: 13,55 + Facing: 649 + Def35: e1 + Location: 15,8 + Owner: GDI + SubCell: 4 + Facing: 896 + Wel3: jeep + Owner: GDI + Location: 19,44 + Facing: 617 + Wel2: jeep + Owner: GDI + Location: 21,43 + Facing: 384 + Actor152: msam + Owner: GDI + Location: 5,18 + Facing: 657 + Actor153: msam + Owner: GDI + Location: 3,17 + Facing: 576 + Actor154: msam + Owner: GDI + Location: 15,12 + Facing: 657 + Actor155: htnk + Owner: GDI + Location: 4,23 + Facing: 527 + Actor156: htnk + Owner: GDI + Location: 3,23 + Facing: 495 + waypoint14: waypoint + Owner: Neutral + Location: 10,45 + Def1: mtnk + Owner: GDI + Location: 14,6 + Facing: 384 + Def2: mtnk + Owner: GDI + Location: 12,7 + Facing: 384 + Def3: mtnk + Owner: GDI + Location: 14,8 + Facing: 384 + Def4: msam + Owner: GDI + Location: 13,8 + Facing: 384 + Wel4: jeep + Owner: GDI + Location: 36,53 + Facing: 227 + Wel5: apc + Owner: GDI + Location: 37,51 + Facing: 349 + +Rules: cnc|rules/campaign-maprules.yaml, cnc|rules/campaign-tooltips.yaml, cnc|rules/campaign-palettes.yaml, rules.yaml + +Weapons: weapons.yaml + +Translations: cnc|languages/lua/en.ftl diff --git a/mods/cnc/maps/eviction-notice/rules.yaml b/mods/cnc/maps/eviction-notice/rules.yaml new file mode 100644 index 0000000000..b7842d3fef --- /dev/null +++ b/mods/cnc/maps/eviction-notice/rules.yaml @@ -0,0 +1,139 @@ +World: + MissionData: + StartVideo: consyard.vqa + LossVideo: bombaway.vqa + WinVideo: inferno.vqa + Briefing: GDI influence in this area is running rampant. Establish a well positioned strike base, and clean the area out. A nearby town may provide a suitable location for your base, if the occupants were "persuaded" to move.... + LuaScript: + Scripts: campaign.lua, utils.lua, eviction-notice.lua , eviction-notice-AI.lua + ScriptLobbyDropdown@difficulty: + ID: difficulty + Label: Difficulty + Description: The difficulty of the mission + Values: + easy: Easy + normal: Normal + hard: Hard + Default: normal + +Player: + EnemyWatcher: + PlayerResources: + DefaultCash: 0 + +# Disable husks for civilian buildings and initial flame tanks +V19: + -SpawnActorOnDeath: + +V20: + -SpawnActorOnDeath: + +V21: + SpawnActorOnDeath: + Actor: smallmcrate + +V22: + -SpawnActorOnDeath: + +V23: + -SpawnActorOnDeath: + +V24: + SpawnActorOnDeath: + Actor: smallmcrate + +V25: + SpawnActorOnDeath: + Actor: moneycrate + +V26: + SpawnActorOnDeath: + Actor: smallmcrate + +V27: + -SpawnActorOnDeath: + +V28: + -SpawnActorOnDeath: + +V29: + -SpawnActorOnDeath: + +V30: + -SpawnActorOnDeath: + +V31: + -SpawnActorOnDeath: + +C5: + AnnounceOnSeen: + +C8: + AnnounceOnSeen: + +MoneyCrate: + ScriptTriggers: + +SmallMCrate: + Inherits: MoneyCrate + ScriptTriggers: + GiveCashCrateAction: + Amount: 1000 + Sequence: dollar + UseCashTick: true + +# Initial flame tanks can't move due to their own husks +FTNK.nohusk: + Inherits: FTNK + -Buildable: + RenderSprites: + Image: FTNK + -SpawnActorOnDeath: + +HQ: + ExternalCondition@CAPTURED: + Condition: captured + AirstrikePower: + StartFullyCharged: True + RequiresCondition: captured + +PROC: + GrantConditionOnPrerequisite@AIN: + Condition: ain + Prerequisites: diffnorm + GrantConditionOnPrerequisite@AIH: + Condition: aih + Prerequisites: diffhard + ResourceValueMultiplier@AIN: + Modifier: 150 + RequiresCondition: ain + ResourceValueMultiplier@AIH: + Modifier: 300 + RequiresCondition: aih + +AIHProcUpgrade: + ProvidesPrerequisite: + Prerequisite: diffhard + Interactable: + AlwaysVisible: + +AINProcUpgrade: + ProvidesPrerequisite: + Prerequisite: diffnorm + Interactable: + AlwaysVisible: + +HTNK: + Buildable: + Prerequisites: ~techlevel.high + +A10: + Targetable: + +FLARE: + RevealsShroud: + Range: 5c0 + +CAMERA: + RevealsShroud: + Range: 5c0 diff --git a/mods/cnc/maps/eviction-notice/weapons.yaml b/mods/cnc/maps/eviction-notice/weapons.yaml new file mode 100644 index 0000000000..83050cfb29 --- /dev/null +++ b/mods/cnc/maps/eviction-notice/weapons.yaml @@ -0,0 +1,3 @@ +IonCannon: + Warhead@1Dam_impact: SpreadDamage + Falloff: 1000, 60, 40, 20 diff --git a/mods/cnc/missions.yaml b/mods/cnc/missions.yaml index 928782d4ca..260e373b63 100644 --- a/mods/cnc/missions.yaml +++ b/mods/cnc/missions.yaml @@ -35,6 +35,9 @@ Nod Campaign: nod10a nod10b +Covert Operations: + eviction-notice + Funpark Campaign: funpark01