@supalosa/chronodivide-bot 0.5.3 → 0.6.4

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 (134) hide show
  1. package/.env.template +4 -4
  2. package/.github/workflows/npm-publish.yml +24 -0
  3. package/README.md +108 -97
  4. package/dist/bot/bot.js +105 -105
  5. package/dist/bot/bot.js.map +1 -1
  6. package/dist/bot/logic/awareness.js +136 -136
  7. package/dist/bot/logic/building/antiAirStaticDefence.js +42 -42
  8. package/dist/bot/logic/building/antiGroundStaticDefence.js +34 -30
  9. package/dist/bot/logic/building/antiGroundStaticDefence.js.map +1 -1
  10. package/dist/bot/logic/building/{ArtilleryUnit.js → artilleryUnit.js} +18 -18
  11. package/dist/bot/logic/building/basicAirUnit.js +19 -19
  12. package/dist/bot/logic/building/basicBuilding.js +26 -26
  13. package/dist/bot/logic/building/basicGroundUnit.js +19 -19
  14. package/dist/bot/logic/building/buildingRules.js +175 -174
  15. package/dist/bot/logic/building/buildingRules.js.map +1 -1
  16. package/dist/bot/logic/building/common.js +19 -18
  17. package/dist/bot/logic/building/common.js.map +1 -1
  18. package/dist/bot/logic/building/harvester.js +16 -16
  19. package/dist/bot/logic/building/powerPlant.js +20 -20
  20. package/dist/bot/logic/building/queueController.js +183 -183
  21. package/dist/bot/logic/building/resourceCollectionBuilding.js +36 -36
  22. package/dist/bot/logic/common/scout.js +126 -126
  23. package/dist/bot/logic/common/utils.js +95 -85
  24. package/dist/bot/logic/common/utils.js.map +1 -1
  25. package/dist/bot/logic/composition/alliedCompositions.js +12 -12
  26. package/dist/bot/logic/composition/common.js +1 -1
  27. package/dist/bot/logic/composition/sovietCompositions.js +12 -12
  28. package/dist/bot/logic/map/map.js +44 -44
  29. package/dist/bot/logic/map/sector.js +137 -137
  30. package/dist/bot/logic/mission/actionBatcher.js +91 -91
  31. package/dist/bot/logic/mission/mission.js +122 -122
  32. package/dist/bot/logic/mission/missionController.js +321 -321
  33. package/dist/bot/logic/mission/missionFactories.js +12 -12
  34. package/dist/bot/logic/mission/missions/attackMission.js +214 -214
  35. package/dist/bot/logic/mission/missions/defenceMission.js +82 -82
  36. package/dist/bot/logic/mission/missions/engineerMission.js +63 -63
  37. package/dist/bot/logic/mission/missions/expansionMission.js +60 -60
  38. package/dist/bot/logic/mission/missions/retreatMission.js +33 -33
  39. package/dist/bot/logic/mission/missions/scoutingMission.js +133 -133
  40. package/dist/bot/logic/mission/missions/squads/combatSquad.js +115 -115
  41. package/dist/bot/logic/mission/missions/squads/common.js +57 -57
  42. package/dist/bot/logic/mission/missions/squads/squad.js +1 -1
  43. package/dist/bot/logic/threat/threat.js +22 -22
  44. package/dist/bot/logic/threat/threatCalculator.js +73 -73
  45. package/dist/exampleBot.js +100 -112
  46. package/dist/exampleBot.js.map +1 -1
  47. package/package.json +32 -29
  48. package/src/bot/bot.ts +161 -161
  49. package/src/bot/logic/awareness.ts +245 -245
  50. package/src/bot/logic/building/antiAirStaticDefence.ts +64 -64
  51. package/src/bot/logic/building/antiGroundStaticDefence.ts +55 -51
  52. package/src/bot/logic/building/artilleryUnit.ts +39 -39
  53. package/src/bot/logic/building/basicAirUnit.ts +39 -39
  54. package/src/bot/logic/building/basicBuilding.ts +49 -49
  55. package/src/bot/logic/building/basicGroundUnit.ts +39 -39
  56. package/src/bot/logic/building/buildingRules.ts +250 -247
  57. package/src/bot/logic/building/common.ts +21 -23
  58. package/src/bot/logic/building/harvester.ts +31 -31
  59. package/src/bot/logic/building/powerPlant.ts +32 -32
  60. package/src/bot/logic/building/queueController.ts +297 -297
  61. package/src/bot/logic/building/resourceCollectionBuilding.ts +52 -52
  62. package/src/bot/logic/common/scout.ts +183 -183
  63. package/src/bot/logic/common/utils.ts +120 -112
  64. package/src/bot/logic/composition/alliedCompositions.ts +22 -22
  65. package/src/bot/logic/composition/common.ts +3 -3
  66. package/src/bot/logic/composition/sovietCompositions.ts +21 -21
  67. package/src/bot/logic/map/map.ts +66 -66
  68. package/src/bot/logic/map/sector.ts +174 -174
  69. package/src/bot/logic/mission/actionBatcher.ts +124 -124
  70. package/src/bot/logic/mission/mission.ts +232 -232
  71. package/src/bot/logic/mission/missionController.ts +413 -413
  72. package/src/bot/logic/mission/missionFactories.ts +51 -51
  73. package/src/bot/logic/mission/missions/attackMission.ts +336 -336
  74. package/src/bot/logic/mission/missions/defenceMission.ts +151 -151
  75. package/src/bot/logic/mission/missions/engineerMission.ts +113 -113
  76. package/src/bot/logic/mission/missions/expansionMission.ts +104 -104
  77. package/src/bot/logic/mission/missions/retreatMission.ts +54 -54
  78. package/src/bot/logic/mission/missions/scoutingMission.ts +186 -186
  79. package/src/bot/logic/mission/missions/squads/combatSquad.ts +160 -160
  80. package/src/bot/logic/mission/missions/squads/common.ts +63 -63
  81. package/src/bot/logic/mission/missions/squads/squad.ts +19 -19
  82. package/src/bot/logic/threat/threatCalculator.ts +100 -100
  83. package/src/exampleBot.ts +111 -124
  84. package/tsconfig.json +73 -73
  85. package/dist/bot/logic/building/building.js +0 -82
  86. package/dist/bot/logic/building/massedAntiGroundUnit.js +0 -20
  87. package/dist/bot/logic/building/queues.js +0 -19
  88. package/dist/bot/logic/knowledge.js +0 -1
  89. package/dist/bot/logic/mission/basicMission.js +0 -26
  90. package/dist/bot/logic/mission/behaviours/combatSquad.js +0 -124
  91. package/dist/bot/logic/mission/behaviours/combatSquad.js.map +0 -1
  92. package/dist/bot/logic/mission/behaviours/common.js +0 -56
  93. package/dist/bot/logic/mission/behaviours/common.js.map +0 -1
  94. package/dist/bot/logic/mission/behaviours/engineerSquad.js +0 -39
  95. package/dist/bot/logic/mission/behaviours/engineerSquad.js.map +0 -1
  96. package/dist/bot/logic/mission/behaviours/expansionSquad.js +0 -46
  97. package/dist/bot/logic/mission/behaviours/expansionSquad.js.map +0 -1
  98. package/dist/bot/logic/mission/behaviours/retreatSquad.js +0 -31
  99. package/dist/bot/logic/mission/behaviours/retreatSquad.js.map +0 -1
  100. package/dist/bot/logic/mission/behaviours/scoutingSquad.js +0 -94
  101. package/dist/bot/logic/mission/behaviours/scoutingSquad.js.map +0 -1
  102. package/dist/bot/logic/mission/expansionMission.js +0 -32
  103. package/dist/bot/logic/mission/missions/basicMission.js +0 -13
  104. package/dist/bot/logic/mission/missions/basicMission.js.map +0 -1
  105. package/dist/bot/logic/mission/missions/missionBehaviour.js +0 -2
  106. package/dist/bot/logic/mission/missions/missionBehaviour.js.map +0 -1
  107. package/dist/bot/logic/mission/missions/oneTimeMission.js +0 -27
  108. package/dist/bot/logic/mission/missions/oneTimeMission.js.map +0 -1
  109. package/dist/bot/logic/squad/behaviours/actionBatcher.js +0 -36
  110. package/dist/bot/logic/squad/behaviours/actionBatcher.js.map +0 -1
  111. package/dist/bot/logic/squad/behaviours/attackSquad.js +0 -82
  112. package/dist/bot/logic/squad/behaviours/combatSquad.js +0 -106
  113. package/dist/bot/logic/squad/behaviours/combatSquad.js.map +0 -1
  114. package/dist/bot/logic/squad/behaviours/common.js +0 -55
  115. package/dist/bot/logic/squad/behaviours/common.js.map +0 -1
  116. package/dist/bot/logic/squad/behaviours/defenceSquad.js +0 -48
  117. package/dist/bot/logic/squad/behaviours/engineerSquad.js +0 -38
  118. package/dist/bot/logic/squad/behaviours/engineerSquad.js.map +0 -1
  119. package/dist/bot/logic/squad/behaviours/expansionSquad.js +0 -45
  120. package/dist/bot/logic/squad/behaviours/expansionSquad.js.map +0 -1
  121. package/dist/bot/logic/squad/behaviours/retreatSquad.js +0 -31
  122. package/dist/bot/logic/squad/behaviours/retreatSquad.js.map +0 -1
  123. package/dist/bot/logic/squad/behaviours/scoutingSquad.js +0 -93
  124. package/dist/bot/logic/squad/behaviours/scoutingSquad.js.map +0 -1
  125. package/dist/bot/logic/squad/behaviours/squadExpansion.js +0 -31
  126. package/dist/bot/logic/squad/behaviours/squadScouters.js +0 -8
  127. package/dist/bot/logic/squad/squad.js +0 -126
  128. package/dist/bot/logic/squad/squad.js.map +0 -1
  129. package/dist/bot/logic/squad/squadBehaviour.js +0 -6
  130. package/dist/bot/logic/squad/squadBehaviour.js.map +0 -1
  131. package/dist/bot/logic/squad/squadBehaviours.js +0 -7
  132. package/dist/bot/logic/squad/squadBehaviours.js.map +0 -1
  133. package/dist/bot/logic/squad/squadController.js +0 -215
  134. package/dist/bot/logic/squad/squadController.js.map +0 -1
package/.env.template CHANGED
@@ -1,5 +1,5 @@
1
- SERVER_URL="wss://gserv-sea1.chronodivide.com"
2
- CLIENT_URL="https://game.chronodivide.com/"
3
- ONLINE_BOT_NAME="username_of_your_bot"
4
- ONLINE_BOT_PASSWORD="password_of_your_bot"
1
+ SERVER_URL="wss://gserv-sea1.chronodivide.com"
2
+ CLIENT_URL="https://game.chronodivide.com/"
3
+ ONLINE_BOT_NAME="username_of_your_bot"
4
+ ONLINE_BOT_PASSWORD="password_of_your_bot"
5
5
  PLAYER_NAME="username_of_human_account"
@@ -0,0 +1,24 @@
1
+ name: Publish Package
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ permissions:
9
+ id-token: write # Required for OIDC
10
+ contents: read
11
+
12
+ jobs:
13
+ publish:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: actions/setup-node@v4
19
+ with:
20
+ node-version: 24
21
+ registry-url: 'https://registry.npmjs.org'
22
+ - run: npm ci
23
+ - run: npm run build --if-present
24
+ - run: npm publish
package/README.md CHANGED
@@ -1,97 +1,108 @@
1
- # Supalosa's Chrono Divide Bot
2
-
3
- [中文版文档](README-CN.md)
4
-
5
- [Chrono Divide](https://chronodivide.com/) is a ground-up rebuild of Red Alert 2 in the browser. It is feature-complete and allows for online skirmish play against other players.
6
- It also provides [an API to build bots](https://discord.com/channels/771701199812558848/842700851520339988), as there is no built-in AI yet.
7
-
8
- This repository is one such implementation of a bot. The original template for the bot is available at [game-api-playground](https://github.com/chronodivide/game-api-playground/blob/master/README.md).
9
-
10
- ## Development State and Future plans
11
-
12
- The developer of Chrono Divide has expressed interest in integrating this bot into the game directly. As a consequence, I am aiming to implement missing features to create a satisfactory AI opponent for humans.
13
- Directionally, this means I am not looking to make this AI a perfect opponent with perfect compositions or micro, and instead hope that it can be a fun challenge for newer players.
14
-
15
- See `TODO.md` for a granular list of structural changes and feature improvements that are planned for the bot.
16
-
17
- Feel free to contribute to the repository, or even fork the repo and build your own version.
18
-
19
- ## Install instructions
20
-
21
- Node 14 is required by the Chrono Divide API. Higher versions are not supported yet.
22
-
23
- ```sh
24
- npm install
25
- npm run build
26
- npx cross-env MIX_DIR="C:\path_to_ra2_install_dir" npm start
27
- ```
28
-
29
- This will create a replay (`.rpl`) file that can be [imported into the live game](https://game.chronodivide.com/).
30
-
31
- You can modify `exampleBot.ts` to configure the match. You will most likely want to look at the line with `const mapName = "..."` to change the map, or the `const offlineSettings1v1` to change the bot countries.
32
-
33
- ## Playing against the bot
34
-
35
- Currently, playing against this bot **is only possible for developers**, because it requires you to run this repository from source. Follow these steps to set up online play.
36
-
37
- ### Initial set up steps (one time only)
38
-
39
- 1. Create a Chronodivide account for your bot using the official client at [https://game.chronodivide.com].
40
- 2. If you don't already have one, create a Chronodivide account for yourself using the same link,
41
- 3. Copy `.env.template` to `.env`. The `.env` file is not checked into the repo.
42
- 4. Set the value of `ONLINE_BOT_NAME` to the username of the bot from step 1.
43
- 5. Set the value of `ONLINE_BOT_PASSWORD` to the password from step 1.
44
- 6. Set the value of `PLAYER_NAME` to the human's account name.
45
- 7. (Optional) Change `SERVER_URL` if you want to connect to another server. The Chronodivide accounts from step 1 and 2 need to be present on that server.
46
-
47
- ### Running the bot and connecting to the game
48
-
49
- Start the bot with `ONLINE_MATCH=1`. For example:
50
-
51
- ```sh
52
- ONLINE_MATCH=1 npx cross-env MIX_DIR="${GAMEPATH}" npm --node-options="${NODE_OPTIONS} --inspect" start
53
- ```
54
-
55
- The bot will connect to the server and should return output like this:
56
-
57
- ```
58
- You may use the following link(s) to join, after the game is created:
59
-
60
- https://game.chronodivide.com/#/game/12345/supalosa
61
-
62
-
63
- Press ENTER to create the game now...
64
- ```
65
-
66
- Navigate to the link, **log in using the human credentials first**, then hit ENTER in the terminal so the bot can create the game.
67
- Do not hit ENTER too early, as there is a very narrow window for the human connect to the match.
68
-
69
- ## Debugging
70
-
71
- To generate a replay with debugging enabled:
72
-
73
- ```sh
74
- npx cross-env MIX_DIR="C:\path_to_ra2_install_dir" npm --node-options="${NODE_OPTIONS} --inspect" start
75
- ```
76
-
77
- To log all actions generated by the bots:
78
-
79
- ```sh
80
- DEBUG_LOGGING="action" npx cross-env MIX_DIR="${GAMEPATH}" npm --node-options="${NODE_OPTIONS} --inspect" start
81
- ```
82
-
83
- We also take advantage of the in-game bot debug functionality provided by CD. These are basically bot-only actions that are saved in the replay, but you must enable the visualisations in the CD client before watching the replay, by typing the following into the dev console:.
84
-
85
- ```
86
- r.debug_text = true;
87
- ```
88
-
89
- This will debug the bot which has been configured with `setDebugMode(true)`, this is done in `exampleBot.ts`.
90
-
91
- ## Publishing
92
-
93
- Have the npmjs token in ~/.npmrc or somewhere appropriate.
94
-
95
- ```
96
- npm publish
97
- ```
1
+ [![Publish Package](https://github.com/Supalosa/supalosa-chronodivide-bot/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/Supalosa/supalosa-chronodivide-bot/actions/workflows/npm-publish.yml)
2
+
3
+ # Supalosa's Chrono Divide Bot
4
+
5
+ [中文版文档](README-CN.md)
6
+
7
+ [Chrono Divide](https://chronodivide.com/) is a ground-up rebuild of Red Alert 2 in the browser. It is feature-complete and allows for online skirmish play against other players.
8
+ It also provides [an API to build bots](https://discord.com/channels/771701199812558848/842700851520339988), as there is no built-in AI yet.
9
+
10
+ This repository is one such implementation of a bot. The original template for the bot is available at [game-api-playground](https://github.com/chronodivide/game-api-playground/blob/master/README.md).
11
+
12
+ ## Development State and Future plans
13
+
14
+ The developer of Chrono Divide has expressed interest in integrating this bot into the game directly. As a consequence, I am aiming to implement missing features to create a satisfactory AI opponent for humans.
15
+ Directionally, this means I am not looking to make this AI a perfect opponent with perfect compositions or micro, and instead hope that it can be a fun challenge for newer players.
16
+
17
+ See `TODO.md` for a granular list of structural changes and feature improvements that are planned for the bot.
18
+
19
+ Feel free to contribute to the repository, or even fork the repo and build your own version.
20
+
21
+ ## Install instructions
22
+
23
+ Node 20 is required by the Chrono Divide API. However, publishing is done on Node 24 or above.
24
+
25
+ ```sh
26
+ npm install
27
+ npm run build
28
+ npx cross-env MIX_DIR="C:\path_to_ra2_install_dir" npm start
29
+ ```
30
+
31
+ This will create a replay (`.rpl`) file that can be [imported into the live game](https://game.chronodivide.com/).
32
+
33
+ You can modify `exampleBot.ts` to configure the match. You will most likely want to look at the line with `const mapName = "..."` to change the map, or the `const offlineSettings1v1` to change the bot countries.
34
+
35
+ ## Playing against the bot
36
+
37
+ Currently, playing against this bot **is only possible for developers**, because it requires you to run this repository from source. Follow these steps to set up online play.
38
+
39
+ ### Initial set up steps (one time only)
40
+
41
+ 1. Create a Chronodivide account for your bot using the official client at [https://game.chronodivide.com].
42
+ 2. If you don't already have one, create a Chronodivide account for yourself using the same link,
43
+ 3. Copy `.env.template` to `.env`. The `.env` file is not checked into the repo.
44
+ 4. Set the value of `ONLINE_BOT_NAME` to the username of the bot from step 1.
45
+ 5. Set the value of `ONLINE_BOT_PASSWORD` to the password from step 1.
46
+ 6. Set the value of `PLAYER_NAME` to the human's account name.
47
+ 7. (Optional) Change `SERVER_URL` if you want to connect to another server. The Chronodivide accounts from step 1 and 2 need to be present on that server.
48
+
49
+ ### Running the bot and connecting to the game
50
+
51
+ Start the bot with `ONLINE_MATCH=1`. For example:
52
+
53
+ ```sh
54
+ ONLINE_MATCH=1 npx cross-env MIX_DIR="${GAMEPATH}" npm --node-options="${NODE_OPTIONS} --inspect" start
55
+ ```
56
+
57
+ The bot will connect to the server and should return output like this:
58
+
59
+ ```
60
+ You may use the following link(s) to join, after the game is created:
61
+
62
+ https://game.chronodivide.com/#/game/12345/supalosa
63
+
64
+
65
+ Press ENTER to create the game now...
66
+ ```
67
+
68
+ Navigate to the link, **log in using the human credentials first**, then hit ENTER in the terminal so the bot can create the game.
69
+ Do not hit ENTER too early, as there is a very narrow window for the human connect to the match.
70
+
71
+ ## Debugging
72
+
73
+ To generate a replay with debugging enabled:
74
+
75
+ ```sh
76
+ npx cross-env MIX_DIR="C:\path_to_ra2_install_dir" npm --node-options="${NODE_OPTIONS} --inspect" start
77
+ ```
78
+
79
+ To log all actions generated by the bots:
80
+
81
+ ```sh
82
+ DEBUG_LOGGING="action" npx cross-env MIX_DIR="${GAMEPATH}" npm --node-options="${NODE_OPTIONS} --inspect" start
83
+ ```
84
+
85
+ We also take advantage of the in-game bot debug functionality provided by CD. These are basically bot-only actions that are saved in the replay, but you must enable the visualisations in the CD client before watching the replay, by typing the following into the dev console:.
86
+
87
+ ```
88
+ r.debug_text = true;
89
+ ```
90
+
91
+ This will debug the bot which has been configured with `setDebugMode(true)`, this is done in `exampleBot.ts`.
92
+
93
+ ## Publishing
94
+
95
+ A Github Action has been set up on the [main repo](https://github.com/Supalosa/supalosa-chronodivide-bot). We use npmjs's [trusted publisher](https://docs.npmjs.com/trusted-publishers#supported-cicd-providers) setup to do this.
96
+
97
+ To publish a new version of the bot:
98
+
99
+ ```
100
+ npm version v0.6.0 # major.minor.patch
101
+ git push origin tag v0.6.0
102
+ ```
103
+
104
+ ## Contributors
105
+
106
+ - use-strict: Making Chrono Divide
107
+ - Libi: Improvements to base structure placement performance
108
+ - Dogemoon: CN Documentation
package/dist/bot/bot.js CHANGED
@@ -1,106 +1,106 @@
1
- import { ApiEventType, Bot, ObjectType, FactoryType } from "@chronodivide/game-api";
2
- import { determineMapBounds } from "./logic/map/map.js";
3
- import { SectorCache } from "./logic/map/sector.js";
4
- import { MissionController } from "./logic/mission/missionController.js";
5
- import { QueueController } from "./logic/building/queueController.js";
6
- import { MatchAwarenessImpl } from "./logic/awareness.js";
7
- import { formatTimeDuration } from "./logic/common/utils.js";
8
- const DEBUG_STATE_UPDATE_INTERVAL_SECONDS = 6;
9
- // Number of ticks per second at the base speed.
10
- const NATURAL_TICK_RATE = 15;
11
- export class SupalosaBot extends Bot {
12
- constructor(name, country, tryAllyWith = [], enableLogging = true) {
13
- super(name, country);
14
- this.tryAllyWith = tryAllyWith;
15
- this.enableLogging = enableLogging;
16
- this.tickOfLastAttackOrder = 0;
17
- this.matchAwareness = null;
18
- this.missionController = new MissionController((message, sayInGame) => this.logBotStatus(message, sayInGame));
19
- this.queueController = new QueueController();
20
- }
21
- onGameStart(game) {
22
- const gameRate = game.getTickRate();
23
- const botApm = 300;
24
- const botRate = botApm / 60;
25
- this.tickRatio = Math.ceil(gameRate / botRate);
26
- this.knownMapBounds = determineMapBounds(game.mapApi);
27
- const myPlayer = game.getPlayerData(this.name);
28
- this.matchAwareness = new MatchAwarenessImpl(null, new SectorCache(game.mapApi, this.knownMapBounds), myPlayer.startLocation, (message, sayInGame) => this.logBotStatus(message, sayInGame));
29
- this.matchAwareness.onGameStart(game, myPlayer);
30
- this.logBotStatus(`Map bounds: ${this.knownMapBounds.width}, ${this.knownMapBounds.height}`);
31
- this.tryAllyWith.forEach((playerName) => this.actionsApi.toggleAlliance(playerName, true));
32
- }
33
- onGameTick(game) {
34
- if (!this.matchAwareness) {
35
- return;
36
- }
37
- const threatCache = this.matchAwareness.getThreatCache();
38
- if ((game.getCurrentTick() / NATURAL_TICK_RATE) % DEBUG_STATE_UPDATE_INTERVAL_SECONDS === 0) {
39
- this.updateDebugState(game);
40
- }
41
- if (game.getCurrentTick() % this.tickRatio === 0) {
42
- const myPlayer = game.getPlayerData(this.name);
43
- this.matchAwareness.onAiUpdate(game, myPlayer);
44
- // hacky resign condition
45
- const armyUnits = game.getVisibleUnits(this.name, "self", (r) => r.isSelectableCombatant);
46
- const mcvUnits = game.getVisibleUnits(this.name, "self", (r) => !!r.deploysInto && game.getGeneralRules().baseUnit.includes(r.name));
47
- const productionBuildings = game.getVisibleUnits(this.name, "self", (r) => r.type == ObjectType.Building && r.factory != FactoryType.None);
48
- if (armyUnits.length == 0 && productionBuildings.length == 0 && mcvUnits.length == 0) {
49
- this.logBotStatus(`No army or production left, quitting.`);
50
- this.actionsApi.quitGame();
51
- }
52
- // Mission logic every 3 ticks
53
- if (this.gameApi.getCurrentTick() % 3 === 0) {
54
- this.missionController.onAiUpdate(game, this.actionsApi, myPlayer, this.matchAwareness);
55
- }
56
- const unitTypeRequests = this.missionController.getRequestedUnitTypes();
57
- // Build logic.
58
- this.queueController.onAiUpdate(game, this.productionApi, this.actionsApi, myPlayer, threatCache, unitTypeRequests, (message) => this.logBotStatus(message));
59
- }
60
- }
61
- getHumanTimestamp(game) {
62
- return formatTimeDuration(game.getCurrentTick() / NATURAL_TICK_RATE);
63
- }
64
- logBotStatus(message, sayInGame = false) {
65
- if (!this.enableLogging) {
66
- return;
67
- }
68
- this.logger.info(message);
69
- if (sayInGame) {
70
- const timestamp = this.getHumanTimestamp(this.gameApi);
71
- this.actionsApi.sayAll(`${timestamp}: ${message}`);
72
- }
73
- }
74
- updateDebugState(game) {
75
- if (!this.getDebugMode()) {
76
- return;
77
- }
78
- // Update the global debug text.
79
- const myPlayer = game.getPlayerData(this.name);
80
- const harvesters = game.getVisibleUnits(this.name, "self", (r) => r.harvester).length;
81
- let globalDebugText = `Cash: ${myPlayer.credits} | Harvesters: ${harvesters}\n`;
82
- globalDebugText += this.queueController.getGlobalDebugText(this.gameApi, this.productionApi);
83
- globalDebugText += this.missionController.getGlobalDebugText(this.gameApi);
84
- globalDebugText += this.matchAwareness?.getGlobalDebugText();
85
- this.missionController.updateDebugText(this.actionsApi);
86
- // Tag enemy units with IDs
87
- game.getVisibleUnits(this.name, "enemy").forEach((unitId) => {
88
- this.actionsApi.setUnitDebugText(unitId, unitId.toString());
89
- });
90
- this.actionsApi.setGlobalDebugText(globalDebugText);
91
- }
92
- onGameEvent(ev) {
93
- switch (ev.type) {
94
- case ApiEventType.ObjectDestroy: {
95
- // Add to the stalemate detection.
96
- if (ev.attackerInfo?.playerName == this.name) {
97
- this.tickOfLastAttackOrder += (this.gameApi.getCurrentTick() - this.tickOfLastAttackOrder) / 2;
98
- }
99
- break;
100
- }
101
- default:
102
- break;
103
- }
104
- }
105
- }
1
+ import { ApiEventType, Bot, ObjectType, FactoryType } from "@chronodivide/game-api";
2
+ import { determineMapBounds } from "./logic/map/map.js";
3
+ import { SectorCache } from "./logic/map/sector.js";
4
+ import { MissionController } from "./logic/mission/missionController.js";
5
+ import { QueueController } from "./logic/building/queueController.js";
6
+ import { MatchAwarenessImpl } from "./logic/awareness.js";
7
+ import { formatTimeDuration } from "./logic/common/utils.js";
8
+ const DEBUG_STATE_UPDATE_INTERVAL_SECONDS = 6;
9
+ // Number of ticks per second at the base speed.
10
+ const NATURAL_TICK_RATE = 15;
11
+ export class SupalosaBot extends Bot {
12
+ constructor(name, country, tryAllyWith = [], enableLogging = true) {
13
+ super(name, country);
14
+ this.tryAllyWith = tryAllyWith;
15
+ this.enableLogging = enableLogging;
16
+ this.tickOfLastAttackOrder = 0;
17
+ this.matchAwareness = null;
18
+ this.missionController = new MissionController((message, sayInGame) => this.logBotStatus(message, sayInGame));
19
+ this.queueController = new QueueController();
20
+ }
21
+ onGameStart(game) {
22
+ const gameRate = game.getTickRate();
23
+ const botApm = 300;
24
+ const botRate = botApm / 60;
25
+ this.tickRatio = Math.ceil(gameRate / botRate);
26
+ this.knownMapBounds = determineMapBounds(game.mapApi);
27
+ const myPlayer = game.getPlayerData(this.name);
28
+ this.matchAwareness = new MatchAwarenessImpl(null, new SectorCache(game.mapApi, this.knownMapBounds), myPlayer.startLocation, (message, sayInGame) => this.logBotStatus(message, sayInGame));
29
+ this.matchAwareness.onGameStart(game, myPlayer);
30
+ this.logBotStatus(`Map bounds: ${this.knownMapBounds.width}, ${this.knownMapBounds.height}`);
31
+ this.tryAllyWith.forEach((playerName) => this.actionsApi.toggleAlliance(playerName, true));
32
+ }
33
+ onGameTick(game) {
34
+ if (!this.matchAwareness) {
35
+ return;
36
+ }
37
+ const threatCache = this.matchAwareness.getThreatCache();
38
+ if ((game.getCurrentTick() / NATURAL_TICK_RATE) % DEBUG_STATE_UPDATE_INTERVAL_SECONDS === 0) {
39
+ this.updateDebugState(game);
40
+ }
41
+ if (game.getCurrentTick() % this.tickRatio === 0) {
42
+ const myPlayer = game.getPlayerData(this.name);
43
+ this.matchAwareness.onAiUpdate(game, myPlayer);
44
+ // hacky resign condition
45
+ const armyUnits = game.getVisibleUnits(this.name, "self", (r) => r.isSelectableCombatant);
46
+ const mcvUnits = game.getVisibleUnits(this.name, "self", (r) => !!r.deploysInto && game.getGeneralRules().baseUnit.includes(r.name));
47
+ const productionBuildings = game.getVisibleUnits(this.name, "self", (r) => r.type == ObjectType.Building && r.factory != FactoryType.None);
48
+ if (armyUnits.length == 0 && productionBuildings.length == 0 && mcvUnits.length == 0) {
49
+ this.logBotStatus(`No army or production left, quitting.`);
50
+ this.actionsApi.quitGame();
51
+ }
52
+ // Mission logic every 3 ticks
53
+ if (this.gameApi.getCurrentTick() % 3 === 0) {
54
+ this.missionController.onAiUpdate(game, this.actionsApi, myPlayer, this.matchAwareness);
55
+ }
56
+ const unitTypeRequests = this.missionController.getRequestedUnitTypes();
57
+ // Build logic.
58
+ this.queueController.onAiUpdate(game, this.productionApi, this.actionsApi, myPlayer, threatCache, unitTypeRequests, (message) => this.logBotStatus(message));
59
+ }
60
+ }
61
+ getHumanTimestamp(game) {
62
+ return formatTimeDuration(game.getCurrentTick() / NATURAL_TICK_RATE);
63
+ }
64
+ logBotStatus(message, sayInGame = false) {
65
+ if (!this.enableLogging) {
66
+ return;
67
+ }
68
+ this.logger.info(message);
69
+ if (sayInGame) {
70
+ const timestamp = this.getHumanTimestamp(this.gameApi);
71
+ this.actionsApi.sayAll(`${timestamp}: ${message}`);
72
+ }
73
+ }
74
+ updateDebugState(game) {
75
+ if (!this.getDebugMode()) {
76
+ return;
77
+ }
78
+ // Update the global debug text.
79
+ const myPlayer = game.getPlayerData(this.name);
80
+ const harvesters = game.getVisibleUnits(this.name, "self", (r) => r.harvester).length;
81
+ let globalDebugText = `Cash: ${myPlayer.credits} | Harvesters: ${harvesters}\n`;
82
+ globalDebugText += this.queueController.getGlobalDebugText(this.gameApi, this.productionApi);
83
+ globalDebugText += this.missionController.getGlobalDebugText(this.gameApi);
84
+ globalDebugText += this.matchAwareness?.getGlobalDebugText();
85
+ this.missionController.updateDebugText(this.actionsApi);
86
+ // Tag enemy units with IDs
87
+ game.getVisibleUnits(this.name, "enemy").forEach((unitId) => {
88
+ this.actionsApi.setUnitDebugText(unitId, unitId.toString());
89
+ });
90
+ this.actionsApi.setGlobalDebugText(globalDebugText);
91
+ }
92
+ onGameEvent(ev) {
93
+ switch (ev.type) {
94
+ case ApiEventType.ObjectDestroy: {
95
+ // Add to the stalemate detection.
96
+ if (ev.attackerInfo?.playerName == this.name) {
97
+ this.tickOfLastAttackOrder += (this.gameApi.getCurrentTick() - this.tickOfLastAttackOrder) / 2;
98
+ }
99
+ break;
100
+ }
101
+ default:
102
+ break;
103
+ }
104
+ }
105
+ }
106
106
  //# sourceMappingURL=bot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bot.js","sourceRoot":"","sources":["../../src/bot/bot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bot.js","sourceRoot":"","sources":["../../src/bot/bot.ts"],"names":[],"mappings":"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"}