1--[[ 2 Copyright 2007-2020 The OpenRA Developers (see AUTHORS) 3 This file is part of OpenRA, which is free software. It is made 4 available to you under the terms of the GNU General Public License 5 as published by the Free Software Foundation, either version 3 of 6 the License, or (at your option) any later version. For more 7 information, see COPYING. 8]] 9 10AtreidesMainBase = { AConYard1, AOutpost1, APalace, ARefinery1, ARefinery2, AHeavyFactory1, ALightFactory1, ARepair1, AStarport1, AHiTechFactory, AResearch, ARock1, ARock2, ARock3, ARock4, ARock5, ARock6, ARock7, ARock8, ARock9, ARock10, ABarracks1, ABarracks2, APower1, APower2, APower3, APower4, APower5, APower6, APower7, APower8, APower9, APower10, APower11, ASilo1, ASilo2, ASilo3 } 11AtreidesSmallBase = { AConYard2, ARefinery3, ABarracks3, AHeavyFactory2, ALightFactory2, ARepair2, AGunt1, AGunt2, ARock11, APower12, APower13, APower14, APower15, APower16, APower17, APower18, APower19, APower20 } 12CorrinoMainBase = { CConYard, COutpost, CPalace, CRefinery1, CHeavyFactory, CResearch, CGunt1, CGunt2, CGunt3, CGunt4, CGunt5, CGunt6, CRock1, CRock2, CRock3, CRock4, CBarracks1, CBarracks2, CPower1, CPower2, CPower3, CPower4, CPower5, CPower6, CPower7, CPower8 } 13CorrinoSmallBase = { CRefinery2, CLightFactory, CStarport, CGunt7, CGunt8, CBarracks3, CPower9, CPower10, CPower11, CPower12, CSilo1, CSilo2, CSilo3, CSilo4 } 14 15AtreidesReinforcements = 16{ 17 easy = 18 { 19 { "combat_tank_a", "quad", "light_inf", "light_inf" }, 20 { "fremen", "trike", "combat_tank_a"}, 21 { "combat_tank_a", "quad", "light_inf", "light_inf" }, 22 { "trooper", "trooper", "trooper" }, 23 { "light_inf", "light_inf", "sonic_tank" }, 24 { "light_inf", "light_inf", "light_inf", "quad" } 25 }, 26 27 normal = 28 { 29 { "combat_tank_a", "quad", "quad", "light_inf", "light_inf" }, 30 { "fremen", "fremen", "trike", "combat_tank_a"}, 31 { "combat_tank_a", "quad", "quad", "light_inf", "light_inf" }, 32 { "trooper", "trooper", "trooper", "trooper" }, 33 { "light_inf", "light_inf", "light_inf", "sonic_tank" }, 34 { "light_inf", "light_inf", "light_inf", "quad", "quad" }, 35 { "combat_tank_a", "combat_tank_a", "missile_tank" } 36 }, 37 38 hard = 39 { 40 { "combat_tank_a", "quad", "quad", "quad", "light_inf", "light_inf" }, 41 { "fremen", "fremen", "fremen", "trike", "combat_tank_a"}, 42 { "combat_tank_a", "quad", "quad", "quad", "light_inf", "light_inf" }, 43 { "trooper", "trooper", "trooper", "trooper", "trooper" }, 44 { "light_inf", "light_inf", "light_inf", "light_inf", "sonic_tank" }, 45 { "light_inf", "light_inf", "light_inf", "quad", "quad", "quad" }, 46 { "combat_tank_a", "combat_tank_a", "combat_tank_a", "missile_tank" }, 47 { "fremen", "fremen", "fremen", "fremen", "fremen", "fremen", "fremen", "fremen" } 48 } 49} 50 51CorrinoStarportReinforcements = 52{ 53 easy = 54 { 55 { "sardaukar", "sardaukar", "sardaukar", "sardaukar", "sardaukar", "siege_tank", "siege_tank" }, 56 { "trooper", "trooper", "combat_tank_h", "combat_tank_h" }, 57 { "trike", "trike", "trike", "trooper", "trooper", "light_inf", "light_inf" } 58 }, 59 60 normal = 61 { 62 { "sardaukar", "sardaukar", "sardaukar", "sardaukar", "sardaukar", "sardaukar", "siege_tank", "siege_tank" }, 63 { "trooper", "trooper", "trooper", "combat_tank_h", "combat_tank_h" }, 64 { "trike", "trike", "trike", "trooper", "trooper", "trooper", "light_inf", "light_inf", "light_inf" } 65 }, 66 67 hard = 68 { 69 { "sardaukar", "sardaukar", "sardaukar", "sardaukar", "sardaukar", "sardaukar", "sardaukar", "siege_tank", "siege_tank" }, 70 { "trooper", "trooper", "trooper", "trooper", "combat_tank_h", "combat_tank_h" }, 71 { "trike", "trike", "trike", "trooper", "trooper", "trooper", "trooper", "light_inf", "light_inf", "light_inf", "light_inf" } 72 } 73} 74 75AtreidesAttackDelay = 76{ 77 easy = DateTime.Minutes(3) + DateTime.Seconds(30), 78 normal = DateTime.Minutes(2) + DateTime.Seconds(30), 79 hard = DateTime.Minutes(1) + DateTime.Seconds(30) 80} 81 82CorrinoStarportDelay = 83{ 84 easy = DateTime.Minutes(10), 85 normal = DateTime.Minutes(8), 86 hard = DateTime.Minutes(6) 87} 88 89AtreidesAttackWaves = 90{ 91 easy = 6, 92 normal = 7, 93 hard = 8 94} 95 96FremenGroupSize = 97{ 98 easy = 2, 99 normal = 4, 100 hard = 6 101} 102 103InitialAtreidesReinforcements = 104{ 105 { "combat_tank_a", "combat_tank_a", "quad", "trike" }, 106 { "trooper", "trooper", "trooper", "trooper", "trooper", "combat_tank_a" }, 107 { "combat_tank_a", "combat_tank_a", "quad", "quad", "trike" } 108} 109 110InitialCorrinoReinforcements = 111{ 112 { "trooper", "trooper", "trooper", "trooper", "quad", "quad" }, 113 { "trooper", "trooper", "trooper", "trooper", "trooper", "combat_tank_h", "combat_tank_h" }, 114 { "trooper", "trooper", "trooper", "combat_tank_h", "combat_tank_h", "combat_tank_h" } 115} 116 117AtreidesPaths = 118{ 119 { AtreidesEntry1.Location, AtreidesRally1.Location }, 120 { AtreidesEntry2.Location, AtreidesRally2.Location }, 121 { AtreidesEntry3.Location, AtreidesRally3.Location }, 122 { AtreidesEntry4.Location, AtreidesRally4.Location }, 123 { AtreidesEntry5.Location, AtreidesRally5.Location } 124} 125 126InitialAtreidesPaths = 127{ 128 { AConYard1.Location, AtreidesRally6.Location }, 129 { ARefinery2.Location, AtreidesRally7.Location }, 130 { AtreidesEntry6.Location, AtreidesRally8.Location } 131} 132 133InitialCorrinoPaths = 134{ 135 { CConYard.Location, CorrinoRally1.Location }, 136 { CHeavyFactory.Location, CorrinoRally2.Location }, 137 { CRefinery2.Location, CorrinoRally3.Location } 138} 139 140HarkonnenReinforcements = { "combat_tank_h", "combat_tank_h" } 141 142HarkonnenPath = { HarkonnenEntry.Location, HarkonnenRally.Location } 143 144SendStarportReinforcements = function() 145 Trigger.AfterDelay(CorrinoStarportDelay[Difficulty], function() 146 if CStarport.IsDead or CStarport.Owner ~= corrino_small then 147 return 148 end 149 150 reinforcements = Utils.Random(CorrinoStarportReinforcements[Difficulty]) 151 152 local units = Reinforcements.ReinforceWithTransport(corrino_small, "frigate", reinforcements, { CorrinoStarportEntry.Location, CStarport.Location + CVec.New(1, 1) }, { CorrinoStarportExit.Location })[2] 153 Utils.Do(units, function(unit) 154 unit.AttackMove(AtreidesAttackLocation) 155 IdleHunt(unit) 156 end) 157 158 SendStarportReinforcements() 159 end) 160end 161 162SendHarkonnenReinforcements = function(delay) 163 Trigger.AfterDelay(delay, function() 164 Reinforcements.ReinforceWithTransport(player, "carryall.reinforce", HarkonnenReinforcements, HarkonnenPath, { HarkonnenPath[1] }) 165 Trigger.AfterDelay(DateTime.Seconds(5), function() 166 Media.PlaySpeechNotification(player, "Reinforce") 167 end) 168 end) 169end 170 171SendAirStrike = function() 172 if AHiTechFactory.IsDead or AHiTechFactory.Owner ~= atreides_main then 173 return 174 end 175 176 local targets = Utils.Where(player.GetActors(), function(actor) 177 return 178 actor.HasProperty("Sell") and 179 actor.Type ~= "wall" and 180 actor.Type ~= "medium_gun_turret" and 181 actor.Type ~= "large_gun_turret" and 182 actor.Type ~= "silo" and 183 actor.Type ~= "wind_trap" 184 end) 185 186 if #targets > 0 then 187 AHiTechFactory.SendAirstrike(Utils.Random(targets).CenterPosition, true, 0) 188 end 189 190 Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike) 191end 192 193BuildFremen = function() 194 if APalace.IsDead or APalace.Owner ~= atreides_main then 195 return 196 end 197 198 APalace.Produce("fremen") 199 APalace.Produce("fremen") 200 201 Trigger.AfterDelay(DateTime.Seconds(5), function() 202 IdleFremen = Utils.Where(atreides_main.GetActorsByType('fremen'), function(actor) return actor.IsIdle end) 203 204 if #IdleFremen >= FremenGroupSize[Difficulty] then 205 SendFremen() 206 end 207 end) 208 209 Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds (30), BuildFremen) 210end 211 212SendFremen = function() 213 Utils.Do(IdleFremen, function(freman) 214 freman.AttackMove(AtreidesAttackLocation) 215 IdleHunt(freman) 216 end) 217end 218 219ChangeOwner = function(old_owner, new_owner) 220 local units = old_owner.GetActors() 221 Utils.Do(units, function(unit) 222 if not unit.IsDead then 223 unit.Owner = new_owner 224 end 225 end) 226end 227 228CheckSmugglerEnemies = function() 229 Utils.Do(SmugglerUnits, function(unit) 230 Trigger.OnDamaged(unit, function(self, attacker) 231 if unit.Owner == smuggler_neutral and attacker.Owner == player then 232 ChangeOwner(smuggler_neutral, smuggler_harkonnen) 233 234 -- Ensure that harvesters that was on a carryall switched sides. 235 Trigger.AfterDelay(DateTime.Seconds(15), function() 236 ChangeOwner(smuggler_neutral, smuggler_harkonnen) 237 end) 238 end 239 240 if unit.Owner == smuggler_ai and attacker.Owner == player then 241 ChangeOwner(smuggler_ai, smuggler_both) 242 243 -- Ensure that harvesters that was on a carryall switched sides. 244 Trigger.AfterDelay(DateTime.Seconds(15), function() 245 ChangeOwner(smuggler_ai, smuggler_both) 246 end) 247 end 248 249 if unit.Owner == smuggler_neutral and (attacker.Owner == atreides_main or attacker.Owner == atreides_small or attacker.Owner == corrino_main or attacker.Owner == corrino_small) then 250 ChangeOwner(smuggler_neutral, smuggler_ai) 251 252 -- Ensure that harvesters that was on a carryall switched sides. 253 Trigger.AfterDelay(DateTime.Seconds(15), function() 254 ChangeOwner(smuggler_neutral, smuggler_ai) 255 end) 256 end 257 258 if unit.Owner == smuggler_harkonnen and (attacker.Owner == atreides_main or attacker.Owner == atreides_small or attacker.Owner == corrino_main or attacker.Owner == corrino_small) then 259 ChangeOwner(smuggler_harkonnen, smuggler_both) 260 261 -- Ensure that harvesters that was on a carryall switched sides. 262 Trigger.AfterDelay(DateTime.Seconds(15), function() 263 ChangeOwner(smuggler_harkonnen, smuggler_both) 264 end) 265 end 266 267 if attacker.Owner == player and not message_check then 268 269 message_check = true 270 Media.DisplayMessage("The Smugglers are now hostile!", "Mentat") 271 end 272 end) 273 end) 274end 275 276Tick = function() 277 if player.HasNoRequiredUnits() then 278 atreides_main.MarkCompletedObjective(KillHarkonnen1) 279 atreides_small.MarkCompletedObjective(KillHarkonnen2) 280 corrino_main.MarkCompletedObjective(KillHarkonnen3) 281 corrino_small.MarkCompletedObjective(KillHarkonnen4) 282 end 283 284 if atreides_main.HasNoRequiredUnits() and atreides_small.HasNoRequiredUnits() and not player.IsObjectiveCompleted(KillAtreides) then 285 Media.DisplayMessage("The Atreides have been annihilated!", "Mentat") 286 player.MarkCompletedObjective(KillAtreides) 287 end 288 289 if corrino_main.HasNoRequiredUnits() and corrino_small.HasNoRequiredUnits() and not player.IsObjectiveCompleted(KillCorrino) then 290 Media.DisplayMessage("The Emperor has been annihilated!", "Mentat") 291 player.MarkCompletedObjective(KillCorrino) 292 end 293 294 if smuggler_neutral.HasNoRequiredUnits() and smuggler_harkonnen.HasNoRequiredUnits() and smuggler_ai.HasNoRequiredUnits() and smuggler_both.HasNoRequiredUnits() and not SmugglersKilled then 295 Media.DisplayMessage("The Smugglers have been annihilated!", "Mentat") 296 SmugglersKilled = true 297 end 298 299 local playerConYards = player.GetActorsByType("construction_yard") 300 if #playerConYards > 0 and not player.IsObjectiveCompleted(DeployMCV) then 301 player.MarkCompletedObjective(DeployMCV) 302 end 303 304 if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[atreides_main] then 305 local units = atreides_main.GetActorsByType("harvester") 306 307 if #units > 0 then 308 LastHarvesterEaten[atreides_main] = false 309 ProtectHarvester(units[1], atreides_main, AttackGroupSize[Difficulty]) 310 end 311 end 312 313 if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[atreides_small] then 314 local units = atreides_small.GetActorsByType("harvester") 315 316 if #units > 0 then 317 LastHarvesterEaten[atreides_small] = false 318 ProtectHarvester(units[1], atreides_small, AttackGroupSize[Difficulty]) 319 end 320 end 321 322 if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[corrino_main] then 323 local units = corrino_main.GetActorsByType("harvester") 324 325 if #units > 0 then 326 LastHarvesterEaten[corrino_main] = false 327 ProtectHarvester(units[1], corrino_main, AttackGroupSize[Difficulty]) 328 end 329 end 330 331 if DateTime.GameTime % DateTime.Seconds(10) == 0 and LastHarvesterEaten[corrino_small] then 332 local units = corrino_small.GetActorsByType("harvester") 333 334 if #units > 0 then 335 LastHarvesterEaten[corrino_small] = false 336 ProtectHarvester(units[1], corrino_small, AttackGroupSize[Difficulty]) 337 end 338 end 339end 340 341WorldLoaded = function() 342 atreides_main = Player.GetPlayer("Atreides Main Base") 343 atreides_small = Player.GetPlayer("Atreides Small Base") 344 corrino_main = Player.GetPlayer("Corrino Main Base") 345 corrino_small = Player.GetPlayer("Corrino Small Base") 346 smuggler_neutral = Player.GetPlayer("Smugglers - Neutral") 347 smuggler_harkonnen = Player.GetPlayer("Smugglers - Enemy to Harkonnen") 348 smuggler_ai = Player.GetPlayer("Smugglers - Enemy to AI") 349 smuggler_both = Player.GetPlayer("Smugglers - Enemy to Both") 350 player = Player.GetPlayer("Harkonnen") 351 352 InitObjectives(player) 353 DeployMCV = player.AddSecondaryObjective("Build an MCV and deploy it into a Construction Yard.") 354 KillAtreides = player.AddPrimaryObjective("Destroy the Atreides.") 355 KillCorrino = player.AddPrimaryObjective("Destroy the Imperial Forces.") 356 KillHarkonnen1 = atreides_main.AddPrimaryObjective("Kill all Harkonnen units.") 357 KillHarkonnen2 = atreides_small.AddPrimaryObjective("Kill all Harkonnen units.") 358 KillHarkonnen3 = corrino_main.AddPrimaryObjective("Kill all Harkonnen units.") 359 KillHarkonnen4 = corrino_small.AddPrimaryObjective("Kill all Harkonnen units.") 360 361 -- Wait for carryall drop 362 Trigger.AfterDelay(DateTime.Seconds(10), function() 363 SmugglerUnits = smuggler_neutral.GetActors() 364 CheckSmugglerEnemies() 365 end) 366 367 Camera.Position = HBarracks.CenterPosition 368 AtreidesAttackLocation = HBarracks.Location 369 370 Trigger.AfterDelay(DateTime.Minutes(5), SendAirStrike) 371 Trigger.AfterDelay(DateTime.Minutes(1) + DateTime.Seconds (30), BuildFremen) 372 373 Trigger.OnAllKilledOrCaptured(AtreidesMainBase, function() 374 Utils.Do(atreides_main.GetGroundAttackers(), IdleHunt) 375 end) 376 377 Trigger.OnAllKilledOrCaptured(AtreidesSmallBase, function() 378 Utils.Do(atreides_small.GetGroundAttackers(), IdleHunt) 379 end) 380 381 Trigger.OnAllKilledOrCaptured(CorrinoMainBase, function() 382 Utils.Do(corrino_main.GetGroundAttackers(), IdleHunt) 383 end) 384 385 Trigger.OnAllKilledOrCaptured(CorrinoSmallBase, function() 386 Utils.Do(corrino_small.GetGroundAttackers(), IdleHunt) 387 end) 388 389 local path = function() return Utils.Random(AtreidesPaths) end 390 local waveCondition = function() return player.IsObjectiveCompleted(KillAtreides) end 391 local huntFunction = function(unit) 392 unit.AttackMove(AtreidesAttackLocation) 393 IdleHunt(unit) 394 end 395 SendCarryallReinforcements(atreides_main, 0, AtreidesAttackWaves[Difficulty], AtreidesAttackDelay[Difficulty], path, AtreidesReinforcements[Difficulty], waveCondition, huntFunction) 396 397 SendStarportReinforcements() 398 399 Actor.Create("upgrade.barracks", true, { Owner = atreides_main }) 400 Actor.Create("upgrade.light", true, { Owner = atreides_main }) 401 Actor.Create("upgrade.heavy", true, { Owner = atreides_main }) 402 Actor.Create("upgrade.hightech", true, { Owner = atreides_main }) 403 Actor.Create("upgrade.barracks", true, { Owner = atreides_small }) 404 Actor.Create("upgrade.light", true, { Owner = atreides_small }) 405 Actor.Create("upgrade.heavy", true, { Owner = atreides_small }) 406 Actor.Create("upgrade.barracks", true, { Owner = corrino_main }) 407 Actor.Create("upgrade.heavy", true, { Owner = corrino_main }) 408 Actor.Create("upgrade.barracks", true, { Owner = corrino_small }) 409 Actor.Create("upgrade.light", true, { Owner = corrino_small }) 410 Trigger.AfterDelay(0, ActivateAI) 411 412 SendHarkonnenReinforcements(DateTime.Minutes(2)) 413end 414