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