@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,271 +0,0 @@
1
- // Meta-controller for forming and controlling squads.
2
-
3
- import { ActionsApi, GameApi, PlayerData, UnitData } from "@chronodivide/game-api";
4
- import { Squad, SquadLiveness } from "./squad.js";
5
- import {
6
- SquadAction,
7
- SquadActionDisband,
8
- SquadActionGrabFreeCombatants,
9
- SquadActionMergeInto,
10
- SquadActionRequestSpecificUnits,
11
- SquadActionRequestUnits,
12
- } from "./squadBehaviour.js";
13
- import { MatchAwareness } from "../awareness.js";
14
- import { getDistanceBetween } from "../map/map.js";
15
- import { countBy } from "../common/utils.js";
16
- import { ActionBatcher } from "./behaviours/actionBatcher.js";
17
-
18
- type SquadWithAction<T> = {
19
- squad: Squad;
20
- action: T;
21
- };
22
-
23
- export class SquadController {
24
- private squads: Squad[] = [];
25
- private unitIdToSquad: Map<number, Squad> = new Map();
26
-
27
- constructor(private logger: (message: string, sayInGame?: boolean) => void) {}
28
-
29
- public onAiUpdate(
30
- gameApi: GameApi,
31
- actionsApi: ActionsApi,
32
- playerData: PlayerData,
33
- matchAwareness: MatchAwareness,
34
- ) {
35
- // Remove dead squads or those where the mission is dead.
36
- this.squads = this.squads.filter((squad) => squad.getLiveness() !== SquadLiveness.SquadDead);
37
- this.squads.sort((a, b) => a.getName().localeCompare(b.getName()));
38
-
39
- // Check for units in multiple squads, this shouldn't happen.
40
- this.unitIdToSquad = new Map();
41
- this.squads.forEach((squad) => {
42
- squad.getUnitIds().forEach((unitId) => {
43
- if (this.unitIdToSquad.has(unitId)) {
44
- this.logger(`WARNING: unit ${unitId} is in multiple squads, please debug.`);
45
- } else {
46
- this.unitIdToSquad.set(unitId, squad);
47
- }
48
- });
49
- });
50
-
51
- // Batch actions to reduce spamming of actions for larger armies.
52
- const actionBatcher = new ActionBatcher();
53
-
54
- const squadActions: SquadWithAction<SquadAction>[] = this.squads.map((squad) => {
55
- return {
56
- squad,
57
- action: squad.onAiUpdate(gameApi, actionsApi, actionBatcher, playerData, matchAwareness, this.logger),
58
- };
59
- });
60
-
61
- // Handle disbands and merges.
62
- const isDisband = (a: SquadAction): a is SquadActionDisband => a.type === "disband";
63
- const isMerge = (a: SquadAction): a is SquadActionMergeInto => a.type === "mergeInto";
64
- let disbandedSquads: Set<string> = new Set();
65
- squadActions
66
- .filter((a) => isDisband(a.action))
67
- .forEach((a) => {
68
- this.logger(`Squad ${a.squad.getName()} disbanding as requested.`);
69
- a.squad.getMission()?.removeSquad();
70
- a.squad.getUnitIds().forEach((unitId) => {
71
- this.unitIdToSquad.delete(unitId);
72
- actionsApi.setUnitDebugText(unitId, undefined);
73
- });
74
- disbandedSquads.add(a.squad.getName());
75
- });
76
- squadActions
77
- .filter((a) => isMerge(a.action))
78
- .forEach((a) => {
79
- let mergeInto = a.action as SquadActionMergeInto;
80
- if (disbandedSquads.has(mergeInto.mergeInto.getName())) {
81
- this.logger(
82
- `Squad ${a.squad.getName()} tried to merge into disbanded squad ${mergeInto.mergeInto.getName()}, cancelling.`,
83
- );
84
- return;
85
- }
86
- a.squad.getUnitIds().forEach((unitId) => mergeInto.mergeInto.addUnit(unitId));
87
- disbandedSquads.add(a.squad.getName());
88
- });
89
- // remove disbanded and merged squads.
90
- this.squads = this.squads.filter((squad) => !disbandedSquads.has(squad.getName()));
91
-
92
- // Request specific units by ID
93
- const isRequestSpecific = (a: SquadAction) => a.type === "requestSpecific";
94
- const unitIdToHighestRequest = squadActions
95
- .filter((a) => isRequestSpecific(a.action))
96
- .reduce(
97
- (prev, a) => {
98
- const squadWithAction = a as SquadWithAction<SquadActionRequestSpecificUnits>;
99
- const { unitIds } = squadWithAction.action;
100
- unitIds.forEach((unitId) => {
101
- if (prev.hasOwnProperty(unitId)) {
102
- if (prev[unitId].action.priority > prev[unitId].action.priority) {
103
- prev[unitId] = squadWithAction;
104
- }
105
- } else {
106
- prev[unitId] = squadWithAction;
107
- }
108
- });
109
- return prev;
110
- },
111
- {} as Record<number, SquadWithAction<SquadActionRequestSpecificUnits>>,
112
- );
113
-
114
- // Map of Squad ID to Unit Type to Count.
115
- const newSquadAssignments = Object.entries(unitIdToHighestRequest)
116
- .flatMap(([id, request]) => {
117
- const unitId = Number.parseInt(id);
118
- const unit = gameApi.getUnitData(unitId);
119
- const { squad: requestingSquad } = request;
120
- const missionName = requestingSquad.getMission()?.getUniqueName();
121
- if (!unit) {
122
- this.logger(`mission ${missionName} requested non-existent unit ${unitId}`);
123
- return [];
124
- }
125
- if (!this.unitIdToSquad.has(unitId)) {
126
- this.addUnitToSquad(requestingSquad, unit);
127
- return [{ unitName: unit?.name, squad: requestingSquad.getName() }];
128
- }
129
- return [];
130
- })
131
- .reduce(
132
- (acc, curr) => {
133
- if (!acc[curr.squad]) {
134
- acc[curr.squad] = {};
135
- }
136
- if (!acc[curr.squad][curr.unitName]) {
137
- acc[curr.squad][curr.unitName] = 0;
138
- }
139
- acc[curr.squad][curr.unitName] = acc[curr.squad][curr.unitName] + 1;
140
- return acc;
141
- },
142
- {} as Record<string, Record<string, number>>,
143
- );
144
- Object.entries(newSquadAssignments).forEach(([squad, assignments]) => {
145
- this.logger(
146
- `Squad ${squad} received: ${Object.entries(assignments)
147
- .map(([unitType, count]) => unitType + " x " + count)
148
- .join(", ")}`,
149
- );
150
- });
151
-
152
- // Request units by type
153
- const isRequest = (a: SquadAction) => a.type === "request";
154
- const unitTypeToHighestRequest = squadActions
155
- .filter((a) => isRequest(a.action))
156
- .reduce(
157
- (prev, a) => {
158
- const squadWithAction = a as SquadWithAction<SquadActionRequestUnits>;
159
- const { unitNames } = squadWithAction.action;
160
- unitNames.forEach((unitName) => {
161
- if (prev.hasOwnProperty(unitName)) {
162
- if (prev[unitName].action.priority > prev[unitName].action.priority) {
163
- prev[unitName] = squadWithAction;
164
- }
165
- } else {
166
- prev[unitName] = squadWithAction;
167
- }
168
- });
169
- return prev;
170
- },
171
- {} as Record<string, SquadWithAction<SquadActionRequestUnits>>,
172
- );
173
-
174
- // Request combat-capable units in an area
175
- const isGrab = (a: SquadAction) => a.type === "requestCombatants";
176
- const grabRequests = squadActions.filter((a) =>
177
- isGrab(a.action),
178
- ) as SquadWithAction<SquadActionGrabFreeCombatants>[];
179
-
180
- // Find loose units
181
- const unitIds = gameApi.getVisibleUnits(playerData.name, "self");
182
- const freeUnits = unitIds
183
- .map((unitId) => gameApi.getUnitData(unitId))
184
- .filter((unit) => !!unit && !this.unitIdToSquad.has(unit.id || 0))
185
- .map((unit) => unit!);
186
-
187
- type AssignmentWithType = { unitName: string; squad: string; method: "type" | "grab" };
188
- const newAssignmentsByType = freeUnits
189
- .flatMap((freeUnit) => {
190
- if (unitTypeToHighestRequest.hasOwnProperty(freeUnit.name)) {
191
- const { squad: requestingSquad } = unitTypeToHighestRequest[freeUnit.name];
192
- this.logger(`granting unit ${freeUnit.id}#${freeUnit.name} to squad ${requestingSquad.getName()}`);
193
- this.addUnitToSquad(requestingSquad, freeUnit);
194
- delete unitTypeToHighestRequest[freeUnit.name];
195
- return [
196
- { unitName: freeUnit.name, squad: requestingSquad.getName(), method: "type" },
197
- ] as AssignmentWithType[];
198
- } else if (grabRequests.length > 0) {
199
- const grantedSquad = grabRequests.find((request) => {
200
- return (
201
- freeUnit.rules.isSelectableCombatant &&
202
- getDistanceBetween(freeUnit, request.action.point) <= request.action.radius
203
- );
204
- });
205
- if (grantedSquad) {
206
- this.addUnitToSquad(grantedSquad.squad, freeUnit);
207
- return [
208
- { unitName: freeUnit.name, squad: grantedSquad.squad.getName(), method: "grab" },
209
- ] as AssignmentWithType[];
210
- }
211
- }
212
- return [];
213
- })
214
- .reduce(
215
- (acc, curr) => {
216
- if (!acc[curr.squad]) {
217
- acc[curr.squad] = {};
218
- }
219
- if (!acc[curr.squad][curr.unitName]) {
220
- acc[curr.squad][curr.unitName] = { grab: 0, type: 0 };
221
- }
222
- acc[curr.squad][curr.unitName][curr.method] = acc[curr.squad][curr.unitName][curr.method] + 1;
223
- return acc;
224
- },
225
- {} as Record<string, Record<string, Record<"type" | "grab", number>>>,
226
- );
227
- Object.entries(newAssignmentsByType).forEach(([squad, assignments]) => {
228
- this.logger(
229
- `Squad ${squad} received: ${Object.entries(assignments)
230
- .flatMap(([unitType, methodToCount]) =>
231
- Object.entries(methodToCount)
232
- .filter(([, count]) => count > 0)
233
- .map(([method, count]) => unitType + " x " + count + " (by " + method + ")"),
234
- )
235
- .join(", ")}`,
236
- );
237
- });
238
-
239
- actionBatcher.resolve(actionsApi);
240
- }
241
-
242
- private addUnitToSquad(squad: Squad, unit: UnitData) {
243
- squad.addUnit(unit.id);
244
- this.unitIdToSquad.set(unit.id, squad);
245
- }
246
-
247
- public registerSquad(squad: Squad) {
248
- this.squads.push(squad);
249
- }
250
-
251
- // return text to display for global debug
252
- public debugSquads(gameApi: GameApi, actionsApi: ActionsApi): string {
253
- const unitsInSquad = (unitIds: number[]) => countBy(unitIds, (unitId) => gameApi.getUnitData(unitId)?.name);
254
-
255
- let globalDebugText = "";
256
-
257
- this.squads.forEach((squad) => {
258
- this.logger(
259
- `Squad ${squad.getName()}: ${Object.entries(unitsInSquad(squad.getUnitIds()))
260
- .map(([unitName, count]) => `${unitName} x ${count}`)
261
- .join(", ")}`,
262
- );
263
- squad.getUnitIds().forEach((unitId) => actionsApi.setUnitDebugText(unitId, squad.getName()));
264
- const squadDebugText = squad.getGlobalDebugText();
265
- if (squadDebugText) {
266
- globalDebugText += squad.getName() + ": " + squadDebugText + "\n";
267
- }
268
- });
269
- return globalDebugText;
270
- }
271
- }