@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.
- package/.env.template +4 -4
- package/.github/workflows/npm-publish.yml +24 -0
- package/README.md +108 -97
- package/dist/bot/bot.js +105 -105
- package/dist/bot/bot.js.map +1 -1
- package/dist/bot/logic/awareness.js +136 -136
- package/dist/bot/logic/building/antiAirStaticDefence.js +42 -42
- package/dist/bot/logic/building/antiGroundStaticDefence.js +34 -30
- package/dist/bot/logic/building/antiGroundStaticDefence.js.map +1 -1
- package/dist/bot/logic/building/{ArtilleryUnit.js → artilleryUnit.js} +18 -18
- package/dist/bot/logic/building/basicAirUnit.js +19 -19
- package/dist/bot/logic/building/basicBuilding.js +26 -26
- package/dist/bot/logic/building/basicGroundUnit.js +19 -19
- package/dist/bot/logic/building/buildingRules.js +175 -174
- package/dist/bot/logic/building/buildingRules.js.map +1 -1
- package/dist/bot/logic/building/common.js +19 -18
- package/dist/bot/logic/building/common.js.map +1 -1
- package/dist/bot/logic/building/harvester.js +16 -16
- package/dist/bot/logic/building/powerPlant.js +20 -20
- package/dist/bot/logic/building/queueController.js +183 -183
- package/dist/bot/logic/building/resourceCollectionBuilding.js +36 -36
- package/dist/bot/logic/common/scout.js +126 -126
- package/dist/bot/logic/common/utils.js +95 -85
- package/dist/bot/logic/common/utils.js.map +1 -1
- package/dist/bot/logic/composition/alliedCompositions.js +12 -12
- package/dist/bot/logic/composition/common.js +1 -1
- package/dist/bot/logic/composition/sovietCompositions.js +12 -12
- package/dist/bot/logic/map/map.js +44 -44
- package/dist/bot/logic/map/sector.js +137 -137
- package/dist/bot/logic/mission/actionBatcher.js +91 -91
- package/dist/bot/logic/mission/mission.js +122 -122
- package/dist/bot/logic/mission/missionController.js +321 -321
- package/dist/bot/logic/mission/missionFactories.js +12 -12
- package/dist/bot/logic/mission/missions/attackMission.js +214 -214
- package/dist/bot/logic/mission/missions/defenceMission.js +82 -82
- package/dist/bot/logic/mission/missions/engineerMission.js +63 -63
- package/dist/bot/logic/mission/missions/expansionMission.js +60 -60
- package/dist/bot/logic/mission/missions/retreatMission.js +33 -33
- package/dist/bot/logic/mission/missions/scoutingMission.js +133 -133
- package/dist/bot/logic/mission/missions/squads/combatSquad.js +115 -115
- package/dist/bot/logic/mission/missions/squads/common.js +57 -57
- package/dist/bot/logic/mission/missions/squads/squad.js +1 -1
- package/dist/bot/logic/threat/threat.js +22 -22
- package/dist/bot/logic/threat/threatCalculator.js +73 -73
- package/dist/exampleBot.js +100 -112
- package/dist/exampleBot.js.map +1 -1
- package/package.json +32 -29
- package/src/bot/bot.ts +161 -161
- package/src/bot/logic/awareness.ts +245 -245
- package/src/bot/logic/building/antiAirStaticDefence.ts +64 -64
- package/src/bot/logic/building/antiGroundStaticDefence.ts +55 -51
- package/src/bot/logic/building/artilleryUnit.ts +39 -39
- package/src/bot/logic/building/basicAirUnit.ts +39 -39
- package/src/bot/logic/building/basicBuilding.ts +49 -49
- package/src/bot/logic/building/basicGroundUnit.ts +39 -39
- package/src/bot/logic/building/buildingRules.ts +250 -247
- package/src/bot/logic/building/common.ts +21 -23
- package/src/bot/logic/building/harvester.ts +31 -31
- package/src/bot/logic/building/powerPlant.ts +32 -32
- package/src/bot/logic/building/queueController.ts +297 -297
- package/src/bot/logic/building/resourceCollectionBuilding.ts +52 -52
- package/src/bot/logic/common/scout.ts +183 -183
- package/src/bot/logic/common/utils.ts +120 -112
- package/src/bot/logic/composition/alliedCompositions.ts +22 -22
- package/src/bot/logic/composition/common.ts +3 -3
- package/src/bot/logic/composition/sovietCompositions.ts +21 -21
- package/src/bot/logic/map/map.ts +66 -66
- package/src/bot/logic/map/sector.ts +174 -174
- package/src/bot/logic/mission/actionBatcher.ts +124 -124
- package/src/bot/logic/mission/mission.ts +232 -232
- package/src/bot/logic/mission/missionController.ts +413 -413
- package/src/bot/logic/mission/missionFactories.ts +51 -51
- package/src/bot/logic/mission/missions/attackMission.ts +336 -336
- package/src/bot/logic/mission/missions/defenceMission.ts +151 -151
- package/src/bot/logic/mission/missions/engineerMission.ts +113 -113
- package/src/bot/logic/mission/missions/expansionMission.ts +104 -104
- package/src/bot/logic/mission/missions/retreatMission.ts +54 -54
- package/src/bot/logic/mission/missions/scoutingMission.ts +186 -186
- package/src/bot/logic/mission/missions/squads/combatSquad.ts +160 -160
- package/src/bot/logic/mission/missions/squads/common.ts +63 -63
- package/src/bot/logic/mission/missions/squads/squad.ts +19 -19
- package/src/bot/logic/threat/threatCalculator.ts +100 -100
- package/src/exampleBot.ts +111 -124
- package/tsconfig.json +73 -73
- package/dist/bot/logic/building/building.js +0 -82
- package/dist/bot/logic/building/massedAntiGroundUnit.js +0 -20
- package/dist/bot/logic/building/queues.js +0 -19
- package/dist/bot/logic/knowledge.js +0 -1
- package/dist/bot/logic/mission/basicMission.js +0 -26
- package/dist/bot/logic/mission/behaviours/combatSquad.js +0 -124
- package/dist/bot/logic/mission/behaviours/combatSquad.js.map +0 -1
- package/dist/bot/logic/mission/behaviours/common.js +0 -56
- package/dist/bot/logic/mission/behaviours/common.js.map +0 -1
- package/dist/bot/logic/mission/behaviours/engineerSquad.js +0 -39
- package/dist/bot/logic/mission/behaviours/engineerSquad.js.map +0 -1
- package/dist/bot/logic/mission/behaviours/expansionSquad.js +0 -46
- package/dist/bot/logic/mission/behaviours/expansionSquad.js.map +0 -1
- package/dist/bot/logic/mission/behaviours/retreatSquad.js +0 -31
- package/dist/bot/logic/mission/behaviours/retreatSquad.js.map +0 -1
- package/dist/bot/logic/mission/behaviours/scoutingSquad.js +0 -94
- package/dist/bot/logic/mission/behaviours/scoutingSquad.js.map +0 -1
- package/dist/bot/logic/mission/expansionMission.js +0 -32
- package/dist/bot/logic/mission/missions/basicMission.js +0 -13
- package/dist/bot/logic/mission/missions/basicMission.js.map +0 -1
- package/dist/bot/logic/mission/missions/missionBehaviour.js +0 -2
- package/dist/bot/logic/mission/missions/missionBehaviour.js.map +0 -1
- package/dist/bot/logic/mission/missions/oneTimeMission.js +0 -27
- package/dist/bot/logic/mission/missions/oneTimeMission.js.map +0 -1
- package/dist/bot/logic/squad/behaviours/actionBatcher.js +0 -36
- package/dist/bot/logic/squad/behaviours/actionBatcher.js.map +0 -1
- package/dist/bot/logic/squad/behaviours/attackSquad.js +0 -82
- package/dist/bot/logic/squad/behaviours/combatSquad.js +0 -106
- package/dist/bot/logic/squad/behaviours/combatSquad.js.map +0 -1
- package/dist/bot/logic/squad/behaviours/common.js +0 -55
- package/dist/bot/logic/squad/behaviours/common.js.map +0 -1
- package/dist/bot/logic/squad/behaviours/defenceSquad.js +0 -48
- package/dist/bot/logic/squad/behaviours/engineerSquad.js +0 -38
- package/dist/bot/logic/squad/behaviours/engineerSquad.js.map +0 -1
- package/dist/bot/logic/squad/behaviours/expansionSquad.js +0 -45
- package/dist/bot/logic/squad/behaviours/expansionSquad.js.map +0 -1
- package/dist/bot/logic/squad/behaviours/retreatSquad.js +0 -31
- package/dist/bot/logic/squad/behaviours/retreatSquad.js.map +0 -1
- package/dist/bot/logic/squad/behaviours/scoutingSquad.js +0 -93
- package/dist/bot/logic/squad/behaviours/scoutingSquad.js.map +0 -1
- package/dist/bot/logic/squad/behaviours/squadExpansion.js +0 -31
- package/dist/bot/logic/squad/behaviours/squadScouters.js +0 -8
- package/dist/bot/logic/squad/squad.js +0 -126
- package/dist/bot/logic/squad/squad.js.map +0 -1
- package/dist/bot/logic/squad/squadBehaviour.js +0 -6
- package/dist/bot/logic/squad/squadBehaviour.js.map +0 -1
- package/dist/bot/logic/squad/squadBehaviours.js +0 -7
- package/dist/bot/logic/squad/squadBehaviours.js.map +0 -1
- package/dist/bot/logic/squad/squadController.js +0 -215
- package/dist/bot/logic/squad/squadController.js.map +0 -1
package/dist/exampleBot.js
CHANGED
|
@@ -1,113 +1,101 @@
|
|
|
1
|
-
import "dotenv/config";
|
|
2
|
-
import { cdapi } from "@chronodivide/game-api";
|
|
3
|
-
import { SupalosaBot } from "./bot/bot.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
CDR2 1v1
|
|
11
|
-
CDR2 1v1
|
|
12
|
-
CDR2 1v1
|
|
13
|
-
CDR2 1v1
|
|
14
|
-
CDR2 1v1
|
|
15
|
-
CDR2 1v1
|
|
16
|
-
CDR2 1v1
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
console.log("
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
console.log(`Game forced to end due to timeout`);
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
await game.update();
|
|
105
|
-
}
|
|
106
|
-
game.saveReplay();
|
|
107
|
-
game.dispose();
|
|
108
|
-
}
|
|
109
|
-
main().catch((e) => {
|
|
110
|
-
console.error(e);
|
|
111
|
-
process.exit(1);
|
|
112
|
-
});
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import { cdapi } from "@chronodivide/game-api";
|
|
3
|
+
import { SupalosaBot } from "./bot/bot.js";
|
|
4
|
+
import { Countries } from "./bot/logic/common/utils.js";
|
|
5
|
+
// The game will automatically end after this time. This is to handle stalemates.
|
|
6
|
+
const MAX_GAME_LENGTH_SECONDS = 7200; // 7200 = two hours
|
|
7
|
+
async function main() {
|
|
8
|
+
/*
|
|
9
|
+
Ladder maps:
|
|
10
|
+
CDR2 1v1 2_malibu_cliffs_le.map
|
|
11
|
+
CDR2 1v1 4_country_swing_le_v2.map
|
|
12
|
+
CDR2 1v1 mp01t4.map, large map, oil derricks
|
|
13
|
+
CDR2 1v1 tn04t2.map, small map
|
|
14
|
+
CDR2 1v1 mp10s4.map <- depth charge, naval map (not supported). Cramped in position 1.
|
|
15
|
+
CDR2 1v1 heckcorners.map
|
|
16
|
+
CDR2 1v1 4_montana_dmz_le.map
|
|
17
|
+
CDR2 1v1 barrel.map
|
|
18
|
+
|
|
19
|
+
Other maps:
|
|
20
|
+
mp03t4 large map, no oil derricks
|
|
21
|
+
mp02t2.map,mp06t2.map,mp11t2.map,mp08t2.map,mp21s2.map,mp14t2.map,mp29u2.map,mp31s2.map,mp18s3.map,mp09t3.map,mp01t4.map,mp03t4.map,mp05t4.map,mp10s4.map,mp12s4.map,mp13s4.map,mp19t4.map,
|
|
22
|
+
mp15s4.map,mp16s4.map,mp23t4.map,mp33u4.map,mp34u4.map,mp17t6.map,mp20t6.map,mp25t6.map,mp26s6.map,mp30s6.map,mp22s8.map,mp27t8.map,mp32s8.map,mp06mw.map,mp08mw.map,mp14mw.map,mp29mw.map,
|
|
23
|
+
mp05mw.map,mp13mw.map,mp15mw.map,mp16mw.map,mp23mw.map,mp17mw.map,mp25mw.map,mp30mw.map,mp22mw.map,mp27mw.map,mp32mw.map,mp09du.map,mp01du.map,mp05du.map,mp13du.map,mp15du.map,mp18du.map,
|
|
24
|
+
mp24du.map,mp17du.map,mp25du.map,mp27du.map,mp32du.map,c1m1a.map,c1m1b.map,c1m1c.map,c1m2a.map,c1m2b.map,c1m2c.map,c1m3a.map,c1m3b.map,c1m3c.map,c1m4a.map,c1m4b.map,c1m4c.map,c1m5a.map,
|
|
25
|
+
c1m5b.map,c1m5c.map,c2m1a.map,c2m1b.map,c2m1c.map,c2m2a.map,c2m2b.map,c2m2c.map,c2m3a.map,c2m3b.map,c2m3c.map,c2m4a.map,c2m4b.map,c2m4c.map,c2m5a.map,c2m5b.map,c2m5c.map,c3m1a.map,c3m1b.map,
|
|
26
|
+
c3m1c.map,c3m2a.map,c3m2b.map,c3m2c.map,c3m3a.map,c3m3b.map,c3m3c.map,c3m4a.map,c3m4b.map,c3m4c.map,c3m5a.map,c3m5b.map,c3m5c.map,c4m1a.map,c4m1b.map,c4m1c.map,c4m2a.map,c4m2b.map,c4m2c.map,
|
|
27
|
+
c4m3a.map,c4m3b.map,c4m3c.map,c4m4a.map,c4m4b.map,c4m4c.map,c4m5a.map,c4m5b.map,c4m5c.map,c5m1a.map,c5m1b.map,c5m1c.map,c5m2a.map,c5m2b.map,c5m2c.map,c5m3a.map,c5m3b.map,c5m3c.map,c5m4a.map,
|
|
28
|
+
c5m4b.map,c5m4c.map,c5m5a.map,c5m5b.map,c5m5c.map,tn01t2.map,tn01mw.map,tn04t2.map,tn04mw.map,tn02s4.map,tn02mw.map,amazon01.map,eb1.map,eb2.map,eb3.map,eb4.map,eb5.map,invasion.map,arena.map,
|
|
29
|
+
barrel.map,bayopigs.map,bermuda.map,break.map,carville.map,deadman.map,death.map,disaster.map,dustbowl.map,goldst.map,grinder.map,hailmary.map,hills.map,kaliforn.map,killer.map,lostlake.map,
|
|
30
|
+
newhghts.map,oceansid.map,pacific.map,potomac.map,powdrkeg.map,rockets.map,roulette.map,round.map,seaofiso.map,shrapnel.map,tanyas.map,tower.map,tsunami.map,valley.map,xmas.map,yuriplot.map,
|
|
31
|
+
cavernsofsiberia.map,countryswingfixed.map,4_country_swing_le_v2.map,dorado_descent_yr_port.mpr,dryheat.map,dunepatrolremake.map,heckbvb.map,heckcorners.map,heckgolden.mpr,heckcorners_b.map,
|
|
32
|
+
heckcorners_b_golden.map,hecklvl.map,heckrvr.map,hecktvt.map,isleland.map,jungleofvietnam.map,2_malibu_cliffs_le.map,mojosprt.map,4_montana_dmz_le.map,6_near_ore_far.map,8_near_ore_far.map,
|
|
33
|
+
offensedefense.map,ore2_startfixed.map,rekoool_fast_6players.mpr,rekoool_fast_8players.mpr,riverram.map,tourofegypt.map,unrepent.map,sinkswim_yr_port.map
|
|
34
|
+
*/
|
|
35
|
+
const mapName = "heckcorners_b.map";
|
|
36
|
+
// Bot names must be unique in online mode
|
|
37
|
+
const timestamp = String(Date.now()).substr(-6);
|
|
38
|
+
const firstBotName = `Joe${timestamp}`;
|
|
39
|
+
const secondBotName = `Bob${timestamp}`;
|
|
40
|
+
const thirdBotName = `Mike${timestamp}`;
|
|
41
|
+
const fourthBotName = `Charlie${timestamp}`;
|
|
42
|
+
await cdapi.init(process.env.MIX_DIR || "./");
|
|
43
|
+
console.log("Server URL: " + process.env.SERVER_URL);
|
|
44
|
+
console.log("Client URL: " + process.env.CLIENT_URL);
|
|
45
|
+
const baseSettings = {
|
|
46
|
+
buildOffAlly: false,
|
|
47
|
+
cratesAppear: false,
|
|
48
|
+
credits: 10000,
|
|
49
|
+
gameMode: cdapi.getAvailableGameModes(mapName)[0],
|
|
50
|
+
gameSpeed: 6,
|
|
51
|
+
mapName,
|
|
52
|
+
mcvRepacks: true,
|
|
53
|
+
shortGame: true,
|
|
54
|
+
superWeapons: false,
|
|
55
|
+
unitCount: 0,
|
|
56
|
+
};
|
|
57
|
+
const onlineSettings = {
|
|
58
|
+
...baseSettings,
|
|
59
|
+
online: true,
|
|
60
|
+
serverUrl: process.env.SERVER_URL,
|
|
61
|
+
clientUrl: process.env.CLIENT_URL,
|
|
62
|
+
agents: [
|
|
63
|
+
new SupalosaBot(process.env.ONLINE_BOT_NAME ?? firstBotName, Countries.USA),
|
|
64
|
+
{ name: process.env.PLAYER_NAME ?? secondBotName, country: Countries.FRANCE },
|
|
65
|
+
],
|
|
66
|
+
botPassword: process.env.ONLINE_BOT_PASSWORD ?? "default",
|
|
67
|
+
};
|
|
68
|
+
const offlineSettings1v1 = {
|
|
69
|
+
...baseSettings,
|
|
70
|
+
online: false,
|
|
71
|
+
agents: [
|
|
72
|
+
new SupalosaBot(firstBotName, Countries.FRANCE, [], false),
|
|
73
|
+
new SupalosaBot(secondBotName, Countries.RUSSIA, [], true).setDebugMode(true),
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
const offlineSettings2v2 = {
|
|
77
|
+
...baseSettings,
|
|
78
|
+
online: false,
|
|
79
|
+
agents: [
|
|
80
|
+
new SupalosaBot(firstBotName, Countries.FRANCE, [firstBotName], false),
|
|
81
|
+
new SupalosaBot(secondBotName, Countries.RUSSIA, [firstBotName], true).setDebugMode(true),
|
|
82
|
+
new SupalosaBot(thirdBotName, Countries.RUSSIA, [fourthBotName], false),
|
|
83
|
+
new SupalosaBot(fourthBotName, Countries.FRANCE, [thirdBotName], false),
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
const game = await cdapi.createGame(process.env.ONLINE_MATCH ? onlineSettings : offlineSettings1v1);
|
|
87
|
+
while (!game.isFinished()) {
|
|
88
|
+
if (!!MAX_GAME_LENGTH_SECONDS && game.getCurrentTick() / 15 > MAX_GAME_LENGTH_SECONDS) {
|
|
89
|
+
console.log(`Game forced to end due to timeout`);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
await game.update();
|
|
93
|
+
}
|
|
94
|
+
game.saveReplay();
|
|
95
|
+
game.dispose();
|
|
96
|
+
}
|
|
97
|
+
main().catch((e) => {
|
|
98
|
+
console.error(e);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
});
|
|
113
101
|
//# sourceMappingURL=exampleBot.js.map
|
package/dist/exampleBot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exampleBot.js","sourceRoot":"","sources":["../src/exampleBot.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAmE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAChH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"exampleBot.js","sourceRoot":"","sources":["../src/exampleBot.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,29 +1,32 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@supalosa/chronodivide-bot",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Example bot for Chrono Divide",
|
|
5
|
-
"repository":
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
},
|
|
24
|
-
"
|
|
25
|
-
"@
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@supalosa/chronodivide-bot",
|
|
3
|
+
"version": "0.6.4",
|
|
4
|
+
"description": "Example bot for Chrono Divide",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/Supalosa/supalosa-chronodivide-bot.git"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/exampleBot.js",
|
|
10
|
+
"type": "module",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc -p .",
|
|
13
|
+
"watch": "tsc -p . -w",
|
|
14
|
+
"start": "node . --es-module-specifier-resolution=node",
|
|
15
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
16
|
+
},
|
|
17
|
+
"license": "UNLICENSED",
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@chronodivide/game-api": "^0.73.0",
|
|
20
|
+
"@types/node": "^14.17.32",
|
|
21
|
+
"prettier": "3.0.3",
|
|
22
|
+
"typescript": "^4.3.5"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@chronodivide/game-api": "^0.73.0"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@datastructures-js/priority-queue": "^6.3.0",
|
|
29
|
+
"@timohausmann/quadtree-ts": "2.2.2",
|
|
30
|
+
"dotenv": "^16.3.1"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/bot/bot.ts
CHANGED
|
@@ -1,161 +1,161 @@
|
|
|
1
|
-
import { ApiEventType, Bot, GameApi, ApiEvent, ObjectType, FactoryType, Size } from "@chronodivide/game-api";
|
|
2
|
-
|
|
3
|
-
import { determineMapBounds } from "./logic/map/map.js";
|
|
4
|
-
import { SectorCache } from "./logic/map/sector.js";
|
|
5
|
-
import { MissionController } from "./logic/mission/missionController.js";
|
|
6
|
-
import { QueueController } from "./logic/building/queueController.js";
|
|
7
|
-
import { MatchAwareness, MatchAwarenessImpl } from "./logic/awareness.js";
|
|
8
|
-
import { formatTimeDuration } from "./logic/common/utils.js";
|
|
9
|
-
|
|
10
|
-
const DEBUG_STATE_UPDATE_INTERVAL_SECONDS = 6;
|
|
11
|
-
|
|
12
|
-
// Number of ticks per second at the base speed.
|
|
13
|
-
const NATURAL_TICK_RATE = 15;
|
|
14
|
-
|
|
15
|
-
export class SupalosaBot extends Bot {
|
|
16
|
-
private tickRatio?: number;
|
|
17
|
-
private knownMapBounds: Size | undefined;
|
|
18
|
-
private missionController: MissionController;
|
|
19
|
-
private queueController: QueueController;
|
|
20
|
-
private tickOfLastAttackOrder: number = 0;
|
|
21
|
-
|
|
22
|
-
private matchAwareness: MatchAwareness | null = null;
|
|
23
|
-
|
|
24
|
-
constructor(
|
|
25
|
-
name: string,
|
|
26
|
-
country:
|
|
27
|
-
private tryAllyWith: string[] = [],
|
|
28
|
-
private enableLogging = true,
|
|
29
|
-
) {
|
|
30
|
-
super(name, country);
|
|
31
|
-
this.missionController = new MissionController((message, sayInGame) => this.logBotStatus(message, sayInGame));
|
|
32
|
-
this.queueController = new QueueController();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
override onGameStart(game: GameApi) {
|
|
36
|
-
const gameRate = game.getTickRate();
|
|
37
|
-
const botApm = 300;
|
|
38
|
-
const botRate = botApm / 60;
|
|
39
|
-
this.tickRatio = Math.ceil(gameRate / botRate);
|
|
40
|
-
|
|
41
|
-
this.knownMapBounds = determineMapBounds(game.mapApi);
|
|
42
|
-
const myPlayer = game.getPlayerData(this.name);
|
|
43
|
-
|
|
44
|
-
this.matchAwareness = new MatchAwarenessImpl(
|
|
45
|
-
null,
|
|
46
|
-
new SectorCache(game.mapApi, this.knownMapBounds),
|
|
47
|
-
myPlayer.startLocation,
|
|
48
|
-
(message, sayInGame) => this.logBotStatus(message, sayInGame),
|
|
49
|
-
);
|
|
50
|
-
this.matchAwareness.onGameStart(game, myPlayer);
|
|
51
|
-
|
|
52
|
-
this.logBotStatus(`Map bounds: ${this.knownMapBounds.width}, ${this.knownMapBounds.height}`);
|
|
53
|
-
|
|
54
|
-
this.tryAllyWith.forEach((playerName) => this.actionsApi.toggleAlliance(playerName, true));
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
override onGameTick(game: GameApi) {
|
|
58
|
-
if (!this.matchAwareness) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const threatCache = this.matchAwareness.getThreatCache();
|
|
63
|
-
|
|
64
|
-
if ((game.getCurrentTick() / NATURAL_TICK_RATE) % DEBUG_STATE_UPDATE_INTERVAL_SECONDS === 0) {
|
|
65
|
-
this.updateDebugState(game);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (game.getCurrentTick() % this.tickRatio! === 0) {
|
|
69
|
-
const myPlayer = game.getPlayerData(this.name);
|
|
70
|
-
|
|
71
|
-
this.matchAwareness.onAiUpdate(game, myPlayer);
|
|
72
|
-
|
|
73
|
-
// hacky resign condition
|
|
74
|
-
const armyUnits = game.getVisibleUnits(this.name, "self", (r) => r.isSelectableCombatant);
|
|
75
|
-
const mcvUnits = game.getVisibleUnits(
|
|
76
|
-
this.name,
|
|
77
|
-
"self",
|
|
78
|
-
(r) => !!r.deploysInto && game.getGeneralRules().baseUnit.includes(r.name),
|
|
79
|
-
);
|
|
80
|
-
const productionBuildings = game.getVisibleUnits(
|
|
81
|
-
this.name,
|
|
82
|
-
"self",
|
|
83
|
-
(r) => r.type == ObjectType.Building && r.factory != FactoryType.None,
|
|
84
|
-
);
|
|
85
|
-
if (armyUnits.length == 0 && productionBuildings.length == 0 && mcvUnits.length == 0) {
|
|
86
|
-
this.logBotStatus(`No army or production left, quitting.`);
|
|
87
|
-
this.actionsApi.quitGame();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Mission logic every 3 ticks
|
|
91
|
-
if (this.gameApi.getCurrentTick() % 3 === 0) {
|
|
92
|
-
this.missionController.onAiUpdate(game, this.actionsApi, myPlayer, this.matchAwareness);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const unitTypeRequests = this.missionController.getRequestedUnitTypes();
|
|
96
|
-
|
|
97
|
-
// Build logic.
|
|
98
|
-
this.queueController.onAiUpdate(
|
|
99
|
-
game,
|
|
100
|
-
this.productionApi,
|
|
101
|
-
this.actionsApi,
|
|
102
|
-
myPlayer,
|
|
103
|
-
threatCache,
|
|
104
|
-
unitTypeRequests,
|
|
105
|
-
(message) => this.logBotStatus(message),
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
private getHumanTimestamp(game: GameApi) {
|
|
111
|
-
return formatTimeDuration(game.getCurrentTick() / NATURAL_TICK_RATE);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
private logBotStatus(message: string, sayInGame: boolean = false) {
|
|
115
|
-
if (!this.enableLogging) {
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
this.logger.info(message);
|
|
119
|
-
if (sayInGame) {
|
|
120
|
-
const timestamp = this.getHumanTimestamp(this.gameApi);
|
|
121
|
-
this.actionsApi.sayAll(`${timestamp}: ${message}`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private updateDebugState(game: GameApi) {
|
|
126
|
-
if (!this.getDebugMode()) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
// Update the global debug text.
|
|
130
|
-
const myPlayer = game.getPlayerData(this.name);
|
|
131
|
-
const harvesters = game.getVisibleUnits(this.name, "self", (r) => r.harvester).length;
|
|
132
|
-
|
|
133
|
-
let globalDebugText = `Cash: ${myPlayer.credits} | Harvesters: ${harvesters}\n`;
|
|
134
|
-
globalDebugText += this.queueController.getGlobalDebugText(this.gameApi, this.productionApi);
|
|
135
|
-
globalDebugText += this.missionController.getGlobalDebugText(this.gameApi);
|
|
136
|
-
globalDebugText += this.matchAwareness?.getGlobalDebugText();
|
|
137
|
-
|
|
138
|
-
this.missionController.updateDebugText(this.actionsApi);
|
|
139
|
-
|
|
140
|
-
// Tag enemy units with IDs
|
|
141
|
-
game.getVisibleUnits(this.name, "enemy").forEach((unitId) => {
|
|
142
|
-
this.actionsApi.setUnitDebugText(unitId, unitId.toString());
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
this.actionsApi.setGlobalDebugText(globalDebugText);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
override onGameEvent(ev: ApiEvent) {
|
|
149
|
-
switch (ev.type) {
|
|
150
|
-
case ApiEventType.ObjectDestroy: {
|
|
151
|
-
// Add to the stalemate detection.
|
|
152
|
-
if (ev.attackerInfo?.playerName == this.name) {
|
|
153
|
-
this.tickOfLastAttackOrder += (this.gameApi.getCurrentTick() - this.tickOfLastAttackOrder) / 2;
|
|
154
|
-
}
|
|
155
|
-
break;
|
|
156
|
-
}
|
|
157
|
-
default:
|
|
158
|
-
break;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
1
|
+
import { ApiEventType, Bot, GameApi, ApiEvent, ObjectType, FactoryType, Size } from "@chronodivide/game-api";
|
|
2
|
+
|
|
3
|
+
import { determineMapBounds } from "./logic/map/map.js";
|
|
4
|
+
import { SectorCache } from "./logic/map/sector.js";
|
|
5
|
+
import { MissionController } from "./logic/mission/missionController.js";
|
|
6
|
+
import { QueueController } from "./logic/building/queueController.js";
|
|
7
|
+
import { MatchAwareness, MatchAwarenessImpl } from "./logic/awareness.js";
|
|
8
|
+
import { Countries, formatTimeDuration } from "./logic/common/utils.js";
|
|
9
|
+
|
|
10
|
+
const DEBUG_STATE_UPDATE_INTERVAL_SECONDS = 6;
|
|
11
|
+
|
|
12
|
+
// Number of ticks per second at the base speed.
|
|
13
|
+
const NATURAL_TICK_RATE = 15;
|
|
14
|
+
|
|
15
|
+
export class SupalosaBot extends Bot {
|
|
16
|
+
private tickRatio?: number;
|
|
17
|
+
private knownMapBounds: Size | undefined;
|
|
18
|
+
private missionController: MissionController;
|
|
19
|
+
private queueController: QueueController;
|
|
20
|
+
private tickOfLastAttackOrder: number = 0;
|
|
21
|
+
|
|
22
|
+
private matchAwareness: MatchAwareness | null = null;
|
|
23
|
+
|
|
24
|
+
constructor(
|
|
25
|
+
name: string,
|
|
26
|
+
country: Countries,
|
|
27
|
+
private tryAllyWith: string[] = [],
|
|
28
|
+
private enableLogging = true,
|
|
29
|
+
) {
|
|
30
|
+
super(name, country);
|
|
31
|
+
this.missionController = new MissionController((message, sayInGame) => this.logBotStatus(message, sayInGame));
|
|
32
|
+
this.queueController = new QueueController();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override onGameStart(game: GameApi) {
|
|
36
|
+
const gameRate = game.getTickRate();
|
|
37
|
+
const botApm = 300;
|
|
38
|
+
const botRate = botApm / 60;
|
|
39
|
+
this.tickRatio = Math.ceil(gameRate / botRate);
|
|
40
|
+
|
|
41
|
+
this.knownMapBounds = determineMapBounds(game.mapApi);
|
|
42
|
+
const myPlayer = game.getPlayerData(this.name);
|
|
43
|
+
|
|
44
|
+
this.matchAwareness = new MatchAwarenessImpl(
|
|
45
|
+
null,
|
|
46
|
+
new SectorCache(game.mapApi, this.knownMapBounds),
|
|
47
|
+
myPlayer.startLocation,
|
|
48
|
+
(message, sayInGame) => this.logBotStatus(message, sayInGame),
|
|
49
|
+
);
|
|
50
|
+
this.matchAwareness.onGameStart(game, myPlayer);
|
|
51
|
+
|
|
52
|
+
this.logBotStatus(`Map bounds: ${this.knownMapBounds.width}, ${this.knownMapBounds.height}`);
|
|
53
|
+
|
|
54
|
+
this.tryAllyWith.forEach((playerName) => this.actionsApi.toggleAlliance(playerName, true));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
override onGameTick(game: GameApi) {
|
|
58
|
+
if (!this.matchAwareness) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const threatCache = this.matchAwareness.getThreatCache();
|
|
63
|
+
|
|
64
|
+
if ((game.getCurrentTick() / NATURAL_TICK_RATE) % DEBUG_STATE_UPDATE_INTERVAL_SECONDS === 0) {
|
|
65
|
+
this.updateDebugState(game);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (game.getCurrentTick() % this.tickRatio! === 0) {
|
|
69
|
+
const myPlayer = game.getPlayerData(this.name);
|
|
70
|
+
|
|
71
|
+
this.matchAwareness.onAiUpdate(game, myPlayer);
|
|
72
|
+
|
|
73
|
+
// hacky resign condition
|
|
74
|
+
const armyUnits = game.getVisibleUnits(this.name, "self", (r) => r.isSelectableCombatant);
|
|
75
|
+
const mcvUnits = game.getVisibleUnits(
|
|
76
|
+
this.name,
|
|
77
|
+
"self",
|
|
78
|
+
(r) => !!r.deploysInto && game.getGeneralRules().baseUnit.includes(r.name),
|
|
79
|
+
);
|
|
80
|
+
const productionBuildings = game.getVisibleUnits(
|
|
81
|
+
this.name,
|
|
82
|
+
"self",
|
|
83
|
+
(r) => r.type == ObjectType.Building && r.factory != FactoryType.None,
|
|
84
|
+
);
|
|
85
|
+
if (armyUnits.length == 0 && productionBuildings.length == 0 && mcvUnits.length == 0) {
|
|
86
|
+
this.logBotStatus(`No army or production left, quitting.`);
|
|
87
|
+
this.actionsApi.quitGame();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Mission logic every 3 ticks
|
|
91
|
+
if (this.gameApi.getCurrentTick() % 3 === 0) {
|
|
92
|
+
this.missionController.onAiUpdate(game, this.actionsApi, myPlayer, this.matchAwareness);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const unitTypeRequests = this.missionController.getRequestedUnitTypes();
|
|
96
|
+
|
|
97
|
+
// Build logic.
|
|
98
|
+
this.queueController.onAiUpdate(
|
|
99
|
+
game,
|
|
100
|
+
this.productionApi,
|
|
101
|
+
this.actionsApi,
|
|
102
|
+
myPlayer,
|
|
103
|
+
threatCache,
|
|
104
|
+
unitTypeRequests,
|
|
105
|
+
(message) => this.logBotStatus(message),
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private getHumanTimestamp(game: GameApi) {
|
|
111
|
+
return formatTimeDuration(game.getCurrentTick() / NATURAL_TICK_RATE);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private logBotStatus(message: string, sayInGame: boolean = false) {
|
|
115
|
+
if (!this.enableLogging) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
this.logger.info(message);
|
|
119
|
+
if (sayInGame) {
|
|
120
|
+
const timestamp = this.getHumanTimestamp(this.gameApi);
|
|
121
|
+
this.actionsApi.sayAll(`${timestamp}: ${message}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private updateDebugState(game: GameApi) {
|
|
126
|
+
if (!this.getDebugMode()) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
// Update the global debug text.
|
|
130
|
+
const myPlayer = game.getPlayerData(this.name);
|
|
131
|
+
const harvesters = game.getVisibleUnits(this.name, "self", (r) => r.harvester).length;
|
|
132
|
+
|
|
133
|
+
let globalDebugText = `Cash: ${myPlayer.credits} | Harvesters: ${harvesters}\n`;
|
|
134
|
+
globalDebugText += this.queueController.getGlobalDebugText(this.gameApi, this.productionApi);
|
|
135
|
+
globalDebugText += this.missionController.getGlobalDebugText(this.gameApi);
|
|
136
|
+
globalDebugText += this.matchAwareness?.getGlobalDebugText();
|
|
137
|
+
|
|
138
|
+
this.missionController.updateDebugText(this.actionsApi);
|
|
139
|
+
|
|
140
|
+
// Tag enemy units with IDs
|
|
141
|
+
game.getVisibleUnits(this.name, "enemy").forEach((unitId) => {
|
|
142
|
+
this.actionsApi.setUnitDebugText(unitId, unitId.toString());
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
this.actionsApi.setGlobalDebugText(globalDebugText);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
override onGameEvent(ev: ApiEvent) {
|
|
149
|
+
switch (ev.type) {
|
|
150
|
+
case ApiEventType.ObjectDestroy: {
|
|
151
|
+
// Add to the stalemate detection.
|
|
152
|
+
if (ev.attackerInfo?.playerName == this.name) {
|
|
153
|
+
this.tickOfLastAttackOrder += (this.gameApi.getCurrentTick() - this.tickOfLastAttackOrder) / 2;
|
|
154
|
+
}
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
default:
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|