@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,36 +1,127 @@
1
- import { GameApi, PlayerData } from "@chronodivide/game-api";
2
- import { Squad } from "../squad/squad.js";
1
+ import { ActionsApi, GameApi, PlayerData, Tile, UnitData, Vector2 } from "@chronodivide/game-api";
3
2
  import { MatchAwareness } from "../awareness.js";
4
3
  import { DebugLogger } from "../common/utils.js";
5
-
6
- // AI starts Missions based on heuristics, which have one or more squads.
7
- // Missions can create squads (but squads will disband themselves).
4
+ import { ActionBatcher } from "./actionBatcher.js";
5
+ import { getDistanceBetweenTileAndPoint } from "../map/map.js";
6
+
7
+ const calculateCenterOfMass: (unitTiles: Tile[]) => {
8
+ centerOfMass: Vector2;
9
+ maxDistance: number;
10
+ } | null = (unitTiles) => {
11
+ if (unitTiles.length === 0) {
12
+ return null;
13
+ }
14
+ // TODO: use median here
15
+ const sums = unitTiles.reduce(
16
+ ({ x, y }, tile) => {
17
+ return {
18
+ x: x + (tile?.rx || 0),
19
+ y: y + (tile?.ry || 0),
20
+ };
21
+ },
22
+ { x: 0, y: 0 },
23
+ );
24
+ const centerOfMass = new Vector2(Math.round(sums.x / unitTiles.length), Math.round(sums.y / unitTiles.length));
25
+
26
+ // max distance of units to the center of mass
27
+ const distances = unitTiles.map((tile) => getDistanceBetweenTileAndPoint(tile, centerOfMass));
28
+ const maxDistance = Math.max(...distances);
29
+ return { centerOfMass, maxDistance };
30
+ };
31
+ // AI starts Missions based on heuristics.
8
32
  export abstract class Mission<FailureReasons = undefined> {
9
- private squad: Squad | null = null;
10
33
  private active = true;
34
+ private unitIds: number[] = [];
35
+ private centerOfMass: Vector2 | null = null;
36
+ private maxDistanceToCenterOfMass: number | null = null;
37
+
38
+ private onFinish: (unitIds: number[], reason: FailureReasons) => void = () => {};
39
+
40
+ constructor(
41
+ private uniqueName: string,
42
+ protected logger: DebugLogger,
43
+ ) {}
44
+
45
+ // TODO call this
46
+ protected updateCenterOfMass(gameApi: GameApi) {
47
+ const movableUnitTiles = this.unitIds
48
+ .map((unitId) => gameApi.getUnitData(unitId))
49
+ .filter((unit) => unit?.canMove)
50
+ .map((unit) => unit?.tile)
51
+ .filter((tile) => !!tile) as Tile[];
52
+ const tileMetrics = calculateCenterOfMass(movableUnitTiles);
53
+ if (tileMetrics) {
54
+ this.centerOfMass = tileMetrics.centerOfMass;
55
+ this.maxDistanceToCenterOfMass = tileMetrics.maxDistance;
56
+ } else {
57
+ this.centerOfMass = null;
58
+ this.maxDistanceToCenterOfMass = null;
59
+ }
60
+ }
11
61
 
12
- private onFinish: (reason: FailureReasons, squad: Squad | null) => void = () => {};
13
-
14
- constructor(private uniqueName: string, private priority: number, protected logger: DebugLogger) {}
62
+ public onAiUpdate(
63
+ gameApi: GameApi,
64
+ actionsApi: ActionsApi,
65
+ playerData: PlayerData,
66
+ matchAwareness: MatchAwareness,
67
+ actionBatcher: ActionBatcher,
68
+ ): MissionAction {
69
+ this.updateCenterOfMass(gameApi);
70
+ return this._onAiUpdate(gameApi, actionsApi, playerData, matchAwareness, actionBatcher);
71
+ }
15
72
 
16
- abstract onAiUpdate(gameApi: GameApi, playerData: PlayerData, matchAwareness: MatchAwareness): MissionAction;
73
+ // TODO: fix this weird indirection
74
+ abstract _onAiUpdate(
75
+ gameApi: GameApi,
76
+ actionsApi: ActionsApi,
77
+ playerData: PlayerData,
78
+ matchAwareness: MatchAwareness,
79
+ actionBatcher: ActionBatcher,
80
+ ): MissionAction;
17
81
 
18
82
  isActive(): boolean {
19
83
  return this.active;
20
84
  }
21
85
 
22
- protected setSquad(squad: Squad): MissionActionRegisterSquad {
23
- this.squad = squad;
24
- return registerSquad(squad);
86
+ public getUnitIds(): number[] {
87
+ return this.unitIds;
88
+ }
89
+
90
+ public removeUnit(unitIdToRemove: number): void {
91
+ this.unitIds = this.unitIds.filter((unitId) => unitId != unitIdToRemove);
92
+ }
93
+
94
+ public addUnit(unitIdToAdd: number): void {
95
+ this.unitIds.push(unitIdToAdd);
25
96
  }
26
97
 
27
- getSquad(): Squad | null {
28
- return this.squad;
98
+ public getUnits(gameApi: GameApi): UnitData[] {
99
+ return this.unitIds
100
+ .map((unitId) => gameApi.getUnitData(unitId))
101
+ .filter((unit) => unit != null)
102
+ .map((unit) => unit!);
29
103
  }
30
104
 
31
- removeSquad() {
32
- // The squad was removed from this mission.
33
- this.squad = null;
105
+ public getUnitsOfTypes(gameApi: GameApi, ...names: string[]): UnitData[] {
106
+ return this.unitIds
107
+ .map((unitId) => gameApi.getUnitData(unitId))
108
+ .filter((unit) => !!unit && names.includes(unit.name))
109
+ .map((unit) => unit!);
110
+ }
111
+
112
+ public getUnitsMatching(gameApi: GameApi, filter: (r: UnitData) => boolean): UnitData[] {
113
+ return this.unitIds
114
+ .map((unitId) => gameApi.getUnitData(unitId))
115
+ .filter((unit) => !!unit && filter(unit))
116
+ .map((unit) => unit!);
117
+ }
118
+
119
+ public getCenterOfMass() {
120
+ return this.centerOfMass;
121
+ }
122
+
123
+ public getMaxDistanceToCenterOfMass() {
124
+ return this.maxDistanceToCenterOfMass;
34
125
  }
35
126
 
36
127
  getUniqueName(): string {
@@ -39,27 +130,37 @@ export abstract class Mission<FailureReasons = undefined> {
39
130
 
40
131
  // Don't call this from the mission itself
41
132
  endMission(reason: FailureReasons): void {
42
- this.onFinish(reason, this.squad);
43
- this.squad = null;
133
+ this.onFinish(this.unitIds, reason);
44
134
  this.active = false;
45
135
  }
46
136
 
47
137
  /**
48
138
  * Declare a callback that is executed when the mission is disbanded for whatever reason.
49
139
  */
50
- then(onFinish: (reason: FailureReasons, squad: Squad | null) => void): Mission<FailureReasons> {
140
+ then(onFinish: (unitIds: number[], reason: FailureReasons) => void): Mission<FailureReasons> {
51
141
  this.onFinish = onFinish;
52
142
  return this;
53
143
  }
144
+
145
+ abstract getGlobalDebugText(): string | undefined;
146
+
147
+ /**
148
+ * Determines whether units can be stolen from this mission by other missions with higher priority.
149
+ */
150
+ public isUnitsLocked(): boolean {
151
+ return true;
152
+ }
153
+
154
+ abstract getPriority(): number;
54
155
  }
55
156
 
56
- export type MissionActionNoop = {
57
- type: "noop";
157
+ export type MissionWithAction<T extends MissionAction> = {
158
+ mission: Mission<any>;
159
+ action: T;
58
160
  };
59
161
 
60
- export type MissionActionRegisterSquad = {
61
- type: "registerSquad";
62
- squad: Squad;
162
+ export type MissionActionNoop = {
163
+ type: "noop";
63
164
  };
64
165
 
65
166
  export type MissionActionDisband = {
@@ -67,17 +168,65 @@ export type MissionActionDisband = {
67
168
  reason: any | null;
68
169
  };
69
170
 
70
- export const noop = () =>
71
- ({
72
- type: "noop",
73
- } as MissionActionNoop);
171
+ export type MissionActionRequestUnits = {
172
+ type: "request";
173
+ unitNames: string[];
174
+ priority: number;
175
+ };
74
176
 
75
- export const registerSquad = (squad: Squad) =>
76
- ({
77
- type: "registerSquad",
78
- squad,
79
- } as MissionActionRegisterSquad);
177
+ export type MissionActionRequestSpecificUnits = {
178
+ type: "requestSpecific";
179
+ unitIds: number[];
180
+ priority: number;
181
+ };
80
182
 
81
- export const disbandMission = (reason?: any) => ({ type: "disband", reason } as MissionActionDisband);
183
+ export type MissionActionGrabFreeCombatants = {
184
+ type: "requestCombatants";
185
+ point: Vector2;
186
+ radius: number;
187
+ };
82
188
 
83
- export type MissionAction = MissionActionNoop | MissionActionRegisterSquad | MissionActionDisband;
189
+ export type MissionActionReleaseUnits = {
190
+ type: "releaseUnits";
191
+ unitIds: number[];
192
+ };
193
+
194
+ export const noop = () =>
195
+ ({
196
+ type: "noop",
197
+ }) as MissionActionNoop;
198
+
199
+ export const disbandMission = (reason?: any) => ({ type: "disband", reason }) as MissionActionDisband;
200
+ export const isDisbandMission = (a: MissionWithAction<MissionAction>): a is MissionWithAction<MissionActionDisband> =>
201
+ a.action.type === "disband";
202
+
203
+ export const requestUnits = (unitNames: string[], priority: number) =>
204
+ ({ type: "request", unitNames, priority }) as MissionActionRequestUnits;
205
+ export const isRequestUnits = (
206
+ a: MissionWithAction<MissionAction>,
207
+ ): a is MissionWithAction<MissionActionRequestUnits> => a.action.type === "request";
208
+
209
+ export const requestSpecificUnits = (unitIds: number[], priority: number) =>
210
+ ({ type: "requestSpecific", unitIds, priority }) as MissionActionRequestSpecificUnits;
211
+ export const isRequestSpecificUnits = (
212
+ a: MissionWithAction<MissionAction>,
213
+ ): a is MissionWithAction<MissionActionRequestSpecificUnits> => a.action.type === "requestSpecific";
214
+
215
+ export const grabCombatants = (point: Vector2, radius: number) =>
216
+ ({ type: "requestCombatants", point, radius }) as MissionActionGrabFreeCombatants;
217
+ export const isGrabCombatants = (
218
+ a: MissionWithAction<MissionAction>,
219
+ ): a is MissionWithAction<MissionActionGrabFreeCombatants> => a.action.type === "requestCombatants";
220
+
221
+ export const releaseUnits = (unitIds: number[]) => ({ type: "releaseUnits", unitIds }) as MissionActionReleaseUnits;
222
+ export const isReleaseUnits = (
223
+ a: MissionWithAction<MissionAction>,
224
+ ): a is MissionWithAction<MissionActionReleaseUnits> => a.action.type === "releaseUnits";
225
+
226
+ export type MissionAction =
227
+ | MissionActionNoop
228
+ | MissionActionDisband
229
+ | MissionActionRequestUnits
230
+ | MissionActionRequestSpecificUnits
231
+ | MissionActionGrabFreeCombatants
232
+ | MissionActionReleaseUnits;