1--[[ 2 Task Queues! 3]]-- 4 5require "common" 6 7 8local DebugEnabled = false 9 10local function EchoDebug(inStr) 11 if DebugEnabled then 12 game:SendToConsole("Taskqueues: " .. inStr) 13 end 14end 15 16local random = math.random 17math.randomseed( os.time() + game:GetTeamID() ) 18random(); random(); random() 19 20local needAA = false 21local needShields = false 22local needAntinuke = false 23local needtorpedo = false 24local needGroundDefense = true 25 26-- do we need siege equipment such as artillery and merl? 27local needSiege = false 28 29local heavyPlasmaLimit = 3 -- changes with CheckForMapControl 30local AAUnitPerTypeLimit = 3 -- changes with CheckForMapControl 31local nukeLimit = 1 -- changes with CheckForMapControl 32local tacticalNukeLimit = 1 -- changes with CheckForMapControl 33 34local lastCheckFrame = 0 35local lastSiegeCheckFrame = 0 36 37-- build ranges to check for things 38local AreaCheckRange = 1500 39 40local tidalPower = 0 41 42local averageWind = 0 43local needWind = false 44local windRatio = 1 45 46local needAmphibiousCons = false 47 48local minDefenseNetworkSize = 100000 49 50local function MapHasWater() 51 return (ai.waterMap or ai.hasUWSpots) or false 52end 53 54local function CheckMySide(self) 55 -- fix: moved here so map object is present when it's accessed 56 ConUnitPerTypeLimit = math.max(map:SpotCount() / 6, 4) 57 ConUnitAdvPerTypeLimit = math.max(map:SpotCount() / 8, 2) 58 EchoDebug("per-type construction unit limit: " .. ConUnitPerTypeLimit) 59 minDefenseNetworkSize = ai.mobilityGridArea / 4 60 -- set the averageWind 61 if averageWind == 0 then 62 averageWind = map:AverageWind() 63 if averageWind > 11 then 64 needWind = true 65 else 66 needWind = false 67 end 68 local minWind = map:MinimumWindSpeed() 69 if minWind < 8 then 70 windRatio = minWind / 8 71 else 72 windRatio = 1 73 end 74 EchoDebug("wind/solar ratio: " .. windRatio) 75 end 76 -- set the tidal strength 77 if MapHasWater() then 78 if tidalPower == 0 then tidalPower = map:TidalStrength() end 79 else 80 tidalPower = 0 81 end 82 if ai.hasUWSpots and ai.mobRating["sub"] > ai.mobRating["bot"] * 0.75 then 83 needAmphibiousCons = true 84 end 85 if self.unit ~= nil then 86 local tmpName = self.unit:Internal():Name() 87 if tmpName == "corcom" then 88 ai.mySide = CORESideName 89 return DummyUnitName 90 end 91 if tmpName == "armcom" then 92 ai.mySide = ARMSideName 93 return DummyUnitName 94 end 95 game:SendToConsole("Unexpected start unit: "..tmpName..", cannot determine it's race. Assuming CORE") 96 ai.mySide = CORESideName 97 else 98 game:SendToConsole("Unexpected start unit: nil, cannot determine it's race. Assuming CORE") 99 ai.mySide = CORESideName 100 end 101 return DummyUnitName 102end 103 104-- this is initialized in maphandler 105local function MapHasUnderwaterMetal() 106 return ai.hasUWSpots or false 107end 108 109-- check if siege units are needed 110-- check if advanced and experimental factories are needed 111-- check if nukes are needed 112-- check if reclaiming is needed 113function CheckForMapControl() 114 local f = game:Frame() 115 if (lastSiegeCheckFrame + 240) < f then 116 ai.haveAdvFactory = false 117 if ai.factoriesAtLevel[3] ~= nil then 118 ai.haveAdvFactory = #ai.factoriesAtLevel[3] ~= 0 119 end 120 ai.haveExpFactory = false 121 if ai.factoriesAtLevel[5] ~= nil then 122 ai.haveExpFactory = #ai.factoriesAtLevel[5] ~= 0 123 end 124 125 lastSiegeCheckFrame = f 126 ai.needToReclaim = ai.Metal.full < 0.5 and ai.wreckCount > 0 127 AAUnitPerTypeLimit = math.ceil(ai.turtlehandler:GetTotalPriority() / 4) 128 heavyPlasmaLimit = math.ceil(ai.combatCount / 10) 129 nukeLimit = math.ceil(ai.combatCount / 50) 130 tacticalNukeLimit = math.ceil(ai.combatCount / 40) 131 132 local attackCounter = ai.attackhandler:GetCounter() 133 local couldAttack = ai.couldAttack >= 1 or ai.couldBomb >= 1 134 local bombingTooExpensive = ai.bomberhandler:GetCounter() == maxBomberCounter 135 local attackTooExpensive = attackCounter == maxAttackCounter 136 local controlMetalSpots = ai.mexCount > #ai.mobNetworkMetals["air"][1] * 0.4 137 local needUpgrade = couldAttack or bombingTooExpensive or attackTooExpensive 138 local lotsOfMetal = ai.Metal.income > 25 or controlMetalSpots 139 140 EchoDebug(ai.totalEnemyThreat .. " " .. ai.totalEnemyImmobileThreat .. " " .. ai.totalEnemyMobileThreat) 141 -- build siege units if the enemy is turtling, if a lot of our attackers are getting destroyed, or if we control over 40% of the metal spots 142 needSiege = (ai.totalEnemyImmobileThreat > ai.totalEnemyMobileThreat * 3.5 and ai.totalEnemyImmobileThreat > 50000) or attackCounter >= siegeAttackCounter or controlMetalSpots 143 ai.needAdvanced = (ai.Metal.income > 10 or controlMetalSpots) and ai.factories > 0 and (needUpgrade or lotsOfMetal) 144 ai.needExperimental = false 145 ai.needNukes = false 146 if ai.Metal.income > 50 and ai.haveAdvFactory and needUpgrade and ai.enemyBasePosition then 147 if not ai.haveExpFactory then 148 for i, factory in pairs(ai.factoriesAtLevel[ai.maxFactoryLevel]) do 149 if ai.maphandler:MobilityNetworkHere("bot", factory.position) == ai.maphandler:MobilityNetworkHere("bot", ai.enemyBasePosition) then 150 ai.needExperimental = true 151 break 152 end 153 end 154 end 155 ai.needNukes = true 156 end 157 EchoDebug("need experimental? " .. tostring(ai.needExperimental) .. ", need nukes? " .. tostring(ai.needNukes) .. ", have advanced? " .. tostring(ai.haveAdvFactory) .. ", need upgrade? " .. tostring(needUpgrade) .. ", have enemy base position? " .. tostring(ai.enemyBasePosition)) 158 EchoDebug("metal income: " .. ai.Metal.income .. " combat units: " .. ai.combatCount) 159 EchoDebug("have advanced? " .. tostring(ai.haveAdvFactory) .. " have experimental? " .. tostring(ai.haveExpFactory)) 160 EchoDebug("need advanced? " .. tostring(ai.needAdvanced) .. " need experimental? " .. tostring(ai.needExperimental)) 161 EchoDebug("need advanced? " .. tostring(ai.needAdvanced) .. ", need upgrade? " .. tostring(needUpgrade) .. ", have attacked enough? " .. tostring(couldAttack) .. " (" .. ai.couldAttack .. "), have " .. ai.factories .. " factories, " .. math.floor(ai.Metal.income) .. " metal income") 162 end 163end 164 165function IsSiegeEquipmentNeeded() 166 CheckForMapControl() 167 return needSiege 168end 169 170function IsAANeeded() 171 return ai.needAirDefense 172end 173 174function IsShieldNeeded() 175 return ai.needShields 176end 177 178function IsTorpedoNeeded() 179 return ai.needSubmergedDefense 180end 181 182function IsJammerNeeded() 183 return ai.needJammers 184end 185 186function IsAntinukeNeeded() 187 return ai.needAntinuke 188end 189 190function IsNukeNeeded() 191 local nuke = ai.needNukes and ai.canNuke 192 return nuke 193end 194 195function IsLandAttackNeeded() 196 return ai.areLandTargets or ai.needGroundDefense 197end 198 199function IsWaterAttackNeeded() 200 return ai.areWaterTargets or ai.needSubmergedDefense 201end 202 203function BuildMex() 204 local unitName 205 if ai.mySide == CORESideName then 206 unitName = "cormex" 207 else 208 unitName = "armmex" 209 end 210 return unitName 211end 212 213function BuildUWMex() 214 local unitName 215 if ai.mySide == CORESideName then 216 unitName = "coruwmex" 217 else 218 unitName = "armuwmex" 219 end 220 return unitName 221end 222 223function BuildMohoMex() 224 local unitName 225 if ai.mySide == CORESideName then 226 unitName = "cormoho" 227 else 228 unitName = "armmoho" 229 end 230 return unitName 231end 232 233function BuildUWMohoMex() 234 local unitName 235 if ai.mySide == CORESideName then 236 unitName = "coruwmme" 237 else 238 unitName = "armuwmme" 239 end 240 return unitName 241end 242 243function BuildWindSolarIfNeeded() 244 -- check if we need power 245 if ai.Energy.extra < 0 then 246 retVal = WindSolar 247 EchoDebug("BuildWindSolarIfNeeded: income "..res.income..", usage "..res.usage..", building more energy") 248 else 249 retVal = DummyUnitName 250 end 251 252 return retVal 253end 254 255function TidalIfTidal(self) 256 local unitName = DummyUnitName 257 EchoDebug("tidal power is " .. tidalPower) 258 if tidalPower >= 10 then 259 if ai.mySide == CORESideName then 260 unitName = "cortide" 261 else 262 unitName = "armtide" 263 end 264 end 265 return unitName 266end 267 268-- build conversion or storage 269function DoSomethingForTheEconomy(self) 270 local highEnergy = ai.Energy.full > 0.9 271 local lowEnergy = ai.Energy.full < 0.1 272 local highMetal = ai.Metal.full > 0.9 273 local lowMetal = ai.Metal.full < 0.1 274 local isWater = unitTable[self.unit:Internal():Name()].needsWater 275 local unitName = DummyUnitName 276 -- maybe we need conversion? 277 if ai.Energy.extra > 80 and highEnergy and lowMetal and ai.Metal.extra < 0 and ai.Energy.income > 300 then 278 local converterLimit = math.min(math.floor(ai.Energy.income / 200), 4) 279 if isWater then 280 if ai.mySide == CORESideName then 281 unitName = BuildWithLimitedNumber("corfmkr", converterLimit) 282 else 283 unitName = BuildWithLimitedNumber("armfmkr", converterLimit) 284 end 285 else 286 if ai.mySide == CORESideName then 287 unitName = BuildWithLimitedNumber("cormakr", converterLimit) 288 else 289 unitName = BuildWithLimitedNumber("armmakr", converterLimit) 290 end 291 end 292 end 293 -- maybe we need storage? 294 if unitName == DummyUnitName then 295 -- energy storage 296 if ai.Energy.extra > 150 and highEnergy and not lowMetal then 297 if isWater then 298 if ai.mySide == CORESideName then 299 unitName = BuildWithLimitedNumber("coruwes", 2) 300 else 301 unitName = BuildWithLimitedNumber("armuwes", 2) 302 end 303 else 304 if ai.mySide == CORESideName then 305 unitName = BuildWithLimitedNumber("corestor", 2) 306 else 307 unitName = BuildWithLimitedNumber("armestor", 2) 308 end 309 end 310 end 311 end 312 if unitName == DummyUnitName then 313 -- metal storage 314 if ai.Metal.extra > 5 and highMetal and highEnergy then 315 if isWater then 316 if ai.mySide == CORESideName then 317 unitName = BuildWithLimitedNumber("coruwms", 2) 318 else 319 unitName = BuildWithLimitedNumber("armuwms", 2) 320 end 321 else 322 if ai.mySide == CORESideName then 323 unitName = BuildWithLimitedNumber("cormstor", 2) 324 else 325 unitName = BuildWithLimitedNumber("armmstor", 2) 326 end 327 end 328 end 329 end 330 331 return unitName 332end 333 334 335-- build advanced conversion or storage 336function DoSomethingAdvancedForTheEconomy(self) 337 local highEnergy = ai.Energy.full > 0.9 338 local lowEnergy = ai.Energy.full < 0.1 339 local highMetal = ai.Metal.full > 0.9 340 local lowMetal = ai.Metal.full < 0.1 341 local unitName = self.unit:Internal():Name() 342 local isWater = unitTable[unitName].needsWater or seaplaneConList[unitName] 343 local unitName = DummyUnitName 344 -- maybe we need conversion? 345 if ai.Energy.extra > 800 and highEnergy and lowMetal and ai.Metal.extra < 0 and ai.Energy.income > 2000 then 346 local converterLimit = math.floor(ai.Energy.income / 1000) 347 if isWater then 348 if ai.mySide == CORESideName then 349 unitName = BuildWithLimitedNumber("armuwmmm", converterLimit) 350 else 351 unitName = BuildWithLimitedNumber("armuwmmm", converterLimit) 352 end 353 else 354 if ai.mySide == CORESideName then 355 unitName = BuildWithLimitedNumber("cormmkr", converterLimit) 356 else 357 unitName = BuildWithLimitedNumber("armmmkr", converterLimit) 358 end 359 end 360 end 361 -- building big storage is a waste 362 --[[ 363 -- maybe we need storage? 364 if unitName == DummyUnitName then 365 -- energy storage 366 if ai.Energy.extra > 1500 and highEnergy and not lowMetal then 367 if ai.mySide == CORESideName then 368 unitName = BuildWithLimitedNumber("coruwadves", 1) 369 else 370 unitName = BuildWithLimitedNumber("armuwadves", 1) 371 end 372 end 373 end 374 if unitName == DummyUnitName then 375 -- metal storage 376 if ai.Metal.extra > 25 and highMetal and highEnergy then 377 if ai.mySide == CORESideName then 378 unitName = BuildWithLimitedNumber("coruwadvms", 1) 379 else 380 unitName = BuildWithLimitedNumber("armuwadvms", 1) 381 end 382 end 383 end 384 ]]-- 385 386 return unitName 387end 388 389function BuildAAIfNeeded(unitName) 390 if IsAANeeded() then 391 if not unitTable[unitName].isBuilding then 392 return BuildWithLimitedNumber(unitName, AAUnitPerTypeLimit) 393 else 394 return unitName 395 end 396 else 397 return DummyUnitName 398 end 399end 400 401function BuildTorpedoIfNeeded(unitName) 402 if IsTorpedoNeeded() then 403 return unitName 404 else 405 return DummyUnitName 406 end 407end 408 409function BuildSiegeIfNeeded(unitName) 410 if unitName == DummyUnitName then return DummyUnitName end 411 if IsSiegeEquipmentNeeded() then 412 if ai.siegeCount < (ai.battleCount + ai.breakthroughCount) * 0.35 then 413 return unitName 414 end 415 end 416 return DummyUnitName 417end 418 419function BuildBreakthroughIfNeeded(unitName) 420 if unitName == DummyUnitName or unitName == nil then return DummyUnitName end 421 if IsSiegeEquipmentNeeded() then return unitName end 422 local mtype = unitTable[unitName].mtype 423 if mtype == "air" then 424 local bomberCounter = ai.bomberhandler:GetCounter() 425 if bomberCounter >= breakthroughBomberCounter and bomberCounter < maxBomberCounter then 426 return unitName 427 else 428 return DummyUnitName 429 end 430 else 431 if ai.battleCount <= minBattleCount then return DummyUnitName end 432 local attackCounter = ai.attackhandler:GetCounter(mtype) 433 if attackCounter == maxAttackCounter then 434 return unitName 435 elseif attackCounter >= breakthroughAttackCounter then 436 return unitName 437 else 438 return DummyUnitName 439 end 440 end 441end 442 443function Lvl1VehArty(self) 444 local unitName = "" 445 if ai.mySide == CORESideName then 446 unitName = "corwolv" 447 else 448 unitName = "tawf013" 449 end 450 return BuildSiegeIfNeeded(unitName) 451end 452 453function Lvl1BotBreakthrough(self) 454 local unitName = "" 455 if ai.mySide == CORESideName then 456 unitName = "corthud" 457 else 458 unitName = "armwar" 459 end 460 return BuildBreakthroughIfNeeded(unitName) 461end 462 463function Lvl1VehBreakthrough(self) 464 if ai.mySide == CORESideName then 465 return BuildBreakthroughIfNeeded("corlevlr") 466 else 467 -- armjanus isn't very a very good defense unit by itself 468 local output = BuildSiegeIfNeeded("armjanus") 469 if output == DummyUnitName then 470 output = BuildBreakthroughIfNeeded("armstump") 471 end 472 return output 473 end 474end 475 476function Lvl2VehBreakthrough(self) 477 local unitName = "" 478 if ai.mySide == CORESideName then 479 return BuildBreakthroughIfNeeded("corgol") 480 else 481 -- armmanni isn't very a very good defense unit by itself 482 local output = BuildSiegeIfNeeded("armmanni") 483 if output == DummyUnitName then 484 output = BuildBreakthroughIfNeeded("armbull") 485 end 486 return output 487 end 488end 489 490function Lvl2BotBreakthrough(self) 491 local unitName = "" 492 if ai.mySide == CORESideName then 493 unitName = "corsumo" 494 else 495 unitName = "armfboy" 496 end 497 return BuildBreakthroughIfNeeded(unitName) 498end 499 500function Lvl2BotArty(self) 501 local unitName = "" 502 if ai.mySide == CORESideName then 503 unitName = "cormort" 504 else 505 unitName = "armfido" 506 end 507 return BuildSiegeIfNeeded(unitName) 508end 509 510function Lvl2BotMerl(self) 511 local unitName = "" 512 if ai.mySide == CORESideName then 513 unitName = "corhrk" 514 else 515 return DummyUnitName 516 end 517 return BuildSiegeIfNeeded(unitName) 518end 519 520function Lvl2VehArty(self) 521 local unitName = "" 522 if ai.mySide == CORESideName then 523 unitName = "cormart" 524 else 525 unitName = "armmart" 526 end 527 return BuildSiegeIfNeeded(unitName) 528end 529 530function Lvl2VehMerl(self) 531 local unitName = "" 532 if ai.mySide == CORESideName then 533 unitName = "corvroc" 534 else 535 unitName = "armmerl" 536 end 537 return BuildSiegeIfNeeded(unitName) 538end 539 540function HoverMerl(self) 541 local unitName = "" 542 if ai.mySide == CORESideName then 543 unitName = "cormh" 544 else 545 unitName = "armmh" 546 end 547 return BuildSiegeIfNeeded(unitName) 548end 549 550function Lvl2ShipBreakthrough(self) 551 local unitName = "" 552 if ai.mySide == CORESideName then 553 unitName = "corbats" 554 else 555 unitName = "armbats" 556 end 557 return BuildBreakthroughIfNeeded(unitName) 558end 559 560function Lvl2ShipMerl(self) 561 local unitName = "" 562 if ai.mySide == CORESideName then 563 unitName = "cormship" 564 else 565 unitName = "armmship" 566 end 567 return BuildSiegeIfNeeded(unitName) 568end 569 570function MegaShip() 571 local unitName = "" 572 if ai.mySide == CORESideName then 573 unitName = "corblackhy" 574 else 575 unitName = "aseadragon" 576 end 577 return BuildBreakthroughIfNeeded(BuildWithLimitedNumber(unitName, 1)) 578end 579 580function MegaAircraft() 581 if ai.mySide == CORESideName then 582 return BuildBreakthroughIfNeeded("corcrw") 583 else 584 return BuildBreakthroughIfNeeded("armcybr") 585 end 586end 587 588function Lvl3Merl(self) 589 local unitName = "" 590 if ai.mySide == CORESideName then 591 unitName = "armraven" 592 else 593 unitName = DummyUnitName 594 end 595 return BuildSiegeIfNeeded(unitName) 596end 597 598function Lvl3Arty(self) 599 local unitName = "" 600 if ai.mySide == CORESideName then 601 unitName = "shiva" 602 else 603 unitName = "armshock" 604 end 605 return BuildSiegeIfNeeded(unitName) 606end 607 608function Lvl3Breakthrough(self) 609 local unitName = "" 610 if ai.mySide == CORESideName then 611 unitName = BuildWithLimitedNumber("corkrog", 1) 612 if unitName == DummyUnitName then 613 unitName = BuildWithLimitedNumber("gorg", 2) 614 end 615 if unitName == DummyUnitName then 616 unitName = "corkarg" 617 end 618 else 619 unitName = BuildWithLimitedNumber("armbanth", 5) 620 if unitName == DummyUnitName then 621 unitName = "armraz" 622 end 623 end 624 return BuildBreakthroughIfNeeded(unitName) 625end 626 627function BuildRaiderIfNeeded(unitName) 628 if unitName == DummyUnitName or unitName == nil then return DummyUnitName end 629 local mtype = unitTable[unitName].mtype 630 if ai.factoriesAtLevel[3] ~= nil and ai.factoriesAtLevel[3] ~= {} then 631 -- if we have a level 2 factory, don't build raiders until we have some battle units 632 local attackCounter = ai.attackhandler:GetCounter(mtype) 633 if ai.battleCount + ai.breakthroughCount < attackCounter / 2 then 634 return DummyUnitName 635 end 636 end 637 local counter = ai.raidhandler:GetCounter(mtype) 638 if counter == minRaidCounter then return DummyUnitName end 639 if ai.raiderCount[mtype] == nil then 640 -- fine 641 elseif ai.raiderCount[mtype] >= counter then 642 unitName = DummyUnitName 643 end 644 return unitName 645end 646 647function Lvl1VehRaider(self) 648 local unitName = "" 649 if ai.mySide == CORESideName then 650 unitName = "corgator" 651 else 652 unitName = "armflash" 653 end 654 return BuildRaiderIfNeeded(unitName) 655end 656 657-- because core doesn't have a lvl2 vehicle raider or a lvl3 raider 658function Lvl1VehRaiderOutmoded(self) 659 if ai.mySide == CORESideName then 660 return BuildRaiderIfNeeded("corgator") 661 else 662 return DummyUnitName 663 end 664end 665 666 667function Lvl1BotRaider(self) 668 local unitName = "" 669 if ai.mySide == CORESideName then 670 unitName = "corak" 671 else 672 unitName = "armpw" 673 end 674 return BuildRaiderIfNeeded(unitName) 675end 676 677function Lvl1ShipRaider(self) 678 local unitName = "" 679 if ai.mySide == CORESideName then 680 unitName = "corsub" 681 else 682 unitName = "armsub" 683 end 684 return BuildRaiderIfNeeded(unitName) 685end 686 687function Lvl1AirRaider(self) 688 local unitName = "" 689 if ai.mySide == CORESideName then 690 unitName = "bladew" 691 else 692 unitName = "armkam" 693 end 694 return BuildRaiderIfNeeded(unitName) 695end 696 697function Lvl2VehRaider(self) 698 if ai.mySide == CORESideName then 699 return DummyUnitName 700 else 701 return BuildRaiderIfNeeded("armlatnk") 702 end 703end 704 705function Lvl2BotRaider(self) 706 local unitName = "" 707 if ai.mySide == CORESideName then 708 unitName = "corpyro" 709 else 710 unitName = "armfast" 711 end 712 return BuildRaiderIfNeeded(unitName) 713end 714 715function Lvl2ShipRaider(self) 716 local unitName = "" 717 if ai.mySide == CORESideName then 718 unitName = "corshark" 719 else 720 unitName = "armsubk" 721 end 722 return BuildRaiderIfNeeded(unitName) 723end 724 725function Lvl2AirRaider(self) 726 local unitName = "" 727 if ai.mySide == CORESideName then 728 unitName = "corape" 729 else 730 -- spedical case: arm has an ubergunship 731 local raidCounter = ai.raidhandler:GetCounter("air") 732 if raidCounter < baseRaidCounter and raidCounter > minRaidCounter then 733 return "blade" 734 else 735 unitName = "armbrawl" 736 end 737 end 738 return BuildRaiderIfNeeded(unitName) 739end 740 741function HoverRaider(self) 742 local unitName = "" 743 if ai.mySide == CORESideName then 744 unitName = "corsh" 745 else 746 unitName = "armsh" 747 end 748 return BuildRaiderIfNeeded(unitName) 749end 750 751function AmphibiousRaider(self) 752 local unitName = "" 753 if ai.mySide == CORESideName then 754 unitName = "corgarp" 755 else 756 unitName = "armpincer" 757 end 758 return BuildRaiderIfNeeded(unitName) 759end 760 761function Lvl3Raider(self) 762 local unitName = "" 763 if ai.mySide == CORESideName then 764 unitName = DummyUnitName 765 else 766 unitName = "marauder" 767 end 768 return BuildRaiderIfNeeded(unitName) 769end 770 771function BuildBattleIfNeeded(unitName) 772 if unitName == DummyUnitName or unitName == nil then return DummyUnitName end 773 local mtype = unitTable[unitName].mtype 774 local attackCounter = ai.attackhandler:GetCounter(mtype) 775 EchoDebug(mtype .. " " .. attackCounter .. " " .. maxAttackCounter) 776 if attackCounter == maxAttackCounter and ai.battleCount > minBattleCount then return DummyUnitName end 777 if mtype == "veh" and ai.mySide == CORESideName and (ai.factoriesAtLevel[1] == nil or ai.factoriesAtLevel[1] == {}) then 778 -- core only has a lvl1 vehicle raider, so this prevents getting stuck 779 return unitName 780 end 781 if ai.factoriesAtLevel[3] ~= nil and ai.factoriesAtLevel[3] ~= {} then 782 -- if we have a level 2 factory, don't wait to build raiders first 783 return unitName 784 end 785 local raidCounter = ai.raidhandler:GetCounter(mtype) 786 EchoDebug(mtype .. " " .. raidCounter .. " " .. maxRaidCounter) 787 if raidCounter == minRaidCounter then return unitName end 788 EchoDebug(ai.raiderCount[mtype]) 789 if ai.raiderCount[mtype] == nil then 790 return unitName 791 elseif ai.raiderCount[mtype] < raidCounter / 2 then 792 return DummyUnitName 793 else 794 return unitName 795 end 796end 797 798function Lvl2BotCorRaiderArmBattle(self) 799 if ai.mySide == CORESideName then 800 return Lvl2BotRaider(self) 801 else 802 return Lvl2BotBattle(self) 803 end 804end 805 806function Lvl1VehBattle(self) 807 local unitName = "" 808 if ai.mySide == CORESideName then 809 unitName = "corraid" 810 else 811 unitName = "armstump" 812 end 813 return BuildBattleIfNeeded(unitName) 814end 815 816function Lvl1BotBattle(self) 817 local unitName = "" 818 local r = math.random(1, 2) 819 if r == 1 then 820 if ai.mySide == CORESideName then 821 unitName = "corthud" 822 else 823 unitName = "armham" 824 end 825 else 826 if ai.mySide == CORESideName then 827 unitName = "corstorm" 828 else 829 unitName = "armrock" 830 end 831 end 832 return BuildBattleIfNeeded(unitName) 833end 834 835function HoverBattle(self) 836 local unitName = "" 837 if ai.mySide == CORESideName then 838 unitName = "corsnap" 839 else 840 unitName = "armanac" 841 end 842 return BuildBattleIfNeeded(unitName) 843end 844 845function HoverBreakthrough(self) 846 local unitName = "" 847 if ai.mySide == CORESideName then 848 unitName = "nsaclash" 849 else 850 unitName = "armanac" 851 end 852 BuildBreakthroughIfNeeded(unitName) 853end 854 855function AmphibiousBattle(self) 856 local unitName = "" 857 if ai.mySide == CORESideName then 858 unitName = "corseal" 859 else 860 unitName = "armcroc" 861 end 862 return BuildBattleIfNeeded(unitName) 863end 864 865function AmphibiousBreakthrough(self) 866 local unitName = "" 867 if ai.mySide == CORESideName then 868 unitName = "corparrow" 869 else 870 unitName = "armcroc" 871 end 872 BuildBreakthroughIfNeeded(unitName) 873end 874 875function Lvl1ShipDestroyerOnly(self) 876 if ai.combatCount > 12 then 877 if ai.mySide == CORESideName then 878 unitName = "corroy" 879 else 880 unitName = "armroy" 881 end 882 return BuildBattleIfNeeded(unitName) 883 end 884end 885 886function Lvl1ShipBattle(self) 887 local unitName = "" 888 local r = 1 889 if ai.combatCount > 12 then r = 2 end -- only build destroyers if you've already got quite a few units (combat = scouts + raiders + battle) 890 if r == 1 then 891 if ai.mySide == CORESideName then 892 unitName = "coresupp" 893 else 894 unitName = "decade" 895 end 896 else 897 if ai.mySide == CORESideName then 898 unitName = "corroy" 899 else 900 unitName = "armroy" 901 end 902 end 903 return BuildBattleIfNeeded(unitName) 904end 905 906function Lvl2VehBattle(self) 907 local unitName = "" 908 if ai.mySide == CORESideName then 909 unitName = "correap" 910 else 911 unitName = "armbull" 912 end 913 return BuildBattleIfNeeded(unitName) 914end 915 916function Lvl2BotBattle(self) 917 local unitName = "" 918 if ai.mySide == CORESideName then 919 unitName = "corcan" 920 else 921 unitName = "armzeus" 922 end 923 return BuildBattleIfNeeded(unitName) 924end 925 926function Lvl2ShipBattle(self) 927 local unitName = "" 928 if ai.mySide == CORESideName then 929 unitName = "corcrus" 930 else 931 unitName = "armcrus" 932 end 933 return BuildBattleIfNeeded(unitName) 934end 935 936function Lvl3Battle(self) 937 local unitName = "" 938 if ai.mySide == CORESideName then 939 unitName = "corkarg" 940 else 941 unitName = "armraz" 942 end 943 return BuildBattleIfNeeded(unitName) 944end 945 946function WindSolar() 947 local wind = false 948 if needWind then 949 if windRatio == 1 then 950 wind = true 951 else 952 local r = math.random() 953 if r < windRatio then wind = true end 954 end 955 end 956 if wind then 957 if ai.mySide == CORESideName then 958 return "corwin" 959 else 960 return "armwin" 961 end 962 else 963 if ai.mySide == CORESideName then 964 return "corsolar" 965 else 966 return "armsolar" 967 end 968 end 969end 970 971function Solar() 972 if ai.mySide == CORESideName then 973 return "corsolar" 974 else 975 return "armsolar" 976 end 977end 978 979local function WindSolarTidal(self) 980 LandOrWater(self, WindSolar(), TidalIfTidal()) 981end 982 983function CountOwnUnits(tmpUnitName) 984 if tmpUnitName == DummyUnitName then return 0 end -- don't count no-units 985 if ai.nameCount[tmpUnitName] == nil then return 0 end 986 return ai.nameCount[tmpUnitName] 987end 988 989function BuildWithLimitedNumber(tmpUnitName, minNumber) 990 if tmpUnitName == DummyUnitName then return DummyUnitName end 991 if minNumber == 0 then return DummyUnitName end 992 if ai.nameCount[tmpUnitName] == nil then 993 return tmpUnitName 994 else 995 if ai.nameCount[tmpUnitName] == 0 or ai.nameCount[tmpUnitName] < minNumber then 996 return tmpUnitName 997 else 998 return DummyUnitName 999 end 1000 end 1001end 1002 1003local function SolarAdv() 1004 if ai.mySide == CORESideName then 1005 return "coradvsol" 1006 else 1007 return "armadvsol" 1008 end 1009end 1010 1011local function BuildGeo() 1012 -- don't attempt if there are no spots on the map 1013 if not ai.mapHasGeothermal then 1014 return DummyUnitName 1015 end 1016 if ai.mySide == CORESideName then 1017 return "corgeo" 1018 else 1019 return "armgeo" 1020 end 1021end 1022 1023local function BuildMohoGeo(self) 1024 -- don't attempt if there are no spots on the map 1025 if not ai.mapHasGeothermal then 1026 return DummyUnitName 1027 end 1028 if ai.mySide == CORESideName then 1029 return "cmgeo" 1030 else 1031 return "amgeo" 1032 end 1033 -- will turn into a safe geothermal or a geothermal plasma battery if too close to a factory 1034end 1035 1036local function BuildFusion() 1037 if ai.mySide == CORESideName then 1038 return "corfus" 1039 else 1040 return "armfus" 1041 end 1042 -- will become cafus and aafus in CategoryEconFilter in TaskQueueBehaviour if energy income is higher than 4000 1043end 1044 1045local function BuildUWFusion() 1046 if ai.mySide == CORESideName then 1047 return "coruwfus" 1048 else 1049 return "armuwfus" 1050 end 1051end 1052 1053local function Lvl1AABot() 1054 if ai.mySide == CORESideName then 1055 return BuildAAIfNeeded("corcrash") 1056 else 1057 return BuildAAIfNeeded("armjeth") 1058 end 1059end 1060 1061local function Lvl2AABot() 1062 if ai.mySide == CORESideName then 1063 return BuildAAIfNeeded("coraak") 1064 else 1065 return BuildAAIfNeeded("armaak") 1066 end 1067end 1068 1069local function Lvl1AAVeh() 1070 if ai.mySide == CORESideName then 1071 return BuildAAIfNeeded("cormist") 1072 else 1073 return BuildAAIfNeeded("armsam") 1074 end 1075end 1076 1077local function Lvl2AAVeh() 1078 if ai.mySide == CORESideName then 1079 return BuildAAIfNeeded("corsent") 1080 else 1081 return BuildAAIfNeeded("armyork") 1082 end 1083end 1084 1085local function Lvl2AAShip() 1086 if ai.mySide == CORESideName then 1087 return BuildAAIfNeeded("corarch") 1088 else 1089 return BuildAAIfNeeded("armaas") 1090 end 1091end 1092 1093local function AAHover() 1094 if ai.mySide == CORESideName then 1095 return BuildAAIfNeeded("corah") 1096 else 1097 return BuildAAIfNeeded("armah") 1098 end 1099end 1100 1101local function ConVehicle() 1102 local unitName 1103 if needAmphibiousCons then 1104 if ai.mySide == CORESideName then 1105 unitName = "cormuskrat" 1106 else 1107 unitName = "armbeaver" 1108 end 1109 else 1110 if ai.mySide == CORESideName then 1111 unitName = "corcv" 1112 else 1113 unitName = "armcv" 1114 end 1115 end 1116 return BuildWithLimitedNumber(unitName, ConUnitPerTypeLimit) 1117end 1118 1119local function ConVehicleAmphibious() 1120 if ai.mySide == CORESideName then 1121 unitName = "cormuskrat" 1122 else 1123 unitName = "armbeaver" 1124 end 1125 return BuildWithLimitedNumber(unitName, ConUnitAdvPerTypeLimit) 1126end 1127 1128local function ConAdvVehicle() 1129 if ai.mySide == CORESideName then 1130 return BuildWithLimitedNumber("coracv", ConUnitAdvPerTypeLimit) 1131 else 1132 return BuildWithLimitedNumber("armacv", ConUnitAdvPerTypeLimit) 1133 end 1134end 1135 1136local function ConBot() 1137 if ai.mySide == CORESideName then 1138 return BuildWithLimitedNumber("corck", ConUnitPerTypeLimit) 1139 else 1140 return BuildWithLimitedNumber("armck", ConUnitPerTypeLimit) 1141 end 1142end 1143 1144local function ConCoreBotArmVehicle() 1145 if ai.mySide == CORESideName then 1146 return BuildWithLimitedNumber("corck", ConUnitPerTypeLimit) 1147 else 1148 return BuildWithLimitedNumber("armcv", ConUnitPerTypeLimit) 1149 end 1150end 1151 1152local function ConAdvBot() 1153 if ai.mySide == CORESideName then 1154 return BuildWithLimitedNumber("corack", ConUnitAdvPerTypeLimit) 1155 else 1156 return BuildWithLimitedNumber("armack", ConUnitAdvPerTypeLimit) 1157 end 1158end 1159 1160local function ConAir() 1161 if ai.mySide == CORESideName then 1162 return BuildWithLimitedNumber("corca", ConUnitPerTypeLimit) 1163 else 1164 return BuildWithLimitedNumber("armca", ConUnitPerTypeLimit) 1165 end 1166end 1167 1168local function ConAdvAir() 1169 if ai.mySide == CORESideName then 1170 return BuildWithLimitedNumber("coraca", ConUnitAdvPerTypeLimit) 1171 else 1172 return BuildWithLimitedNumber("armaca", ConUnitAdvPerTypeLimit) 1173 end 1174end 1175 1176local function ConSeaAir() 1177 if ai.mySide == CORESideName then 1178 return BuildWithLimitedNumber("corcsa", ConUnitPerTypeLimit) 1179 else 1180 return BuildWithLimitedNumber("armcsa", ConUnitPerTypeLimit) 1181 end 1182end 1183 1184local function ConShip() 1185 if ai.mySide == CORESideName then 1186 return BuildWithLimitedNumber("corcs", ConUnitPerTypeLimit) 1187 else 1188 return BuildWithLimitedNumber("armcs", ConUnitPerTypeLimit) 1189 end 1190end 1191 1192local function ConAdvSub() 1193 if ai.mySide == CORESideName then 1194 return BuildWithLimitedNumber("coracsub", ConUnitAdvPerTypeLimit) 1195 else 1196 return BuildWithLimitedNumber("armacsub", ConUnitAdvPerTypeLimit) 1197 end 1198end 1199 1200local function ConHover() 1201 if ai.mySide == CORESideName then 1202 return BuildWithLimitedNumber("corch", ConUnitPerTypeLimit) 1203 else 1204 return BuildWithLimitedNumber("armch", ConUnitPerTypeLimit) 1205 end 1206end 1207 1208local function GroundDefenseIfNeeded(unitName, builder) 1209 if not ai.needGroundDefense then 1210 return DummyUnitName 1211 else 1212 return unitName 1213 end 1214end 1215 1216function BuildShield() 1217 if IsShieldNeeded() then 1218 local unitName = "" 1219 if ai.mySide == CORESideName then 1220 unitName = "corgate" 1221 else 1222 unitName = "armgate" 1223 end 1224 return unitName 1225 end 1226 return DummyUnitName 1227end 1228 1229function BuildAntinuke() 1230 if IsAntinukeNeeded() then 1231 local unitName = "" 1232 if ai.mySide == CORESideName then 1233 unitName = "corfmd" 1234 else 1235 unitName = "armamd" 1236 end 1237 return unitName 1238 end 1239 return DummyUnitName 1240end 1241 1242function BuildNuke() 1243 local unitName = "" 1244 if ai.mySide == CORESideName then 1245 unitName = "corsilo" 1246 else 1247 unitName = "armsilo" 1248 end 1249 return BuildWithLimitedNumber(unitName, nukeLimit) 1250end 1251 1252function BuildNukeIfNeeded() 1253 if IsNukeNeeded() then 1254 return BuildNuke() 1255 end 1256end 1257 1258function BuildTacticalNuke() 1259 local unitName = "" 1260 if ai.mySide == CORESideName then 1261 unitName = "cortron" 1262 else 1263 unitName = "armemp" 1264 end 1265 return BuildWithLimitedNumber(unitName, tacticalNukeLimit) 1266end 1267 1268local function BuildLvl1Plasma() 1269 local unitName = "" 1270 if ai.mySide == CORESideName then 1271 unitName = "corpun" 1272 else 1273 unitName = "armguard" 1274 end 1275 return unitName 1276end 1277 1278local function BuildLvl2Plasma() 1279 local unitName = "" 1280 if ai.mySide == CORESideName then 1281 unitName = "cortoast" 1282 else 1283 unitName = "armamb" 1284 end 1285 return unitName 1286end 1287 1288local function BuildHeavyPlasma() 1289 local unitName = "" 1290 if ai.mySide == CORESideName then 1291 unitName = "corint" 1292 else 1293 unitName = "armbrtha" 1294 end 1295 return BuildWithLimitedNumber(unitName, heavyPlasmaLimit) 1296end 1297 1298local function BuildLLT(self) 1299 if self.unit == nil then 1300 return DummyUnitName 1301 end 1302 local unitName = "" 1303 if ai.mySide == CORESideName then 1304 unitName = "corllt" 1305 else 1306 unitName = "armllt" 1307 end 1308 local unit = self.unit:Internal() 1309 return GroundDefenseIfNeeded(unitName, unit) 1310end 1311 1312local function BuildSpecialLT(self) 1313 if self.unit == nil then 1314 return DummyUnitName 1315 end 1316 local unitName = "" 1317 if IsAANeeded() then 1318 -- pop-up turrets are protected against bombs 1319 if ai.mySide == CORESideName then 1320 unitName = "cormaw" 1321 else 1322 unitName = "armclaw" 1323 end 1324 else 1325 if ai.mySide == CORESideName then 1326 unitName = "hllt" 1327 else 1328 unitName = "tawf001" 1329 end 1330 end 1331 local unit = self.unit:Internal() 1332 return GroundDefenseIfNeeded(unitName, unit) 1333end 1334 1335local function BuildSpecialLTOnly(self) 1336 if self.unit == nil then 1337 return DummyUnitName 1338 end 1339 local unitName = "" 1340 if ai.mySide == CORESideName then 1341 unitName = "hllt" 1342 else 1343 unitName = "tawf001" 1344 end 1345 local unit = self.unit:Internal() 1346 return GroundDefenseIfNeeded(unitName, unit) 1347end 1348 1349local function BuildFloatHLT(self) 1350 if self.unit == nil then 1351 return DummyUnitName 1352 end 1353 local unitName = "" 1354 if ai.mySide == CORESideName then 1355 unitName = "corfhlt" 1356 else 1357 unitName = "armfhlt" 1358 end 1359 local unit = self.unit:Internal() 1360 return GroundDefenseIfNeeded(unitName, unit) 1361end 1362 1363local function BuildHLT(self) 1364 if self.unit == nil then 1365 return DummyUnitName 1366 end 1367 local unitName = "" 1368 if ai.mySide == CORESideName then 1369 unitName = "corhlt" 1370 else 1371 unitName = "armhlt" 1372 end 1373 local unit = self.unit:Internal() 1374 return GroundDefenseIfNeeded(unitName, unit) 1375end 1376 1377local function BuildLvl2PopUp(self) 1378 if self.unit == nil then 1379 return DummyUnitName 1380 end 1381 local unitName = "" 1382 if ai.mySide == CORESideName then 1383 unitName = "corvipe" 1384 else 1385 unitName = "armpb" 1386 end 1387 local unit = self.unit:Internal() 1388 return GroundDefenseIfNeeded(unitName, unit) 1389end 1390 1391local function BuildTachyon(self) 1392 if self.unit == nil then 1393 return DummyUnitName 1394 end 1395 local unitName = "" 1396 if ai.mySide == CORESideName then 1397 unitName = "cordoom" 1398 else 1399 unitName = "armanni" 1400 end 1401 local unit = self.unit:Internal() 1402 return GroundDefenseIfNeeded(unitName, unit) 1403end 1404 1405local function BuildDepthCharge(self) 1406 if self.unit == nil then 1407 return DummyUnitName 1408 end 1409 local unitName = "" 1410 if ai.mySide == CORESideName then 1411 unitName = "cordl" 1412 else 1413 unitName = "armdl" 1414 end 1415 return BuildTorpedoIfNeeded(unitName) 1416end 1417 1418 1419local function BuildLightTorpedo(self) 1420 if self.unit == nil then 1421 return DummyUnitName 1422 end 1423 local unitName = "" 1424 if ai.mySide == CORESideName then 1425 unitName = "cortl" 1426 else 1427 unitName = "armtl" 1428 end 1429 return BuildTorpedoIfNeeded(unitName) 1430end 1431 1432local function BuildPopTorpedo(self) 1433 if self.unit == nil then 1434 return DummyUnitName 1435 end 1436 local unitName = "" 1437 if ai.mySide == CORESideName then 1438 unitName = "corptl" 1439 else 1440 unitName = "armptl" 1441 end 1442 return BuildTorpedoIfNeeded(unitName) 1443end 1444 1445local function BuildHeavyTorpedo(self) 1446 if self.unit == nil then 1447 return DummyUnitName 1448 end 1449 local unitName = "" 1450 if ai.mySide == CORESideName then 1451 unitName = "coratl" 1452 else 1453 unitName = "armatl" 1454 end 1455 return BuildTorpedoIfNeeded(unitName) 1456end 1457 1458 1459-- build AA in area only if there's not enough of it there already 1460local function BuildLightAA(self) 1461 if self.unit == nil then 1462 return DummyUnitName 1463 end 1464 local unitName = "" 1465 if ai.mySide == CORESideName then 1466 unitName = BuildAAIfNeeded("corrl") 1467 else 1468 unitName = BuildAAIfNeeded("armrl") 1469 end 1470 return unitName 1471end 1472 1473local function BuildFloatLightAA(self) 1474 if self.unit == nil then 1475 return DummyUnitName 1476 end 1477 local unitName = "" 1478 if ai.mySide == CORESideName then 1479 unitName = BuildAAIfNeeded("corfrt") 1480 else 1481 unitName = BuildAAIfNeeded("armfrt") 1482 end 1483 return unitName 1484end 1485 1486local function BuildMediumAA(self) 1487 if self.unit == nil then 1488 return DummyUnitName 1489 end 1490 local unitName = "" 1491 if ai.mySide == CORESideName then 1492 unitName = BuildAAIfNeeded("madsam") 1493 else 1494 unitName = BuildAAIfNeeded("packo") 1495 end 1496 return unitName 1497end 1498 1499local function BuildHeavyishAA(self) 1500 if self.unit == nil then 1501 return DummyUnitName 1502 end 1503 local unitName = "" 1504 if ai.mySide == CORESideName then 1505 unitName = BuildAAIfNeeded("corerad") 1506 else 1507 unitName = BuildAAIfNeeded("armcir") 1508 end 1509 return unitName 1510end 1511 1512local function BuildHeavyAA(self) 1513 if self.unit == nil then 1514 return DummyUnitName 1515 end 1516 local unitName = "" 1517 if ai.mySide == CORESideName then 1518 unitName = BuildAAIfNeeded("corflak") 1519 else 1520 unitName = BuildAAIfNeeded("armflak") 1521 end 1522 return unitName 1523end 1524 1525local function BuildFloatHeavyAA(self) 1526 if self.unit == nil then 1527 return DummyUnitName 1528 end 1529 local unitName = "" 1530 if ai.mySide == CORESideName then 1531 unitName = BuildAAIfNeeded("corenaa") 1532 else 1533 unitName = BuildAAIfNeeded("armfflak") 1534 end 1535 return unitName 1536end 1537 1538local function BuildExtraHeavyAA(self) 1539 if self.unit == nil then 1540 return DummyUnitName 1541 end 1542 local unitName = "" 1543 if ai.mySide == CORESideName then 1544 unitName = BuildAAIfNeeded("screamer") 1545 else 1546 unitName = BuildAAIfNeeded("mercury") 1547 end 1548 return unitName 1549end 1550 1551local function BuildSonar() 1552 local unitName = "" 1553 if ai.mySide == CORESideName then 1554 unitName = "corsonar" 1555 else 1556 unitName = "armsonar" 1557 end 1558 return unitName 1559end 1560 1561local function BuildAdvancedSonar() 1562 local unitName = "" 1563 if ai.mySide == CORESideName then 1564 unitName = "corason" 1565 else 1566 unitName = "armason" 1567 end 1568 return unitName 1569end 1570 1571 1572local function BuildRadar() 1573 local unitName = "" 1574 if ai.mySide == CORESideName then 1575 unitName = "corrad" 1576 else 1577 unitName = "armrad" 1578 end 1579 return unitName 1580end 1581 1582local function BuildFloatRadar() 1583 local unitName = "" 1584 if ai.mySide == CORESideName then 1585 unitName = "corfrad" 1586 else 1587 unitName = "armfrad" 1588 end 1589 return unitName 1590end 1591 1592local function BuildAdvancedRadar() 1593 local unitName = "" 1594 if ai.mySide == CORESideName then 1595 unitName = "corarad" 1596 else 1597 unitName = "armarad" 1598 end 1599 return unitName 1600end 1601 1602local function BuildLvl1Jammer() 1603 if not IsJammerNeeded() then return DummyUnitName end 1604 if ai.mySide == CORESideName then 1605 return "corjamt" 1606 else 1607 return "armjamt" 1608 end 1609end 1610 1611local function BuildLvl2Jammer() 1612 if not IsJammerNeeded() then return DummyUnitName end 1613 if ai.mySide == CORESideName then 1614 return "corshroud" 1615 else 1616 return "armveil" 1617 end 1618end 1619 1620local function NanoTurret() 1621 local unitName = "" 1622 if ai.mySide == CORESideName then 1623 unitName = "cornanotc" 1624 else 1625 unitName = "armnanotc" 1626 end 1627 return BuildWithLimitedNumber(unitName, ai.factories * 12) 1628end 1629 1630local function AirRepairPadIfNeeded() 1631 local tmpUnitName = DummyUnitName 1632 1633 -- only make air pads if the team has at least 1 air fac 1634 if CountOwnUnits("corap") > 0 or CountOwnUnits("armap") > 0 or CountOwnUnits("coraap") > 0 or CountOwnUnits("armaap") > 0 then 1635 if ai.mySide == CORESideName then 1636 tmpUnitName = "corasp" 1637 else 1638 tmpUnitName = "armasp" 1639 end 1640 end 1641 1642 return BuildWithLimitedNumber(tmpUnitName, ConUnitPerTypeLimit) 1643end 1644 1645local function corDebug(self) 1646 game:SendToConsole("d") 1647 return "corwin" 1648end 1649 1650function BuildBomberIfNeeded(unitName) 1651 if not IsLandAttackNeeded() then return DummyUnitName end 1652 if unitName == DummyUnitName or unitName == nil then return DummyUnitName end 1653 if ai.bomberhandler:GetCounter() == maxBomberCounter then 1654 return DummyUnitName 1655 else 1656 return unitName 1657 end 1658end 1659 1660function BuildTorpedoBomberIfNeeded(unitName) 1661 if not IsWaterAttackNeeded() then return DummyUnitName end 1662 if unitName == DummyUnitName or unitName == nil then return DummyUnitName end 1663 if ai.bomberhandler:GetCounter() == maxBomberCounter then 1664 return DummyUnitName 1665 else 1666 return unitName 1667 end 1668end 1669 1670function Lvl1Bomber() 1671 local unitName 1672 if ai.mySide == CORESideName then 1673 unitName = "corshad" 1674 else 1675 unitName = "armthund" 1676 end 1677 return BuildBomberIfNeeded(unitName) 1678end 1679 1680function Lvl1Fighter() 1681 local unitName 1682 if ai.mySide == CORESideName then 1683 unitName = "corveng" 1684 else 1685 unitName = "armfig" 1686 end 1687 return BuildAAIfNeeded(unitName) 1688end 1689 1690function Lvl2Bomber() 1691 local unitName 1692 if ai.mySide == CORESideName then 1693 unitName = "corhurc" 1694 else 1695 unitName = "armpnix" 1696 end 1697 return BuildBomberIfNeeded(unitName) 1698end 1699 1700function Lvl2TorpedoBomber() 1701 local unitName 1702 if ai.mySide == CORESideName then 1703 unitName = "cortitan" 1704 else 1705 unitName = "armlance" 1706 end 1707 return BuildTorpedoBomberIfNeeded(unitName) 1708end 1709 1710function Lvl2Fighter() 1711 local unitName 1712 if ai.mySide == CORESideName then 1713 unitName = "corvamp" 1714 else 1715 unitName = "armhawk" 1716 end 1717 return BuildAAIfNeeded(unitName) 1718end 1719 1720function SeaBomber() 1721 local unitName 1722 if ai.mySide == CORESideName then 1723 unitName = "corsb" 1724 else 1725 unitName = "armsb" 1726 end 1727 return BuildBomberIfNeeded(unitName) 1728end 1729 1730function SeaTorpedoBomber() 1731 local unitName 1732 if ai.mySide == CORESideName then 1733 unitName = "corseap" 1734 else 1735 unitName = "armseap" 1736 end 1737 return BuildTorpedoBomberIfNeeded(unitName) 1738end 1739 1740function SeaFighter() 1741 local unitName 1742 if ai.mySide == CORESideName then 1743 unitName = "corsfig" 1744 else 1745 unitName = "armsfig" 1746 end 1747 return BuildAAIfNeeded(unitName) 1748end 1749 1750function SeaAirRaider(self) 1751 local unitName = "" 1752 if ai.mySide == CORESideName then 1753 unitName = "corcut" 1754 else 1755 unitName = "armsaber" 1756 end 1757 return BuildRaiderIfNeeded(unitName) 1758end 1759 1760local function CheckMySideIfNeeded() 1761 if ai.mySide == nil then 1762 EchoDebug("commander: checkmyside") 1763 return CheckMySide 1764 else 1765 return DummyUnitName 1766 end 1767end 1768 1769local function BuildAppropriateFactory() 1770 return FactoryUnitName 1771end 1772 1773local function FactoryOrNano(self) 1774 CheckForMapControl() 1775 if ai.factories == 0 then return BuildAppropriateFactory() end 1776 EchoDebug("factories: " .. ai.factories .. " combat units: " .. ai.combatCount) 1777 local unitName = DummyUnitName 1778 local attackCounter = ai.attackhandler:GetCounter() 1779 local couldAttack = ai.couldAttack >= 2 or ai.couldBomb >= 2 1780 if (ai.combatCount > attackCounter * 0.5 and couldAttack) or ai.needAdvanced then 1781 unitName = BuildAppropriateFactory() 1782 end 1783 if unitName == DummyUnitName and ai.combatCount > attackCounter * 0.2 then 1784 unitName = NanoTurret() 1785 end 1786 return unitName 1787end 1788 1789local function LandOrWater(self, landName, waterName) 1790 local builder = self.unit:Internal() 1791 local bpos = builder:GetPosition() 1792 local waterNet = ai.maphandler:MobilityNetworkSizeHere("shp", bpos) 1793 if waterNet ~= nil then 1794 return waterName 1795 else 1796 return landName 1797 end 1798end 1799 1800local function RezBot1() 1801 local unitName 1802 if ai.mySide == CORESideName then 1803 unitName = "cornecro" 1804 else 1805 unitName = "armrectr" 1806 end 1807 return BuildWithLimitedNumber(unitName, 1) 1808end 1809 1810local function ScoutBot() 1811 local unitName 1812 if ai.mySide == CORESideName then 1813 return DummyUnitName 1814 else 1815 unitName = "armflea" 1816 end 1817 return BuildWithLimitedNumber(unitName, 1) 1818end 1819 1820local function ScoutVeh() 1821 local unitName 1822 if ai.mySide == CORESideName then 1823 unitName = "corfav" 1824 else 1825 unitName = "armfav" 1826 end 1827 return BuildWithLimitedNumber(unitName, 1) 1828end 1829 1830local function ScoutAir() 1831 local unitName 1832 if ai.mySide == CORESideName then 1833 unitName = "corfink" 1834 else 1835 unitName = "armpeep" 1836 end 1837 return BuildWithLimitedNumber(unitName, 1) 1838end 1839 1840local function ScoutShip() 1841 local unitName 1842 if ai.mySide == CORESideName then 1843 unitName = "corpt" 1844 else 1845 unitName = "armpt" 1846 end 1847 local scout = BuildWithLimitedNumber(unitName, 1) 1848 if scout == DummyUnitName then 1849 return BuildAAIfNeeded(unitName) 1850 else 1851 return unitName 1852 end 1853end 1854 1855local function ScoutAdvAir() 1856 local unitName 1857 if ai.mySide == CORESideName then 1858 unitName = "corawac" 1859 else 1860 unitName = "armawac" 1861 end 1862 return BuildWithLimitedNumber(unitName, 1) 1863end 1864 1865local function ScoutSeaAir() 1866 local unitName 1867 if ai.mySide == CORESideName then 1868 unitName = "corhunt" 1869 else 1870 unitName = "armsehak" 1871 end 1872 return BuildWithLimitedNumber(unitName, 1) 1873end 1874 1875local function Lvl2BotAssist() 1876 if ai.mySide == CORESideName then 1877 return "corfast" 1878 else 1879 return "armfark" 1880 end 1881end 1882 1883local function Lvl2VehAssist() 1884 if ai.mySide == CORESideName then 1885 return DummyUnitName 1886 else 1887 return "consul" 1888 end 1889end 1890 1891local function Lvl2ShipAssist() 1892 if ai.mySide == CORESideName then 1893 return "cormls" 1894 else 1895 return "armmls" 1896 end 1897end 1898 1899-- end of functions 1900 1901 1902-- mobile construction units: 1903 1904local anyCommander = { 1905 CheckMySideIfNeeded, 1906 BuildMex, 1907 BuildAppropriateFactory, 1908 WindSolar, 1909 BuildLLT, 1910 BuildRadar, 1911 BuildLightAA, 1912 DoSomethingForTheEconomy, 1913 TidalIfTidal, 1914 BuildPopTorpedo, 1915 BuildSonar, 1916} 1917 1918local anyConUnit = { 1919 BuildAppropriateFactory, 1920 NanoTurret, 1921 BuildLLT, 1922 BuildSpecialLT, 1923 BuildMediumAA, 1924 BuildRadar, 1925 BuildLvl1Jammer, 1926 WindSolar, 1927 BuildGeo, 1928 SolarAdv, 1929 BuildHLT, 1930 BuildLvl1Plasma, 1931 DoSomethingForTheEconomy, 1932 BuildHeavyishAA, 1933 BuildMex, 1934} 1935 1936local anyConAmphibious = { 1937 BuildGeo, 1938 BuildSpecialLT, 1939 BuildMediumAA, 1940 BuildRadar, 1941 BuildLvl1Jammer, 1942 WindSolar, 1943 SolarAdv, 1944 FactoryOrNano, 1945 BuildHLT, 1946 BuildLvl1Plasma, 1947 DoSomethingForTheEconomy, 1948 BuildHeavyishAA, 1949 BuildMex, 1950 BuildPopTorpedo, 1951 BuildFloatLightAA, 1952 BuildSonar, 1953 BuildFloatRadar, 1954 TidalIfTidal, 1955 BuildFloatHLT, 1956 DoSomethingForTheEconomy, 1957} 1958 1959local anyConShip = { 1960 BuildUWMex, 1961 BuildFloatLightAA, 1962 BuildSonar, 1963 BuildLightTorpedo, 1964 BuildFloatRadar, 1965 TidalIfTidal, 1966 BuildAppropriateFactory, 1967 BuildFloatHLT, 1968 DoSomethingForTheEconomy, 1969} 1970 1971local anyAdvConUnit = { 1972 BuildAppropriateFactory, 1973 BuildFusion, 1974 BuildNukeIfNeeded, 1975 BuildAdvancedRadar, 1976 BuildHeavyPlasma, 1977 BuildAntinuke, 1978 BuildLvl2PopUp, 1979 BuildHeavyAA, 1980 BuildLvl2Plasma, 1981 BuildTachyon, 1982 -- BuildTacticalNuke, 1983 BuildExtraHeavyAA, 1984 BuildLvl2Jammer, 1985 BuildMohoGeo, 1986 BuildMohoMex, 1987 -- DoSomethingAdvancedForTheEconomy, 1988} 1989 1990local anyConSeaplane = { 1991 BuildUWMohoMex, 1992 BuildFloatHeavyAA, 1993 BuildUWFusion, 1994 BuildAdvancedSonar, 1995 BuildHeavyTorpedo, 1996 BuildAppropriateFactory, 1997 -- DoSomethingAdvancedForTheEconomy, 1998} 1999 2000local anyAdvConSub = { 2001 BuildUWMohoMex, 2002 BuildFloatHeavyAA, 2003 BuildUWFusion, 2004 BuildAdvancedSonar, 2005 BuildHeavyTorpedo, 2006 -- DoSomethingAdvancedForTheEconomy, 2007} 2008 2009local anyNavalEngineer = { 2010 BuildFloatHLT, 2011 BuildFloatLightAA, 2012 BuildAppropriateFactory, 2013 Lvl1ShipBattle, 2014 BuildFloatRadar, 2015 TidalIfTidal, 2016 BuildUWMex, 2017 BuildSonar, 2018 Lvl1ShipRaider, 2019 Conship, 2020 ScoutShip, 2021 BuildLightTorpedo, 2022} 2023 2024local anyCombatEngineer = { 2025 BuildAppropriateFactory, 2026 NanoTurret, 2027 Solar, 2028 BuildMediumAA, 2029 BuildAdvancedRadar, 2030 BuildLvl2Jammer, 2031 BuildLvl2PopUp, 2032 BuildHeavyAA, 2033 BuildSpecialLTOnly, 2034 BuildLvl2Plasma, 2035 ConCoreBotArmVehicle, 2036 Lvl2BotCorRaiderArmBattle, 2037 Lvl1AABot, 2038 ConShip, 2039 Lvl1ShipDestroyerOnly, 2040 BuildMex, 2041} 2042 2043 2044-- factories: 2045 2046local anyLvl1AirPlant = { 2047 ScoutAir, 2048 Lvl1Bomber, 2049 Lvl1AirRaider, 2050 ConAir, 2051 Lvl1Fighter, 2052} 2053 2054local anyLvl1VehPlant = { 2055 ScoutVeh, 2056 ConVehicle, 2057 Lvl1VehRaider, 2058 Lvl1VehBattle, 2059 Lvl1AAVeh, 2060 Lvl1VehArty, 2061 Lvl1VehBreakthrough, 2062} 2063 2064local anyLvl1BotLab = { 2065 ScoutBot, 2066 ConBot, 2067 Lvl1BotRaider, 2068 Lvl1BotBattle, 2069 Lvl1AABot, 2070 Lvl1BotBreakthrough, 2071 RezBot1, 2072} 2073 2074local anyLvl1ShipYard = { 2075 ScoutShip, 2076 ConShip, 2077 Lvl1ShipBattle, 2078 Lvl1ShipRaider, 2079} 2080 2081local anyHoverPlatform = { 2082 HoverRaider, 2083 ConHover, 2084 HoverBattle, 2085 HoverBreakthrough, 2086 HoverMerl, 2087 AAHover, 2088} 2089 2090local anyAmphibiousComplex = { 2091 AmphibiousRaider, 2092 ConVehicleAmphibious, 2093 AmphibiousBattle, 2094 Lvl1ShipRaider, 2095 Lvl1AABot, 2096 Lvl2AABot, 2097} 2098 2099local anyLvl2VehPlant = { 2100 Lvl2VehRaider, 2101 ConAdvVehicle, 2102 Lvl2VehBattle, 2103 Lvl2VehBreakthrough, 2104 Lvl2VehArty, 2105 Lvl2VehMerl, 2106 Lvl2AAVeh, 2107 Lvl2VehAssist, 2108} 2109 2110local anyLvl2BotLab = { 2111 Lvl2BotRaider, 2112 ConAdvBot, 2113 Lvl2BotBattle, 2114 Lvl2BotBreakthrough, 2115 Lvl2BotArty, 2116 Lvl2BotMerl, 2117 Lvl2AABot, 2118 Lvl2BotAssist, 2119} 2120 2121local anyLvl2AirPlant = { 2122 Lvl2Bomber, 2123 Lvl2TorpedoBomber, 2124 ConAdvAir, 2125 ScoutAdvAir, 2126 Lvl2Fighter, 2127 Lvl2AirRaider, 2128 MegaAircraft, 2129} 2130 2131local anySeaplanePlatform = { 2132 SeaBomber, 2133 SeaTorpedoBomber, 2134 ConSeaAir, 2135 ScoutSeaAir, 2136 SeaFighter, 2137 SeaAirRaider, 2138} 2139 2140local anyLvl2ShipYard = { 2141 Lvl2ShipRaider, 2142 ConAdvSub, 2143 Lvl2ShipBattle, 2144 Lvl2AAShip, 2145 Lvl2ShipBreakthrough, 2146 Lvl2ShipMerl, 2147 Lvl2ShipAssist, 2148 MegaShip, 2149} 2150 2151local anyExperimental = { 2152 Lvl3Raider, 2153 Lvl3Battle, 2154 Lvl3Merl, 2155 Lvl3Arty, 2156 Lvl3Breakthrough, 2157} 2158 2159local anyOutmodedLvl1BotLab = { 2160 ConBot, 2161 RezBot1, 2162 ScoutBot, 2163 Lvl1AABot, 2164} 2165 2166local anyOutmodedLvl1VehPlant = { 2167 Lvl1VehRaiderOutmoded, 2168 ConVehicle, 2169 ScoutVeh, 2170 Lvl1AAVeh, 2171} 2172 2173local anyOutmodedLvl1AirPlant = { 2174 ConAir, 2175 ScoutAir, 2176 Lvl1Fighter, 2177} 2178 2179local anyOutmodedLvl1ShipYard = { 2180 ConShip, 2181 ScoutShip, 2182} 2183 2184local anyOutmodedLvl2BotLab = { 2185 -- Lvl2BotRaider, 2186 ConAdvBot, 2187 Lvl2AABot, 2188 Lvl2BotAssist, 2189} 2190 2191local anyOutmodedLvl2VehPlant = { 2192 -- Lvl2VehRaider, 2193 Lvl2VehAssist, 2194 ConAdvVehicle, 2195 Lvl2AAVeh, 2196} 2197 2198local anyLvl1VehPlantForWater = { 2199 ScoutVeh, 2200 AmphibiousRaider, 2201 ConVehicleAmphibious, 2202 Lvl1AAVeh, 2203} 2204 2205-- use these if it's a watery map 2206wateryTaskqueues = { 2207 armvp = anyLvl1VehPlantForWater, 2208 corvp = anyLvl1VehPlantForWater, 2209} 2210 2211-- fall back to these when a level 2 factory exists 2212outmodedTaskqueues = { 2213 corlab = anyOutmodedLvl1BotLab, 2214 armlab = anyOutmodedLvl1BotLab, 2215 corvp = anyOutmodedLvl1VehPlant, 2216 armvp = anyOutmodedLvl1VehPlant, 2217 corap = anyOutmodedLvl1AirPlant, 2218 armap = anyOutmodedLvl1AirPlant, 2219 corsy = anyOutmodedLvl1ShipYard, 2220 armsy = anyOutmodedLvl1ShipYard, 2221 coralab = anyOutmodedLvl2BotLab, 2222 armalab = anyOutmodedLvl2BotLab, 2223 coravp = anyOutmodedLvl2VehPlant, 2224 armavp = anyOutmodedLvl2VehPlant, 2225} 2226 2227-- finally, the taskqueue definitions 2228taskqueues = { 2229 corcom = anyCommander, 2230 armcom = anyCommander, 2231 corcv = anyConUnit, 2232 armcv = anyConUnit, 2233 corck = anyConUnit, 2234 armck = anyConUnit, 2235 cormuskrat = anyConAmphibious, 2236 armbeaver = anyConAmphibious, 2237 corch = anyConAmphibious, 2238 armch = anyConAmphibious, 2239 corca = anyConUnit, 2240 armca = anyConUnit, 2241 corack = anyAdvConUnit, 2242 armack = anyAdvConUnit, 2243 coracv = anyAdvConUnit, 2244 armacv = anyAdvConUnit, 2245 coraca = anyAdvConUnit, 2246 armaca = anyAdvConUnit, 2247 corcsa = anyConSeaplane, 2248 armcsa = anyConSeaplane, 2249 corcs = anyConShip, 2250 armcs = anyConShip, 2251 coracsub = anyAdvConSub, 2252 armacsub = anyAdvConSub, 2253 cormls = anyNavalEngineer, 2254 armmls = anyNavalEngineer, 2255 consul = anyCombatEngineer, 2256 corfast = anyCombatEngineer, 2257 corap = anyLvl1AirPlant, 2258 armap = anyLvl1AirPlant, 2259 corlab = anyLvl1BotLab, 2260 armlab = anyLvl1BotLab, 2261 corvp = anyLvl1VehPlant, 2262 armvp = anyLvl1VehPlant, 2263 coralab = anyLvl2BotLab, 2264 coravp = anyLvl2VehPlant, 2265 corhp = anyHoverPlatform, 2266 armhp = anyHoverPlatform, 2267 corfhp = anyHoverPlatform, 2268 armfhp = anyHoverPlatform, 2269 csubpen = anyAmphibiousComplex, 2270 asubpen = anyAmphibiousComplex, 2271 armalab = anyLvl2BotLab, 2272 armavp = anyLvl2VehPlant, 2273 coraap = anyLvl2AirPlant, 2274 armaap = anyLvl2AirPlant, 2275 corplat = anySeaplanePlatform, 2276 armplat = anySeaplanePlatform, 2277 corsy = anyLvl1ShipYard, 2278 armsy = anyLvl1ShipYard, 2279 corasy = anyLvl2ShipYard, 2280 armasy = anyLvl2ShipYard, 2281 corgant = anyExperimental, 2282 armshltx = anyExperimental, 2283 armfark = { 2284 WindSolar, 2285 BuildMex, 2286 } 2287}