@supalosa/chronodivide-bot 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/.env.template +5 -0
  2. package/README.md +54 -47
  3. package/dist/bot/bot.js +14 -30
  4. package/dist/bot/bot.js.map +1 -1
  5. package/dist/bot/logic/awareness.js +13 -8
  6. package/dist/bot/logic/awareness.js.map +1 -1
  7. package/dist/bot/logic/awarenessImpl.js +132 -0
  8. package/dist/bot/logic/awarenessImpl.js.map +1 -0
  9. package/dist/bot/logic/building/ArtilleryUnit.js +2 -29
  10. package/dist/bot/logic/building/ArtilleryUnit.js.map +1 -0
  11. package/dist/bot/logic/building/antiAirStaticDefence.js +43 -0
  12. package/dist/bot/logic/building/antiAirStaticDefence.js.map +1 -0
  13. package/dist/bot/logic/building/antiGroundStaticDefence.js +7 -4
  14. package/dist/bot/logic/building/antiGroundStaticDefence.js.map +1 -1
  15. package/dist/bot/logic/building/basicAirUnit.js +2 -23
  16. package/dist/bot/logic/building/basicAirUnit.js.map +1 -1
  17. package/dist/bot/logic/building/basicBuilding.js +3 -2
  18. package/dist/bot/logic/building/basicBuilding.js.map +1 -1
  19. package/dist/bot/logic/building/basicGroundUnit.js +2 -43
  20. package/dist/bot/logic/building/basicGroundUnit.js.map +1 -1
  21. package/dist/bot/logic/building/building.js +55 -11
  22. package/dist/bot/logic/building/building.js.map +1 -0
  23. package/dist/bot/logic/building/buildingRules.js +10 -5
  24. package/dist/bot/logic/building/buildingRules.js.map +1 -1
  25. package/dist/bot/logic/building/common.js +19 -0
  26. package/dist/bot/logic/building/common.js.map +1 -0
  27. package/dist/bot/logic/building/harvester.js +2 -1
  28. package/dist/bot/logic/building/harvester.js.map +1 -1
  29. package/dist/bot/logic/building/queueController.js +69 -42
  30. package/dist/bot/logic/building/queueController.js.map +1 -1
  31. package/dist/bot/logic/common/utils.js +21 -0
  32. package/dist/bot/logic/common/utils.js.map +1 -1
  33. package/dist/bot/logic/composition/alliedCompositions.js +13 -0
  34. package/dist/bot/logic/composition/alliedCompositions.js.map +1 -0
  35. package/dist/bot/logic/composition/common.js +2 -0
  36. package/dist/bot/logic/composition/common.js.map +1 -0
  37. package/dist/bot/logic/composition/sovietCompositions.js +13 -0
  38. package/dist/bot/logic/composition/sovietCompositions.js.map +1 -0
  39. package/dist/bot/logic/mission/actionBatcher.js +92 -0
  40. package/dist/bot/logic/mission/actionBatcher.js.map +1 -0
  41. package/dist/bot/logic/mission/behaviours/combatSquad.js +124 -0
  42. package/dist/bot/logic/mission/behaviours/combatSquad.js.map +1 -0
  43. package/dist/bot/logic/mission/behaviours/common.js +58 -0
  44. package/dist/bot/logic/mission/behaviours/common.js.map +1 -0
  45. package/dist/bot/logic/mission/behaviours/engineerSquad.js +39 -0
  46. package/dist/bot/logic/mission/behaviours/engineerSquad.js.map +1 -0
  47. package/dist/bot/logic/mission/behaviours/expansionSquad.js +46 -0
  48. package/dist/bot/logic/mission/behaviours/expansionSquad.js.map +1 -0
  49. package/dist/bot/logic/mission/behaviours/retreatSquad.js +31 -0
  50. package/dist/bot/logic/mission/behaviours/retreatSquad.js.map +1 -0
  51. package/{src/bot/logic/squad/behaviours/scoutingSquad.ts → dist/bot/logic/mission/behaviours/scoutingSquad.js} +27 -51
  52. package/dist/bot/logic/mission/behaviours/scoutingSquad.js.map +1 -0
  53. package/dist/bot/logic/mission/mission.js +91 -19
  54. package/dist/bot/logic/mission/mission.js.map +1 -1
  55. package/dist/bot/logic/mission/missionController.js +262 -21
  56. package/dist/bot/logic/mission/missionController.js.map +1 -1
  57. package/dist/bot/logic/mission/missions/attackMission.js +113 -39
  58. package/dist/bot/logic/mission/missions/attackMission.js.map +1 -1
  59. package/dist/bot/logic/mission/missions/basicMission.js +13 -0
  60. package/dist/bot/logic/mission/missions/basicMission.js.map +1 -0
  61. package/dist/bot/logic/mission/missions/defenceMission.js +43 -28
  62. package/dist/bot/logic/mission/missions/defenceMission.js.map +1 -1
  63. package/dist/bot/logic/mission/missions/engineerMission.js +37 -7
  64. package/dist/bot/logic/mission/missions/engineerMission.js.map +1 -1
  65. package/dist/bot/logic/mission/missions/expansionMission.js +42 -6
  66. package/dist/bot/logic/mission/missions/expansionMission.js.map +1 -1
  67. package/dist/bot/logic/mission/missions/missionBehaviour.js +2 -0
  68. package/dist/bot/logic/mission/missions/missionBehaviour.js.map +1 -0
  69. package/dist/bot/logic/mission/missions/retreatMission.js +31 -5
  70. package/dist/bot/logic/mission/missions/retreatMission.js.map +1 -1
  71. package/dist/bot/logic/mission/missions/scoutingMission.js +103 -6
  72. package/dist/bot/logic/mission/missions/scoutingMission.js.map +1 -1
  73. package/dist/bot/logic/mission/missions/squads/combatSquad.js +116 -0
  74. package/dist/bot/logic/mission/missions/squads/combatSquad.js.map +1 -0
  75. package/dist/bot/logic/mission/missions/squads/common.js +58 -0
  76. package/dist/bot/logic/mission/missions/squads/common.js.map +1 -0
  77. package/dist/bot/logic/mission/missions/squads/squad.js +2 -0
  78. package/dist/bot/logic/mission/missions/squads/squad.js.map +1 -0
  79. package/dist/bot/logic/squad/behaviours/attackSquad.js +63 -56
  80. package/dist/bot/logic/squad/behaviours/combatSquad.js +21 -25
  81. package/dist/bot/logic/squad/behaviours/combatSquad.js.map +1 -1
  82. package/dist/bot/logic/squad/behaviours/common.js +11 -26
  83. package/dist/bot/logic/squad/behaviours/common.js.map +1 -1
  84. package/dist/bot/logic/squad/behaviours/defenceSquad.js +15 -2
  85. package/dist/bot/logic/squad/behaviours/engineerSquad.js +2 -4
  86. package/dist/bot/logic/squad/behaviours/engineerSquad.js.map +1 -1
  87. package/dist/bot/logic/squad/behaviours/expansionSquad.js +2 -4
  88. package/dist/bot/logic/squad/behaviours/expansionSquad.js.map +1 -1
  89. package/dist/bot/logic/squad/behaviours/retreatSquad.js +1 -4
  90. package/dist/bot/logic/squad/behaviours/retreatSquad.js.map +1 -1
  91. package/dist/bot/logic/squad/behaviours/scoutingSquad.js +18 -25
  92. package/dist/bot/logic/squad/behaviours/scoutingSquad.js.map +1 -1
  93. package/dist/bot/logic/squad/squad.js +10 -10
  94. package/dist/bot/logic/squad/squad.js.map +1 -1
  95. package/dist/bot/logic/squad/squadBehaviour.js.map +1 -1
  96. package/dist/bot/logic/squad/squadController.js +5 -17
  97. package/dist/bot/logic/squad/squadController.js.map +1 -1
  98. package/dist/bot/logic/threat/threatCalculator.js +5 -5
  99. package/dist/bot/logic/threat/threatCalculator.js.map +1 -1
  100. package/dist/exampleBot.js +45 -18
  101. package/dist/exampleBot.js.map +1 -1
  102. package/package.json +5 -4
  103. package/src/bot/bot.ts +19 -45
  104. package/src/bot/logic/awareness.ts +34 -22
  105. package/src/bot/logic/building/antiAirStaticDefence.ts +64 -0
  106. package/src/bot/logic/building/antiGroundStaticDefence.ts +7 -20
  107. package/src/bot/logic/building/artilleryUnit.ts +2 -28
  108. package/src/bot/logic/building/basicAirUnit.ts +2 -33
  109. package/src/bot/logic/building/basicBuilding.ts +8 -6
  110. package/src/bot/logic/building/basicGroundUnit.ts +2 -46
  111. package/src/bot/logic/building/buildingRules.ts +15 -9
  112. package/src/bot/logic/building/common.ts +23 -0
  113. package/src/bot/logic/building/harvester.ts +2 -1
  114. package/src/bot/logic/building/queueController.ts +98 -43
  115. package/src/bot/logic/common/utils.ts +28 -0
  116. package/src/bot/logic/composition/alliedCompositions.ts +22 -0
  117. package/src/bot/logic/composition/common.ts +3 -0
  118. package/src/bot/logic/composition/sovietCompositions.ts +21 -0
  119. package/src/bot/logic/{squad/behaviours → mission}/actionBatcher.ts +66 -7
  120. package/src/bot/logic/mission/mission.ts +186 -37
  121. package/src/bot/logic/mission/missionController.ts +340 -31
  122. package/src/bot/logic/mission/missionFactories.ts +3 -3
  123. package/src/bot/logic/mission/missions/attackMission.ts +181 -44
  124. package/src/bot/logic/mission/missions/defenceMission.ts +72 -45
  125. package/src/bot/logic/mission/missions/engineerMission.ts +67 -15
  126. package/src/bot/logic/mission/missions/expansionMission.ts +67 -14
  127. package/src/bot/logic/mission/missions/retreatMission.ts +50 -6
  128. package/src/bot/logic/mission/missions/scoutingMission.ts +138 -14
  129. package/src/bot/logic/{squad/behaviours → mission/missions/squads}/combatSquad.ts +56 -33
  130. package/src/bot/logic/{squad/behaviours → mission/missions/squads}/common.ts +11 -17
  131. package/src/bot/logic/mission/missions/squads/squad.ts +19 -0
  132. package/src/bot/logic/threat/threat.ts +15 -15
  133. package/src/bot/logic/threat/threatCalculator.ts +10 -10
  134. package/src/exampleBot.ts +50 -24
  135. package/.prettierrc +0 -5
  136. package/TODO.md +0 -15
  137. package/dist/bot/logic/building/artilleryUnit.js.map +0 -1
  138. package/dist/bot/logic/building/massedAntiGroundUnit.js +0 -20
  139. package/dist/bot/logic/building/queues.js +0 -19
  140. package/dist/bot/logic/knowledge.js +0 -1
  141. package/dist/bot/logic/mission/basicMission.js +0 -26
  142. package/dist/bot/logic/mission/expansionMission.js +0 -32
  143. package/dist/bot/logic/squad/behaviours/actionBatcher.js +0 -36
  144. package/dist/bot/logic/squad/behaviours/actionBatcher.js.map +0 -1
  145. package/dist/bot/logic/squad/behaviours/squadExpansion.js +0 -31
  146. package/dist/bot/logic/squad/behaviours/squadScouters.js +0 -8
  147. package/rules.ini +0 -23126
  148. package/src/bot/logic/mission/missions/oneTimeMission.ts +0 -33
  149. package/src/bot/logic/squad/behaviours/engineerSquad.ts +0 -58
  150. package/src/bot/logic/squad/behaviours/expansionSquad.ts +0 -64
  151. package/src/bot/logic/squad/behaviours/retreatSquad.ts +0 -50
  152. package/src/bot/logic/squad/squad.ts +0 -165
  153. package/src/bot/logic/squad/squadBehaviour.ts +0 -66
  154. package/src/bot/logic/squad/squadBehaviours.ts +0 -8
  155. package/src/bot/logic/squad/squadController.ts +0 -271
@@ -1,3 +1,4 @@
1
+ import "dotenv/config";
1
2
  import { cdapi } from "@chronodivide/game-api";
2
3
  import { SupalosaBot } from "./bot/bot.js";
3
4
  async function main() {
@@ -14,6 +15,19 @@ async function main() {
14
15
 
15
16
  Other maps:
16
17
  mp03t4 large map, no oil derricks
18
+ mp02t2.map,mp06t2.map,mp11t2.map,mp08t2.map,mp21s2.map,mp14t2.map,mp29u2.map,mp31s2.map,mp18s3.map,mp09t3.map,mp01t4.map,mp03t4.map,mp05t4.map,mp10s4.map,mp12s4.map,mp13s4.map,mp19t4.map,
19
+ mp15s4.map,mp16s4.map,mp23t4.map,mp33u4.map,mp34u4.map,mp17t6.map,mp20t6.map,mp25t6.map,mp26s6.map,mp30s6.map,mp22s8.map,mp27t8.map,mp32s8.map,mp06mw.map,mp08mw.map,mp14mw.map,mp29mw.map,
20
+ mp05mw.map,mp13mw.map,mp15mw.map,mp16mw.map,mp23mw.map,mp17mw.map,mp25mw.map,mp30mw.map,mp22mw.map,mp27mw.map,mp32mw.map,mp09du.map,mp01du.map,mp05du.map,mp13du.map,mp15du.map,mp18du.map,
21
+ mp24du.map,mp17du.map,mp25du.map,mp27du.map,mp32du.map,c1m1a.map,c1m1b.map,c1m1c.map,c1m2a.map,c1m2b.map,c1m2c.map,c1m3a.map,c1m3b.map,c1m3c.map,c1m4a.map,c1m4b.map,c1m4c.map,c1m5a.map,
22
+ c1m5b.map,c1m5c.map,c2m1a.map,c2m1b.map,c2m1c.map,c2m2a.map,c2m2b.map,c2m2c.map,c2m3a.map,c2m3b.map,c2m3c.map,c2m4a.map,c2m4b.map,c2m4c.map,c2m5a.map,c2m5b.map,c2m5c.map,c3m1a.map,c3m1b.map,
23
+ c3m1c.map,c3m2a.map,c3m2b.map,c3m2c.map,c3m3a.map,c3m3b.map,c3m3c.map,c3m4a.map,c3m4b.map,c3m4c.map,c3m5a.map,c3m5b.map,c3m5c.map,c4m1a.map,c4m1b.map,c4m1c.map,c4m2a.map,c4m2b.map,c4m2c.map,
24
+ c4m3a.map,c4m3b.map,c4m3c.map,c4m4a.map,c4m4b.map,c4m4c.map,c4m5a.map,c4m5b.map,c4m5c.map,c5m1a.map,c5m1b.map,c5m1c.map,c5m2a.map,c5m2b.map,c5m2c.map,c5m3a.map,c5m3b.map,c5m3c.map,c5m4a.map,
25
+ c5m4b.map,c5m4c.map,c5m5a.map,c5m5b.map,c5m5c.map,tn01t2.map,tn01mw.map,tn04t2.map,tn04mw.map,tn02s4.map,tn02mw.map,amazon01.map,eb1.map,eb2.map,eb3.map,eb4.map,eb5.map,invasion.map,arena.map,
26
+ barrel.map,bayopigs.map,bermuda.map,break.map,carville.map,deadman.map,death.map,disaster.map,dustbowl.map,goldst.map,grinder.map,hailmary.map,hills.map,kaliforn.map,killer.map,lostlake.map,
27
+ newhghts.map,oceansid.map,pacific.map,potomac.map,powdrkeg.map,rockets.map,roulette.map,round.map,seaofiso.map,shrapnel.map,tanyas.map,tower.map,tsunami.map,valley.map,xmas.map,yuriplot.map,
28
+ cavernsofsiberia.map,countryswingfixed.map,4_country_swing_le_v2.map,dorado_descent_yr_port.mpr,dryheat.map,dunepatrolremake.map,heckbvb.map,heckcorners.map,heckgolden.mpr,heckcorners_b.map,
29
+ heckcorners_b_golden.map,hecklvl.map,heckrvr.map,hecktvt.map,isleland.map,jungleofvietnam.map,2_malibu_cliffs_le.map,mojosprt.map,4_montana_dmz_le.map,6_near_ore_far.map,8_near_ore_far.map,
30
+ offensedefense.map,ore2_startfixed.map,rekoool_fast_6players.mpr,rekoool_fast_8players.mpr,riverram.map,tourofegypt.map,unrepent.map,sinkswim_yr_port.map
17
31
  */
18
32
  const mapName = "mp03t4.map";
19
33
  // Bot names must be unique in online mode
@@ -38,35 +52,48 @@ async function main() {
38
52
  7=Confederation -> Cuba
39
53
  8=Russians
40
54
  */
55
+ const baseSettings = {
56
+ buildOffAlly: false,
57
+ cratesAppear: false,
58
+ credits: 10000,
59
+ gameMode: cdapi.getAvailableGameModes(mapName)[0],
60
+ gameSpeed: 6,
61
+ mapName,
62
+ mcvRepacks: true,
63
+ shortGame: true,
64
+ superWeapons: false,
65
+ unitCount: 0,
66
+ };
41
67
  const onlineSettings = {
68
+ ...baseSettings,
42
69
  online: true,
43
70
  serverUrl: process.env.SERVER_URL,
44
71
  clientUrl: process.env.CLIENT_URL,
45
- agents: [new SupalosaBot(firstBotName, "Americans"), { name: secondBotName, country: "French" }],
72
+ agents: [
73
+ new SupalosaBot(process.env.ONLINE_BOT_NAME ?? firstBotName, "Americans"),
74
+ { name: process.env.PLAYER_NAME ?? secondBotName, country: "French" },
75
+ ],
76
+ botPassword: process.env.ONLINE_BOT_PASSWORD ?? "default",
46
77
  };
47
- const debugBot = new SupalosaBot(secondBotName, "Russians", [secondBotName], true);
48
- debugBot.setDebugMode(true);
49
- const offlineSettings = {
78
+ const offlineSettings1v1 = {
79
+ ...baseSettings,
80
+ online: false,
81
+ agents: [
82
+ new SupalosaBot(firstBotName, "French", [], true).setDebugMode(true),
83
+ new SupalosaBot(secondBotName, "Russians", [], false),
84
+ ],
85
+ };
86
+ const offlineSettings2v2 = {
87
+ ...baseSettings,
88
+ online: false,
50
89
  agents: [
51
90
  new SupalosaBot(firstBotName, "French", [firstBotName], false),
52
- debugBot,
91
+ new SupalosaBot(secondBotName, "Russians", [firstBotName], true).setDebugMode(true),
53
92
  new SupalosaBot(thirdBotName, "Russians", [fourthBotName], false),
54
93
  new SupalosaBot(fourthBotName, "French", [thirdBotName], false),
55
94
  ],
56
95
  };
57
- const game = await cdapi.createGame({
58
- ...offlineSettings,
59
- buildOffAlly: false,
60
- cratesAppear: false,
61
- credits: 10000,
62
- gameMode: cdapi.getAvailableGameModes(mapName)[0],
63
- gameSpeed: 6,
64
- mapName,
65
- mcvRepacks: true,
66
- shortGame: true,
67
- superWeapons: false,
68
- unitCount: 0,
69
- });
96
+ const game = await cdapi.createGame(process.env.ONLINE_MATCH ? onlineSettings : offlineSettings1v1);
70
97
  while (!game.isFinished()) {
71
98
  await game.update();
72
99
  }
@@ -1 +1 @@
1
- {"version":3,"file":"exampleBot.js","sourceRoot":"","sources":["../src/exampleBot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,KAAK,UAAU,IAAI;IACf;;;;;;;;;;;;;MAaE;IACF,MAAM,OAAO,GAAG,YAAY,CAAC;IAC7B,0CAA0C;IAC1C,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,YAAY,GAAG,MAAM,SAAS,EAAE,CAAC;IACvC,MAAM,aAAa,GAAG,MAAM,SAAS,EAAE,CAAC;IACxC,MAAM,YAAY,GAAG,OAAO,SAAS,EAAE,CAAC;IACxC,MAAM,aAAa,GAAG,UAAU,SAAS,EAAE,CAAC;IAE5C,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC;IAE9C,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,UAAW,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,UAAW,CAAC,CAAC;IAEtD;;;;;;;;;;;;MAYE;IAEF,MAAM,cAAc,GAAG;QACnB,MAAM,EAAE,IAAY;QACpB,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,UAAW;QAClC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,UAAW;QAClC,MAAM,EAAE,CAAC,IAAI,WAAW,CAAC,YAAY,EAAE,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,CAG9F;KACJ,CAAC;IAEF,MAAM,QAAQ,GAAG,IAAI,WAAW,CAAC,aAAa,EAAE,UAAU,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC,CAAC;IACnF,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAE5B,MAAM,eAAe,GAAG;QACpB,MAAM,EAAE;YACJ,IAAI,WAAW,CAAC,YAAY,EAAE,QAAQ,EAAE,CAAC,YAAY,CAAC,EAAE,KAAK,CAAC;YAC9D,QAAQ;YACR,IAAI,WAAW,CAAC,YAAY,EAAE,UAAU,EAAE,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC;YACjE,IAAI,WAAW,CAAC,aAAa,EAAE,QAAQ,EAAE,CAAC,YAAY,CAAC,EAAE,KAAK,CAAC;SAClE;KACJ,CAAC;IAEF,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC;QAChC,GAAG,eAAe;QAClB,YAAY,EAAE,KAAK;QACnB,YAAY,EAAE,KAAK;QACnB,OAAO,EAAE,KAAK;QACd,QAAQ,EAAE,KAAK,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACjD,SAAS,EAAE,CAAC;QACZ,OAAO;QACP,UAAU,EAAE,IAAI;QAChB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,KAAK;QACnB,SAAS,EAAE,CAAC;KACf,CAAC,CAAC;IACH,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE;QACvB,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;KACvB;IAED,IAAI,CAAC,UAAU,EAAE,CAAC;IAClB,IAAI,CAAC,OAAO,EAAE,CAAC;AACnB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACf,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"exampleBot.js","sourceRoot":"","sources":["../src/exampleBot.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supalosa/chronodivide-bot",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "Example bot for Chrono Divide",
5
5
  "repository": "https://github.com/Supalosa/supalosa-chronodivide-bot",
6
6
  "main": "dist/exampleBot.js",
@@ -13,16 +13,17 @@
13
13
  },
14
14
  "license": "UNLICENSED",
15
15
  "devDependencies": {
16
- "@chronodivide/game-api": "^0.49.0",
16
+ "@chronodivide/game-api": "^0.50.1",
17
17
  "@types/node": "^14.17.32",
18
18
  "prettier": "3.0.3",
19
19
  "typescript": "^4.3.5"
20
20
  },
21
21
  "peerDependencies": {
22
- "@chronodivide/game-api": "^0.49.0"
22
+ "@chronodivide/game-api": "^0.50.1"
23
23
  },
24
24
  "dependencies": {
25
25
  "@datastructures-js/priority-queue": "^6.3.0",
26
- "@timohausmann/quadtree-ts": "2.2.2"
26
+ "@timohausmann/quadtree-ts": "2.2.2",
27
+ "dotenv": "^16.3.1"
27
28
  }
28
29
  }
package/src/bot/bot.ts CHANGED
@@ -1,19 +1,9 @@
1
- import {
2
- ApiEventType,
3
- Bot,
4
- GameApi,
5
- ApiEvent,
6
- QueueStatus,
7
- ObjectType,
8
- FactoryType,
9
- Size,
10
- } from "@chronodivide/game-api";
1
+ import { ApiEventType, Bot, GameApi, ApiEvent, ObjectType, FactoryType, Size } from "@chronodivide/game-api";
11
2
 
12
3
  import { determineMapBounds } from "./logic/map/map.js";
13
4
  import { SectorCache } from "./logic/map/sector.js";
14
5
  import { MissionController } from "./logic/mission/missionController.js";
15
- import { SquadController } from "./logic/squad/squadController.js";
16
- import { QUEUES, QueueController, queueTypeToName } from "./logic/building/queueController.js";
6
+ import { QueueController } from "./logic/building/queueController.js";
17
7
  import { MatchAwareness, MatchAwarenessImpl } from "./logic/awareness.js";
18
8
  import { formatTimeDuration } from "./logic/common/utils.js";
19
9
 
@@ -27,7 +17,6 @@ export class SupalosaBot extends Bot {
27
17
  private tickRatio?: number;
28
18
  private knownMapBounds: Size | undefined;
29
19
  private missionController: MissionController;
30
- private squadController: SquadController;
31
20
  private queueController: QueueController;
32
21
  private tickOfLastAttackOrder: number = 0;
33
22
 
@@ -41,7 +30,6 @@ export class SupalosaBot extends Bot {
41
30
  ) {
42
31
  super(name, country);
43
32
  this.missionController = new MissionController((message, sayInGame) => this.logBotStatus(message, sayInGame));
44
- this.squadController = new SquadController((message, sayInGame) => this.logBotStatus(message, sayInGame));
45
33
  this.queueController = new QueueController();
46
34
  }
47
35
 
@@ -105,6 +93,13 @@ export class SupalosaBot extends Bot {
105
93
  this.actionsApi.quitGame();
106
94
  }
107
95
 
96
+ // Mission logic every 3 ticks
97
+ if (this.gameApi.getCurrentTick() % 3 === 0) {
98
+ this.missionController.onAiUpdate(game, this.actionsApi, myPlayer, this.matchAwareness);
99
+ }
100
+
101
+ const unitTypeRequests = this.missionController.getRequestedUnitTypes();
102
+
108
103
  // Build logic.
109
104
  this.queueController.onAiUpdate(
110
105
  game,
@@ -112,18 +107,9 @@ export class SupalosaBot extends Bot {
112
107
  this.actionsApi,
113
108
  myPlayer,
114
109
  threatCache,
110
+ unitTypeRequests,
115
111
  (message) => this.logBotStatus(message),
116
112
  );
117
-
118
- // Mission logic every 6 ticks
119
- if (this.gameApi.getCurrentTick() % 6 === 0) {
120
- this.missionController.onAiUpdate(game, myPlayer, this.matchAwareness, this.squadController);
121
- }
122
-
123
- // Squad logic every 3 ticks
124
- if (this.gameApi.getCurrentTick() % 3 === 0) {
125
- this.squadController.onAiUpdate(game, this.actionsApi, myPlayer, this.matchAwareness);
126
- }
127
113
  }
128
114
  }
129
115
 
@@ -146,31 +132,19 @@ export class SupalosaBot extends Bot {
146
132
  if (!this.getDebugMode()) {
147
133
  return;
148
134
  }
149
-
135
+ // Update the global debug text.
150
136
  const myPlayer = game.getPlayerData(this.name);
151
- const queueState = QUEUES.reduce((prev, queueType) => {
152
- if (this.productionApi.getQueueData(queueType).size === 0) {
153
- return prev;
154
- }
155
- const paused = this.productionApi.getQueueData(queueType).status === QueueStatus.OnHold;
156
- return (
157
- prev +
158
- " [" +
159
- queueTypeToName(queueType) +
160
- (paused ? " PAUSED" : "") +
161
- ": " +
162
- this.productionApi.getQueueData(queueType).items.map((item) => item.rules.name + "x" + item.quantity) +
163
- "]"
164
- );
165
- }, "");
166
- let globalDebugText = `Cash: ${myPlayer.credits} | Queues: ${queueState}\n`;
167
137
  const harvesters = game.getVisibleUnits(this.name, "self", (r) => r.harvester).length;
168
- globalDebugText += `Harvesters: ${harvesters}\n`;
169
- globalDebugText += this.squadController.debugSquads(this.gameApi, this.actionsApi);
170
- this.missionController.logDebugOutput();
138
+
139
+ let globalDebugText = `Cash: ${myPlayer.credits} | Harvesters: ${harvesters}\n`;
140
+ globalDebugText += this.queueController.getGlobalDebugText(this.gameApi, this.productionApi);
141
+ globalDebugText += this.missionController.getGlobalDebugText(this.gameApi);
142
+ globalDebugText += this.matchAwareness?.getGlobalDebugText();
143
+
144
+ this.missionController.updateDebugText(this.actionsApi);
171
145
 
172
146
  // Tag enemy units with IDs
173
- game.getVisibleUnits(this.name, "hostile").forEach((unitId) => {
147
+ game.getVisibleUnits(this.name, "enemy").forEach((unitId) => {
174
148
  this.actionsApi.setUnitDebugText(unitId, unitId.toString());
175
149
  });
176
150
 
@@ -1,4 +1,4 @@
1
- import { GameApi, ObjectType, PlayerData, UnitData, Vector2 } from "@chronodivide/game-api";
1
+ import { GameApi, GameObjectData, ObjectType, PlayerData, UnitData, Vector2 } from "@chronodivide/game-api";
2
2
  import { SectorCache } from "./map/sector";
3
3
  import { GlobalThreat } from "./threat/threat";
4
4
  import { calculateGlobalThreat } from "./threat/threatCalculator.js";
@@ -23,10 +23,15 @@ export interface MatchAwareness {
23
23
  getSectorCache(): SectorCache;
24
24
 
25
25
  /**
26
- * Returns the enemy unit IDs in a certain radius of a point
26
+ * Returns the enemy unit IDs in a certain radius of a point.
27
+ * Warning: this may return non-combatant hostiles, such as neutral units.
27
28
  */
28
29
  getHostilesNearPoint2d(point: Vector2, radius: number): UnitPositionQuery[];
29
30
 
31
+ /**
32
+ * Returns the enemy unit IDs in a certain radius of a point.
33
+ * Warning: this may return non-combatant hostiles, such as neutral units.
34
+ */
30
35
  getHostilesNearPoint(x: number, y: number, radius: number): UnitPositionQuery[];
31
36
 
32
37
  /**
@@ -49,6 +54,8 @@ export interface MatchAwareness {
49
54
  shouldAttack(): boolean;
50
55
 
51
56
  getScoutingManager(): ScoutingManager;
57
+
58
+ getGlobalDebugText(): string | undefined;
52
59
  }
53
60
 
54
61
  const SECTORS_TO_UPDATE_PER_CYCLE = 8;
@@ -59,7 +66,7 @@ const THREAT_UPDATE_INTERVAL_TICKS = 30;
59
66
 
60
67
  type QTUnit = Circle<number>;
61
68
 
62
- const rebuildQuadtree = (quadtree: Quadtree<QTUnit>, units: UnitData[]) => {
69
+ const rebuildQuadtree = (quadtree: Quadtree<QTUnit>, units: GameObjectData[]) => {
63
70
  quadtree.clear();
64
71
  units.forEach((unit) => {
65
72
  quadtree.insert(new Circle<number>({ x: unit.tile.rx, y: unit.tile.ry, r: 1, data: unit.id }));
@@ -91,7 +98,7 @@ export class MatchAwarenessImpl implements MatchAwareness {
91
98
  const intersections = this.hostileQuadTree.retrieve(new Circle({ x: searchX, y: searchY, r: radius }));
92
99
  return intersections
93
100
  .map(({ x, y, data: unitId }) => ({ x, y, unitId: unitId! }))
94
- .filter(({ x, y }) => getDistanceBetweenPoints(new Vector2(x, y), new Vector2(searchX, searchY)) <= radius)
101
+ .filter(({ x, y }) => new Vector2(x, y).distanceTo(new Vector2(searchX, searchY)) <= radius)
95
102
  .filter(({ unitId }) => !!unitId);
96
103
  }
97
104
 
@@ -160,11 +167,14 @@ export class MatchAwarenessImpl implements MatchAwareness {
160
167
  .map((other) => other.name);
161
168
 
162
169
  // Build the quadtree, if this is too slow we should consider doing this periodically.
163
- const hostileUnitIds = game.getVisibleUnits(playerData.name, "hostile");
170
+ const hostileUnitIds = game.getVisibleUnits(playerData.name, "enemy");
164
171
  try {
165
172
  const hostileUnits = hostileUnitIds
166
- .map((id) => game.getUnitData(id))
167
- .filter((unit) => this.isHostileUnit(unit, hostilePlayerNames)) as UnitData[];
173
+ .map((id) => game.getGameObjectData(id))
174
+ .filter(
175
+ (gameObjectData: GameObjectData | undefined): gameObjectData is GameObjectData =>
176
+ gameObjectData !== undefined,
177
+ );
168
178
 
169
179
  rebuildQuadtree(this.hostileQuadTree, hostileUnits);
170
180
  } catch (err) {
@@ -178,21 +188,6 @@ export class MatchAwarenessImpl implements MatchAwareness {
178
188
  this.logger(`${Math.round(visibility * 1000.0) / 10}% of tiles visible. Calculating threat.`);
179
189
  // Update the global threat cache
180
190
  this.threatCache = calculateGlobalThreat(game, playerData, visibility);
181
- this.logger(
182
- `Threat LAND: Them ${Math.round(this.threatCache.totalOffensiveLandThreat)}, us: ${Math.round(
183
- this.threatCache.totalAvailableAntiGroundFirepower,
184
- )}.`,
185
- );
186
- this.logger(
187
- `Threat DEFENSIVE: Them ${Math.round(this.threatCache.totalDefensiveThreat)}, us: ${Math.round(
188
- this.threatCache.totalDefensivePower,
189
- )}.`,
190
- );
191
- this.logger(
192
- `Threat AIR: Them ${Math.round(this.threatCache.totalOffensiveAirThreat)}, us: ${Math.round(
193
- this.threatCache.totalAvailableAntiAirFirepower,
194
- )}.`,
195
- );
196
191
 
197
192
  // As the game approaches 2 hours, be more willing to attack. (15 ticks per second)
198
193
  const gameLengthFactor = Math.max(0, 1.0 - game.getCurrentTick() / (15 * 7200.0));
@@ -230,4 +225,21 @@ export class MatchAwarenessImpl implements MatchAwareness {
230
225
  );
231
226
  }
232
227
  }
228
+
229
+ public getGlobalDebugText(): string | undefined {
230
+ if (!this.threatCache) {
231
+ return undefined;
232
+ }
233
+ return (
234
+ `Threat LAND: Them ${Math.round(this.threatCache.totalOffensiveLandThreat)}, us: ${Math.round(
235
+ this.threatCache.totalAvailableAntiGroundFirepower,
236
+ )}.\n` +
237
+ `Threat DEFENSIVE: Them ${Math.round(this.threatCache.totalDefensiveThreat)}, us: ${Math.round(
238
+ this.threatCache.totalDefensivePower,
239
+ )}.\n` +
240
+ `Threat AIR: Them ${Math.round(this.threatCache.totalOffensiveAirThreat)}, us: ${Math.round(
241
+ this.threatCache.totalAvailableAntiAirFirepower,
242
+ )}.`
243
+ );
244
+ }
233
245
  }
@@ -0,0 +1,64 @@
1
+ import { GameApi, PlayerData, TechnoRules, Vector2 } from "@chronodivide/game-api";
2
+ import { getPointTowardsOtherPoint } from "../map/map.js";
3
+ import { GlobalThreat } from "../threat/threat.js";
4
+ import { AiBuildingRules, getDefaultPlacementLocation, numBuildingsOwnedOfType } from "./buildingRules.js";
5
+
6
+ export class AntiAirStaticDefence implements AiBuildingRules {
7
+ constructor(
8
+ private basePriority: number,
9
+ private baseAmount: number,
10
+ private airStrength: number,
11
+ ) {}
12
+
13
+ getPlacementLocation(
14
+ game: GameApi,
15
+ playerData: PlayerData,
16
+ technoRules: TechnoRules,
17
+ ): { rx: number; ry: number } | undefined {
18
+ // Prefer front towards enemy.
19
+ let startLocation = playerData.startLocation;
20
+ let players = game.getPlayers();
21
+ let enemyFacingLocationCandidates: Vector2[] = [];
22
+ for (let i = 0; i < players.length; ++i) {
23
+ let playerName = players[i];
24
+ if (playerName == playerData.name) {
25
+ continue;
26
+ }
27
+ let enemyPlayer = game.getPlayerData(playerName);
28
+ enemyFacingLocationCandidates.push(
29
+ getPointTowardsOtherPoint(game, startLocation, enemyPlayer.startLocation, 4, 16, 1.5),
30
+ );
31
+ }
32
+ let selectedLocation =
33
+ enemyFacingLocationCandidates[Math.floor(game.generateRandom() * enemyFacingLocationCandidates.length)];
34
+ return getDefaultPlacementLocation(game, playerData, selectedLocation, technoRules, false, 0);
35
+ }
36
+
37
+ getPriority(
38
+ game: GameApi,
39
+ playerData: PlayerData,
40
+ technoRules: TechnoRules,
41
+ threatCache: GlobalThreat | null,
42
+ ): number {
43
+ if (threatCache) {
44
+ let denominator = threatCache.totalAvailableAntiAirFirepower + this.airStrength;
45
+ if (threatCache.totalOffensiveAirThreat > denominator * 1.1) {
46
+ return this.basePriority * (threatCache.totalOffensiveAirThreat / Math.max(1, denominator));
47
+ } else {
48
+ return 0;
49
+ }
50
+ }
51
+ const strengthPerCost = (this.airStrength / technoRules.cost) * 1000;
52
+ const numOwned = numBuildingsOwnedOfType(game, playerData, technoRules);
53
+ return this.basePriority * (1.0 - numOwned / this.baseAmount) * strengthPerCost;
54
+ }
55
+
56
+ getMaxCount(
57
+ game: GameApi,
58
+ playerData: PlayerData,
59
+ technoRules: TechnoRules,
60
+ threatCache: GlobalThreat | null,
61
+ ): number | null {
62
+ return null;
63
+ }
64
+ }
@@ -2,12 +2,13 @@ import { GameApi, PlayerData, TechnoRules, Vector2 } from "@chronodivide/game-ap
2
2
  import { getPointTowardsOtherPoint } from "../map/map.js";
3
3
  import { GlobalThreat } from "../threat/threat.js";
4
4
  import { AiBuildingRules, getDefaultPlacementLocation, numBuildingsOwnedOfType } from "./buildingRules.js";
5
+ import { getStaticDefencePlacement } from "./common.js";
5
6
 
6
7
  export class AntiGroundStaticDefence implements AiBuildingRules {
7
8
  constructor(
8
9
  private basePriority: number,
9
10
  private baseAmount: number,
10
- private strength: number,
11
+ private groundStrength: number,
11
12
  ) {}
12
13
 
13
14
  getPlacementLocation(
@@ -15,23 +16,7 @@ export class AntiGroundStaticDefence implements AiBuildingRules {
15
16
  playerData: PlayerData,
16
17
  technoRules: TechnoRules,
17
18
  ): { rx: number; ry: number } | undefined {
18
- // Prefer front towards enemy.
19
- let startLocation = playerData.startLocation;
20
- let players = game.getPlayers();
21
- let enemyFacingLocationCandidates: Vector2[] = [];
22
- for (let i = 0; i < players.length; ++i) {
23
- let playerName = players[i];
24
- if (playerName == playerData.name) {
25
- continue;
26
- }
27
- let enemyPlayer = game.getPlayerData(playerName);
28
- enemyFacingLocationCandidates.push(
29
- getPointTowardsOtherPoint(game, startLocation, enemyPlayer.startLocation, 4, 16, 1.5),
30
- );
31
- }
32
- let selectedLocation =
33
- enemyFacingLocationCandidates[Math.floor(game.generateRandom() * enemyFacingLocationCandidates.length)];
34
- return getDefaultPlacementLocation(game, playerData, selectedLocation, technoRules, false, 0);
19
+ return getStaticDefencePlacement(game, playerData, technoRules);
35
20
  }
36
21
 
37
22
  getPriority(
@@ -43,12 +28,14 @@ export class AntiGroundStaticDefence implements AiBuildingRules {
43
28
  // If the enemy's ground power is increasing we should try to keep up.
44
29
  if (threatCache) {
45
30
  let denominator =
46
- threatCache.totalAvailableAntiGroundFirepower + threatCache.totalDefensivePower + this.strength;
31
+ threatCache.totalAvailableAntiGroundFirepower + threatCache.totalDefensivePower + this.groundStrength;
47
32
  if (threatCache.totalOffensiveLandThreat > denominator * 1.1) {
48
33
  return this.basePriority * (threatCache.totalOffensiveLandThreat / Math.max(1, denominator));
34
+ } else {
35
+ return 0;
49
36
  }
50
37
  }
51
- const strengthPerCost = (this.strength / technoRules.cost) * 1000;
38
+ const strengthPerCost = (this.groundStrength / technoRules.cost) * 1000;
52
39
  const numOwned = numBuildingsOwnedOfType(game, playerData, technoRules);
53
40
  return this.basePriority * (1.0 - numOwned / this.baseAmount) * strengthPerCost;
54
41
  }
@@ -24,34 +24,8 @@ export class ArtilleryUnit implements AiBuildingRules {
24
24
  technoRules: TechnoRules,
25
25
  threatCache: GlobalThreat | null,
26
26
  ): number {
27
- const numOwned = numBuildingsOwnedOfType(game, playerData, technoRules);
28
- let priority = this.basePriority;
29
- // If the enemy's defensive power is increasing we will start to build these.
30
- if (threatCache && threatCache.totalDefensivePower > threatCache.totalAvailableAntiGroundFirepower) {
31
- priority +=
32
- this.artilleryPower *
33
- (threatCache.totalAvailableAntiGroundFirepower / Math.max(1, threatCache.totalDefensivePower));
34
- }
35
- if (threatCache && this.antiGroundPower > 0) {
36
- // If the enemy's power is increasing we should try to keep up.
37
- if (threatCache.totalOffensiveLandThreat > threatCache.totalAvailableAntiGroundFirepower) {
38
- priority +=
39
- this.antiGroundPower *
40
- this.basePriority *
41
- (threatCache.totalOffensiveLandThreat / Math.max(1, threatCache.totalAvailableAntiGroundFirepower));
42
- } else {
43
- // But also, if our power dwarfs the enemy, keep pressing the advantage.
44
- priority +=
45
- (this.antiGroundPower *
46
- this.basePriority *
47
- GameMath.sqrt(
48
- threatCache.totalAvailableAntiGroundFirepower /
49
- Math.max(1, threatCache.totalOffensiveLandThreat + threatCache.totalDefensiveThreat),
50
- )) /
51
- (numOwned + 1);
52
- }
53
- }
54
- return priority * (1.0 - numOwned / this.baseAmount);
27
+ // Units aren't built automatically, but are instead requested by missions.
28
+ return 0;
55
29
  }
56
30
 
57
31
  getMaxCount(
@@ -24,39 +24,8 @@ export class BasicAirUnit implements AiBuildingRules {
24
24
  technoRules: TechnoRules,
25
25
  threatCache: GlobalThreat | null,
26
26
  ): number {
27
- // If the enemy's anti-air power is low we might build more.
28
- if (threatCache) {
29
- let priority = 0;
30
- if (
31
- this.antiGroundPower > 0 &&
32
- threatCache.totalOffensiveLandThreat > threatCache.totalAvailableAntiGroundFirepower
33
- ) {
34
- priority +=
35
- this.basePriority *
36
- (threatCache.totalOffensiveLandThreat / Math.max(1, threatCache.totalAvailableAntiGroundFirepower));
37
- }
38
- if (
39
- this.antiAirPower > 0 &&
40
- threatCache.totalOffensiveAirThreat > threatCache.totalAvailableAntiAirFirepower
41
- ) {
42
- priority +=
43
- this.basePriority *
44
- (threatCache.totalOffensiveAirThreat / Math.max(1, threatCache.totalAvailableAntiAirFirepower));
45
- }
46
- // sqrt so we don't build too much of one unit type.
47
- priority += Math.min(
48
- 1.0,
49
- Math.max(
50
- 1,
51
- GameMath.sqrt(
52
- threatCache.totalAvailableAirPower / Math.max(1, threatCache.totalOffensiveAntiAirThreat),
53
- ),
54
- ),
55
- );
56
- return this.baseAmount * priority;
57
- }
58
- const numOwned = numBuildingsOwnedOfType(game, playerData, technoRules);
59
- return this.basePriority * (1.0 - numOwned / this.baseAmount);
27
+ // Units aren't built automatically, but are instead requested by missions.
28
+ return 0;
60
29
  }
61
30
 
62
31
  getMaxCount(
@@ -6,13 +6,13 @@ export class BasicBuilding implements AiBuildingRules {
6
6
  constructor(
7
7
  protected basePriority: number,
8
8
  protected maxNeeded: number,
9
- protected onlyBuildWhenFloatingCreditsAmount?: number
9
+ protected onlyBuildWhenFloatingCreditsAmount?: number,
10
10
  ) {}
11
11
 
12
12
  getPlacementLocation(
13
13
  game: GameApi,
14
14
  playerData: PlayerData,
15
- technoRules: TechnoRules
15
+ technoRules: TechnoRules,
16
16
  ): { rx: number; ry: number } | undefined {
17
17
  return getDefaultPlacementLocation(game, playerData, playerData.startLocation, technoRules);
18
18
  }
@@ -21,7 +21,7 @@ export class BasicBuilding implements AiBuildingRules {
21
21
  game: GameApi,
22
22
  playerData: PlayerData,
23
23
  technoRules: TechnoRules,
24
- threatCache: GlobalThreat | null
24
+ threatCache: GlobalThreat | null,
25
25
  ): number {
26
26
  const numOwned = numBuildingsOwnedOfType(game, playerData, technoRules);
27
27
  const calcMaxCount = this.getMaxCount(game, playerData, technoRules, threatCache);
@@ -29,18 +29,20 @@ export class BasicBuilding implements AiBuildingRules {
29
29
  return -100;
30
30
  }
31
31
 
32
+ const priority = this.basePriority * (1.0 - numOwned / this.maxNeeded);
33
+
32
34
  if (this.onlyBuildWhenFloatingCreditsAmount && playerData.credits < this.onlyBuildWhenFloatingCreditsAmount) {
33
- return -100;
35
+ return priority * (playerData.credits / this.onlyBuildWhenFloatingCreditsAmount);
34
36
  }
35
37
 
36
- return this.basePriority * (1.0 - numOwned / this.maxNeeded);
38
+ return priority;
37
39
  }
38
40
 
39
41
  getMaxCount(
40
42
  game: GameApi,
41
43
  playerData: PlayerData,
42
44
  technoRules: TechnoRules,
43
- threatCache: GlobalThreat | null
45
+ threatCache: GlobalThreat | null,
44
46
  ): number | null {
45
47
  return this.maxNeeded;
46
48
  }
@@ -24,52 +24,8 @@ export class BasicGroundUnit implements AiBuildingRules {
24
24
  technoRules: TechnoRules,
25
25
  threatCache: GlobalThreat | null,
26
26
  ): number {
27
- const numOwned = numBuildingsOwnedOfType(game, playerData, technoRules);
28
- if (threatCache) {
29
- let priority = this.basePriority;
30
- if (this.antiGroundPower > 0) {
31
- // If the enemy's power is increasing we should try to keep up.
32
- if (threatCache.totalOffensiveLandThreat > threatCache.totalAvailableAntiGroundFirepower) {
33
- priority +=
34
- this.antiGroundPower *
35
- this.basePriority *
36
- (threatCache.totalOffensiveLandThreat /
37
- Math.max(1, threatCache.totalAvailableAntiGroundFirepower));
38
- } else {
39
- // But also, if our power dwarfs the enemy, keep pressing the advantage.
40
- priority +=
41
- (this.antiGroundPower *
42
- this.basePriority *
43
- GameMath.sqrt(
44
- threatCache.totalAvailableAntiGroundFirepower /
45
- Math.max(
46
- 1,
47
- threatCache.totalOffensiveLandThreat + threatCache.totalDefensiveThreat,
48
- ),
49
- )) /
50
- (numOwned + 1);
51
- }
52
- }
53
- if (this.antiAirPower > 0) {
54
- if (threatCache.totalOffensiveAirThreat > threatCache.totalAvailableAntiAirFirepower) {
55
- priority +=
56
- this.antiAirPower *
57
- this.basePriority *
58
- (threatCache.totalOffensiveAirThreat / Math.max(1, threatCache.totalAvailableAntiAirFirepower));
59
- } else {
60
- priority +=
61
- (this.antiAirPower *
62
- this.basePriority *
63
- GameMath.sqrt(
64
- threatCache.totalAvailableAntiAirFirepower /
65
- Math.max(1, threatCache.totalOffensiveAirThreat + threatCache.totalDefensiveThreat),
66
- )) /
67
- (numOwned + 1);
68
- }
69
- }
70
- return priority;
71
- }
72
- return this.basePriority * (1.0 - numOwned / this.baseAmount);
27
+ // Units aren't built automatically, but are instead requested by missions.
28
+ return 0;
73
29
  }
74
30
 
75
31
  getMaxCount(