@supalosa/chronodivide-bot 0.2.2-b → 0.3.0

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 (68) hide show
  1. package/TODO.md +0 -2
  2. package/dist/bot/bot.js +2 -2
  3. package/dist/bot/bot.js.map +1 -1
  4. package/dist/bot/logic/awareness.js +7 -6
  5. package/dist/bot/logic/awareness.js.map +1 -1
  6. package/dist/bot/logic/building/ArtilleryUnit.js +6 -5
  7. package/dist/bot/logic/building/antiGroundStaticDefence.js.map +1 -1
  8. package/dist/bot/logic/building/artilleryUnit.js.map +1 -1
  9. package/dist/bot/logic/building/basicAirUnit.js +2 -1
  10. package/dist/bot/logic/building/basicAirUnit.js.map +1 -1
  11. package/dist/bot/logic/building/basicGroundUnit.js +3 -2
  12. package/dist/bot/logic/building/basicGroundUnit.js.map +1 -1
  13. package/dist/bot/logic/building/buildingRules.js +4 -10
  14. package/dist/bot/logic/building/buildingRules.js.map +1 -1
  15. package/dist/bot/logic/building/harvester.js.map +1 -1
  16. package/dist/bot/logic/building/resourceCollectionBuilding.js +5 -3
  17. package/dist/bot/logic/building/resourceCollectionBuilding.js.map +1 -1
  18. package/dist/bot/logic/common/scout.js +49 -32
  19. package/dist/bot/logic/common/scout.js.map +1 -1
  20. package/dist/bot/logic/map/map.js +17 -19
  21. package/dist/bot/logic/map/map.js.map +1 -1
  22. package/dist/bot/logic/map/sector.js +10 -13
  23. package/dist/bot/logic/map/sector.js.map +1 -1
  24. package/dist/bot/logic/mission/missions/attackMission.js +2 -2
  25. package/dist/bot/logic/mission/missions/attackMission.js.map +1 -1
  26. package/dist/bot/logic/mission/missions/defenceMission.js +2 -1
  27. package/dist/bot/logic/mission/missions/defenceMission.js.map +1 -1
  28. package/dist/bot/logic/mission/missions/retreatMission.js.map +1 -1
  29. package/dist/bot/logic/squad/behaviours/combatSquad.js +3 -3
  30. package/dist/bot/logic/squad/behaviours/combatSquad.js.map +1 -1
  31. package/dist/bot/logic/squad/behaviours/common.js +2 -2
  32. package/dist/bot/logic/squad/behaviours/common.js.map +1 -1
  33. package/dist/bot/logic/squad/behaviours/retreatSquad.js.map +1 -1
  34. package/dist/bot/logic/squad/behaviours/scoutingSquad.js +21 -17
  35. package/dist/bot/logic/squad/behaviours/scoutingSquad.js.map +1 -1
  36. package/dist/bot/logic/squad/squad.js +4 -6
  37. package/dist/bot/logic/squad/squad.js.map +1 -1
  38. package/dist/bot/logic/squad/squadBehaviour.js.map +1 -1
  39. package/dist/bot/logic/squad/squadController.js +35 -23
  40. package/dist/bot/logic/squad/squadController.js.map +1 -1
  41. package/dist/bot/logic/threat/threatCalculator.js +4 -3
  42. package/dist/bot/logic/threat/threatCalculator.js.map +1 -1
  43. package/dist/exampleBot.js +1 -1
  44. package/package.json +3 -3
  45. package/src/bot/bot.ts +4 -5
  46. package/src/bot/logic/awareness.ts +12 -12
  47. package/src/bot/logic/building/antiGroundStaticDefence.ts +11 -7
  48. package/src/bot/logic/building/artilleryUnit.ts +14 -17
  49. package/src/bot/logic/building/basicAirUnit.ts +9 -7
  50. package/src/bot/logic/building/basicGroundUnit.ts +3 -3
  51. package/src/bot/logic/building/buildingRules.ts +11 -13
  52. package/src/bot/logic/building/harvester.ts +7 -4
  53. package/src/bot/logic/building/resourceCollectionBuilding.ts +8 -12
  54. package/src/bot/logic/common/scout.ts +83 -38
  55. package/src/bot/logic/map/map.ts +26 -30
  56. package/src/bot/logic/map/sector.ts +17 -21
  57. package/src/bot/logic/mission/missions/attackMission.ts +5 -5
  58. package/src/bot/logic/mission/missions/defenceMission.ts +3 -3
  59. package/src/bot/logic/mission/missions/retreatMission.ts +2 -2
  60. package/src/bot/logic/squad/behaviours/combatSquad.ts +6 -6
  61. package/src/bot/logic/squad/behaviours/common.ts +3 -3
  62. package/src/bot/logic/squad/behaviours/retreatSquad.ts +2 -2
  63. package/src/bot/logic/squad/behaviours/scoutingSquad.ts +25 -22
  64. package/src/bot/logic/squad/squad.ts +6 -10
  65. package/src/bot/logic/squad/squadBehaviour.ts +9 -10
  66. package/src/bot/logic/squad/squadController.ts +0 -1
  67. package/src/bot/logic/threat/threatCalculator.ts +100 -99
  68. package/src/exampleBot.ts +1 -1
@@ -1,9 +1,8 @@
1
- import { ActionsApi, GameApi, PlayerData, Point2D, TechnoRules, Tile, UnitData } from "@chronodivide/game-api";
1
+ import { ActionsApi, GameApi, PlayerData, TechnoRules, Tile, UnitData, Vector2 } from "@chronodivide/game-api";
2
2
  import { Mission } from "../mission/mission.js";
3
- import { GlobalThreat } from "../threat/threat.js";
4
3
  import { SquadAction, SquadBehaviour, disband } from "./squadBehaviour.js";
5
4
  import { MatchAwareness } from "../awareness.js";
6
- import { getDistanceBetweenPoints } from "../map/map.js";
5
+ import { getDistanceBetweenTileAndPoint } from "../map/map.js";
7
6
  import { DebugLogger } from "../common/utils.js";
8
7
 
9
8
  export enum SquadLiveness {
@@ -18,7 +17,7 @@ export type SquadConstructionRequest = {
18
17
  };
19
18
 
20
19
  const calculateCenterOfMass: (unitTiles: Tile[]) => {
21
- centerOfMass: Point2D;
20
+ centerOfMass: Vector2;
22
21
  maxDistance: number;
23
22
  } | null = (unitTiles) => {
24
23
  if (unitTiles.length === 0) {
@@ -34,13 +33,10 @@ const calculateCenterOfMass: (unitTiles: Tile[]) => {
34
33
  },
35
34
  { x: 0, y: 0 },
36
35
  );
37
- const centerOfMass = {
38
- x: Math.round(sums.x / unitTiles.length),
39
- y: Math.round(sums.y / unitTiles.length),
40
- };
36
+ const centerOfMass = new Vector2(Math.round(sums.x / unitTiles.length), Math.round(sums.y / unitTiles.length));
41
37
 
42
38
  // max distance of units to the center of mass
43
- const distances = unitTiles.map((tile) => getDistanceBetweenPoints({ x: tile.rx, y: tile.ry }, centerOfMass));
39
+ const distances = unitTiles.map((tile) => getDistanceBetweenTileAndPoint(tile, centerOfMass));
44
40
  const maxDistance = Math.max(...distances);
45
41
  return { centerOfMass, maxDistance };
46
42
  };
@@ -49,7 +45,7 @@ export class Squad {
49
45
  private unitIds: number[] = [];
50
46
  private liveness: SquadLiveness = SquadLiveness.SquadActive;
51
47
  private lastLivenessUpdateTick: number = 0;
52
- private centerOfMass: Point2D | null = null;
48
+ private centerOfMass: Vector2 | null = null;
53
49
  private maxDistanceToCenterOfMass: number | null = null;
54
50
 
55
51
  constructor(
@@ -1,5 +1,4 @@
1
- import { ActionsApi, GameApi, PlayerData, Point2D } from "@chronodivide/game-api";
2
- import { GlobalThreat } from "../threat/threat.js";
1
+ import { ActionsApi, GameApi, PlayerData, Vector2 } from "@chronodivide/game-api";
3
2
  import { Squad } from "./squad.js";
4
3
  import { MatchAwareness } from "../awareness.js";
5
4
  import { DebugLogger } from "../common/utils.js";
@@ -26,22 +25,22 @@ export type SquadActionRequestSpecificUnits = {
26
25
  };
27
26
  export type SquadActionGrabFreeCombatants = {
28
27
  type: "requestCombatants";
29
- point: Point2D;
28
+ point: Vector2;
30
29
  radius: number;
31
30
  };
32
31
 
33
- export const noop = () => ({ type: "noop" } as SquadActionNoop);
32
+ export const noop = () => ({ type: "noop" }) as SquadActionNoop;
34
33
 
35
- export const disband = () => ({ type: "disband" } as SquadActionDisband);
34
+ export const disband = () => ({ type: "disband" }) as SquadActionDisband;
36
35
 
37
36
  export const requestUnits = (unitNames: string[], priority: number) =>
38
- ({ type: "request", unitNames, priority } as SquadActionRequestUnits);
37
+ ({ type: "request", unitNames, priority }) as SquadActionRequestUnits;
39
38
 
40
39
  export const requestSpecificUnits = (unitIds: number[], priority: number) =>
41
- ({ type: "requestSpecific", unitIds, priority } as SquadActionRequestSpecificUnits);
40
+ ({ type: "requestSpecific", unitIds, priority }) as SquadActionRequestSpecificUnits;
42
41
 
43
- export const grabCombatants = (point: Point2D, radius: number) =>
44
- ({ type: "requestCombatants", point, radius } as SquadActionGrabFreeCombatants);
42
+ export const grabCombatants = (point: Vector2, radius: number) =>
43
+ ({ type: "requestCombatants", point, radius }) as SquadActionGrabFreeCombatants;
45
44
 
46
45
  export type SquadAction =
47
46
  | SquadActionNoop
@@ -58,6 +57,6 @@ export interface SquadBehaviour {
58
57
  playerData: PlayerData,
59
58
  squad: Squad,
60
59
  matchAwareness: MatchAwareness,
61
- logger: DebugLogger
60
+ logger: DebugLogger,
62
61
  ): SquadAction;
63
62
  }
@@ -179,7 +179,6 @@ export class SquadController {
179
179
  .map((unit) => unit!);
180
180
 
181
181
  type AssignmentWithType = { unitName: string; squad: string; method: "type" | "grab" };
182
- // [squadName][unitName]['type' | 'grab']
183
182
  const newAssignmentsByType = freeUnits
184
183
  .flatMap((freeUnit) => {
185
184
  if (unitTypeToHighestRequest.hasOwnProperty(freeUnit.name)) {
@@ -1,99 +1,100 @@
1
- import { GameApi, MovementZone, ObjectType, PlayerData, UnitData } from "@chronodivide/game-api";
2
- import { GlobalThreat } from "./threat.js";
3
-
4
- export function calculateGlobalThreat(game: GameApi, playerData: PlayerData, visibleAreaPercent: number): GlobalThreat {
5
- let groundUnits = game.getVisibleUnits(
6
- playerData.name,
7
- "hostile",
8
- (r) => r.type == ObjectType.Vehicle || r.type == ObjectType.Infantry,
9
- );
10
- let airUnits = game.getVisibleUnits(playerData.name, "hostile", (r) => r.movementZone == MovementZone.Fly);
11
- let groundDefence = game
12
- .getVisibleUnits(playerData.name, "hostile", (r) => r.type == ObjectType.Building)
13
- .filter((unitId) => isAntiGround(game, unitId));
14
- let antiAirPower = game
15
- .getVisibleUnits(playerData.name, "hostile", (r) => r.type != ObjectType.Building)
16
- .filter((unitId) => isAntiAir(game, unitId));
17
-
18
- let ourAntiGroundUnits = game
19
- .getVisibleUnits(playerData.name, "self", (r) => r.isSelectableCombatant)
20
- .filter((unitId) => isAntiGround(game, unitId));
21
- let ourAntiAirUnits = game
22
- .getVisibleUnits(playerData.name, "self", (r) => r.isSelectableCombatant)
23
- .filter((unitId) => isAntiAir(game, unitId));
24
- let ourGroundDefence = game
25
- .getVisibleUnits(playerData.name, "self", (r) => r.type == ObjectType.Building)
26
- .filter((unitId) => isAntiGround(game, unitId));
27
- let ourAirUnits = game.getVisibleUnits(
28
- playerData.name,
29
- "self",
30
- (r) => r.movementZone == MovementZone.Fly && r.isSelectableCombatant,
31
- );
32
-
33
- let observedGroundThreat = calculateFirepowerForUnits(game, groundUnits);
34
- let observedAirThreat = calculateFirepowerForUnits(game, airUnits);
35
- let observedAntiAirThreat = calculateFirepowerForUnits(game, antiAirPower);
36
- let observedGroundDefence = calculateFirepowerForUnits(game, groundDefence);
37
-
38
- let ourAntiGroundPower = calculateFirepowerForUnits(game, ourAntiGroundUnits);
39
- let ourAntiAirPower = calculateFirepowerForUnits(game, ourAntiAirUnits);
40
- let ourAirPower = calculateFirepowerForUnits(game, ourAirUnits);
41
- let ourGroundDefencePower = calculateFirepowerForUnits(game, ourGroundDefence);
42
-
43
- return new GlobalThreat(
44
- visibleAreaPercent,
45
- observedGroundThreat,
46
- observedAirThreat,
47
- observedAntiAirThreat,
48
- observedGroundDefence * 0.25,
49
- ourGroundDefencePower * 0.25,
50
- ourAntiGroundPower,
51
- ourAntiAirPower,
52
- ourAirPower,
53
- );
54
- }
55
-
56
- function isAntiGround(gameApi: GameApi, unitId: number): boolean {
57
- let unit = gameApi.getUnitData(unitId);
58
- if (unit && unit.primaryWeapon) {
59
- return unit.primaryWeapon.projectileRules.isAntiGround;
60
- }
61
- return false;
62
- }
63
-
64
- function isAntiAir(gameApi: GameApi, unitId: number): boolean {
65
- let unit = gameApi.getUnitData(unitId);
66
- if (unit && unit.primaryWeapon) {
67
- return unit.primaryWeapon.projectileRules.isAntiAir;
68
- }
69
- return false;
70
- }
71
-
72
- function calculateFirepowerForUnit(unitData: UnitData): number {
73
- let threat = 0;
74
- let hpRatio = unitData.hitPoints / Math.max(1, unitData.maxHitPoints);
75
- if (unitData.primaryWeapon) {
76
- threat +=
77
- (hpRatio *
78
- ((unitData.primaryWeapon.rules.damage + 1) * Math.sqrt(unitData.primaryWeapon.rules.range + 1))) /
79
- Math.max(unitData.primaryWeapon.cooldownTicks, 1);
80
- }
81
- if (unitData.secondaryWeapon) {
82
- threat +=
83
- (hpRatio *
84
- ((unitData.secondaryWeapon.rules.damage + 1) * Math.sqrt(unitData.secondaryWeapon.rules.range + 1))) /
85
- Math.max(unitData.secondaryWeapon.cooldownTicks, 1);
86
- }
87
- return Math.min(800, threat);
88
- }
89
-
90
- function calculateFirepowerForUnits(game: GameApi, unitIds: number[]) {
91
- let threat = 0;
92
- unitIds.forEach((unitId) => {
93
- let unitData = game.getUnitData(unitId);
94
- if (unitData) {
95
- threat += calculateFirepowerForUnit(unitData);
96
- }
97
- });
98
- return threat;
99
- }
1
+ import { GameApi, GameMath, MovementZone, ObjectType, PlayerData, UnitData } from "@chronodivide/game-api";
2
+ import { GlobalThreat } from "./threat.js";
3
+
4
+ export function calculateGlobalThreat(game: GameApi, playerData: PlayerData, visibleAreaPercent: number): GlobalThreat {
5
+ let groundUnits = game.getVisibleUnits(
6
+ playerData.name,
7
+ "hostile",
8
+ (r) => r.type == ObjectType.Vehicle || r.type == ObjectType.Infantry,
9
+ );
10
+ let airUnits = game.getVisibleUnits(playerData.name, "hostile", (r) => r.movementZone == MovementZone.Fly);
11
+ let groundDefence = game
12
+ .getVisibleUnits(playerData.name, "hostile", (r) => r.type == ObjectType.Building)
13
+ .filter((unitId) => isAntiGround(game, unitId));
14
+ let antiAirPower = game
15
+ .getVisibleUnits(playerData.name, "hostile", (r) => r.type != ObjectType.Building)
16
+ .filter((unitId) => isAntiAir(game, unitId));
17
+
18
+ let ourAntiGroundUnits = game
19
+ .getVisibleUnits(playerData.name, "self", (r) => r.isSelectableCombatant)
20
+ .filter((unitId) => isAntiGround(game, unitId));
21
+ let ourAntiAirUnits = game
22
+ .getVisibleUnits(playerData.name, "self", (r) => r.isSelectableCombatant)
23
+ .filter((unitId) => isAntiAir(game, unitId));
24
+ let ourGroundDefence = game
25
+ .getVisibleUnits(playerData.name, "self", (r) => r.type == ObjectType.Building)
26
+ .filter((unitId) => isAntiGround(game, unitId));
27
+ let ourAirUnits = game.getVisibleUnits(
28
+ playerData.name,
29
+ "self",
30
+ (r) => r.movementZone == MovementZone.Fly && r.isSelectableCombatant,
31
+ );
32
+
33
+ let observedGroundThreat = calculateFirepowerForUnits(game, groundUnits);
34
+ let observedAirThreat = calculateFirepowerForUnits(game, airUnits);
35
+ let observedAntiAirThreat = calculateFirepowerForUnits(game, antiAirPower);
36
+ let observedGroundDefence = calculateFirepowerForUnits(game, groundDefence);
37
+
38
+ let ourAntiGroundPower = calculateFirepowerForUnits(game, ourAntiGroundUnits);
39
+ let ourAntiAirPower = calculateFirepowerForUnits(game, ourAntiAirUnits);
40
+ let ourAirPower = calculateFirepowerForUnits(game, ourAirUnits);
41
+ let ourGroundDefencePower = calculateFirepowerForUnits(game, ourGroundDefence);
42
+
43
+ return new GlobalThreat(
44
+ visibleAreaPercent,
45
+ observedGroundThreat,
46
+ observedAirThreat,
47
+ observedAntiAirThreat,
48
+ observedGroundDefence * 0.25,
49
+ ourGroundDefencePower * 0.25,
50
+ ourAntiGroundPower,
51
+ ourAntiAirPower,
52
+ ourAirPower,
53
+ );
54
+ }
55
+
56
+ function isAntiGround(gameApi: GameApi, unitId: number): boolean {
57
+ let unit = gameApi.getUnitData(unitId);
58
+ if (unit && unit.primaryWeapon) {
59
+ return unit.primaryWeapon.projectileRules.isAntiGround;
60
+ }
61
+ return false;
62
+ }
63
+
64
+ function isAntiAir(gameApi: GameApi, unitId: number): boolean {
65
+ let unit = gameApi.getUnitData(unitId);
66
+ if (unit && unit.primaryWeapon) {
67
+ return unit.primaryWeapon.projectileRules.isAntiAir;
68
+ }
69
+ return false;
70
+ }
71
+
72
+ function calculateFirepowerForUnit(unitData: UnitData): number {
73
+ let threat = 0;
74
+ let hpRatio = unitData.hitPoints / Math.max(1, unitData.maxHitPoints);
75
+ if (unitData.primaryWeapon) {
76
+ threat +=
77
+ (hpRatio *
78
+ ((unitData.primaryWeapon.rules.damage + 1) * GameMath.sqrt(unitData.primaryWeapon.rules.range + 1))) /
79
+ Math.max(unitData.primaryWeapon.cooldownTicks, 1);
80
+ }
81
+ if (unitData.secondaryWeapon) {
82
+ threat +=
83
+ (hpRatio *
84
+ ((unitData.secondaryWeapon.rules.damage + 1) *
85
+ GameMath.sqrt(unitData.secondaryWeapon.rules.range + 1))) /
86
+ Math.max(unitData.secondaryWeapon.cooldownTicks, 1);
87
+ }
88
+ return Math.min(800, threat);
89
+ }
90
+
91
+ function calculateFirepowerForUnits(game: GameApi, unitIds: number[]) {
92
+ let threat = 0;
93
+ unitIds.forEach((unitId) => {
94
+ let unitData = game.getUnitData(unitId);
95
+ if (unitData) {
96
+ threat += calculateFirepowerForUnit(unitData);
97
+ }
98
+ });
99
+ return threat;
100
+ }
package/src/exampleBot.ts CHANGED
@@ -16,7 +16,7 @@ async function main() {
16
16
  Other maps:
17
17
  mp03t4 large map, no oil derricks
18
18
  */
19
- const mapName = "tn04t2.map";
19
+ const mapName = "mp10s4.map";
20
20
  // Bot names must be unique in online mode
21
21
  const botName = `Joe${String(Date.now()).substr(-6)}`;
22
22
  const otherBotName = `Bob${String(Date.now() + 1).substr(-6)}`;