@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.
- package/.env.template +5 -0
- package/README.md +54 -47
- package/dist/bot/bot.js +14 -30
- package/dist/bot/bot.js.map +1 -1
- package/dist/bot/logic/awareness.js +13 -8
- package/dist/bot/logic/awareness.js.map +1 -1
- package/dist/bot/logic/awarenessImpl.js +132 -0
- package/dist/bot/logic/awarenessImpl.js.map +1 -0
- package/dist/bot/logic/building/ArtilleryUnit.js +2 -29
- package/dist/bot/logic/building/ArtilleryUnit.js.map +1 -0
- package/dist/bot/logic/building/antiAirStaticDefence.js +43 -0
- package/dist/bot/logic/building/antiAirStaticDefence.js.map +1 -0
- package/dist/bot/logic/building/antiGroundStaticDefence.js +7 -4
- package/dist/bot/logic/building/antiGroundStaticDefence.js.map +1 -1
- package/dist/bot/logic/building/basicAirUnit.js +2 -23
- package/dist/bot/logic/building/basicAirUnit.js.map +1 -1
- package/dist/bot/logic/building/basicBuilding.js +3 -2
- package/dist/bot/logic/building/basicBuilding.js.map +1 -1
- package/dist/bot/logic/building/basicGroundUnit.js +2 -43
- package/dist/bot/logic/building/basicGroundUnit.js.map +1 -1
- package/dist/bot/logic/building/building.js +55 -11
- package/dist/bot/logic/building/building.js.map +1 -0
- package/dist/bot/logic/building/buildingRules.js +10 -5
- package/dist/bot/logic/building/buildingRules.js.map +1 -1
- package/dist/bot/logic/building/common.js +19 -0
- package/dist/bot/logic/building/common.js.map +1 -0
- package/dist/bot/logic/building/harvester.js +2 -1
- package/dist/bot/logic/building/harvester.js.map +1 -1
- package/dist/bot/logic/building/queueController.js +69 -42
- package/dist/bot/logic/building/queueController.js.map +1 -1
- package/dist/bot/logic/common/utils.js +21 -0
- package/dist/bot/logic/common/utils.js.map +1 -1
- package/dist/bot/logic/composition/alliedCompositions.js +13 -0
- package/dist/bot/logic/composition/alliedCompositions.js.map +1 -0
- package/dist/bot/logic/composition/common.js +2 -0
- package/dist/bot/logic/composition/common.js.map +1 -0
- package/dist/bot/logic/composition/sovietCompositions.js +13 -0
- package/dist/bot/logic/composition/sovietCompositions.js.map +1 -0
- package/dist/bot/logic/mission/actionBatcher.js +92 -0
- package/dist/bot/logic/mission/actionBatcher.js.map +1 -0
- package/dist/bot/logic/mission/behaviours/combatSquad.js +124 -0
- package/dist/bot/logic/mission/behaviours/combatSquad.js.map +1 -0
- package/dist/bot/logic/mission/behaviours/common.js +58 -0
- package/dist/bot/logic/mission/behaviours/common.js.map +1 -0
- package/dist/bot/logic/mission/behaviours/engineerSquad.js +39 -0
- package/dist/bot/logic/mission/behaviours/engineerSquad.js.map +1 -0
- package/dist/bot/logic/mission/behaviours/expansionSquad.js +46 -0
- package/dist/bot/logic/mission/behaviours/expansionSquad.js.map +1 -0
- package/dist/bot/logic/mission/behaviours/retreatSquad.js +31 -0
- package/dist/bot/logic/mission/behaviours/retreatSquad.js.map +1 -0
- package/{src/bot/logic/squad/behaviours/scoutingSquad.ts → dist/bot/logic/mission/behaviours/scoutingSquad.js} +27 -51
- package/dist/bot/logic/mission/behaviours/scoutingSquad.js.map +1 -0
- package/dist/bot/logic/mission/mission.js +91 -19
- package/dist/bot/logic/mission/mission.js.map +1 -1
- package/dist/bot/logic/mission/missionController.js +262 -21
- package/dist/bot/logic/mission/missionController.js.map +1 -1
- package/dist/bot/logic/mission/missions/attackMission.js +113 -39
- package/dist/bot/logic/mission/missions/attackMission.js.map +1 -1
- package/dist/bot/logic/mission/missions/basicMission.js +13 -0
- package/dist/bot/logic/mission/missions/basicMission.js.map +1 -0
- package/dist/bot/logic/mission/missions/defenceMission.js +43 -28
- package/dist/bot/logic/mission/missions/defenceMission.js.map +1 -1
- package/dist/bot/logic/mission/missions/engineerMission.js +37 -7
- package/dist/bot/logic/mission/missions/engineerMission.js.map +1 -1
- package/dist/bot/logic/mission/missions/expansionMission.js +42 -6
- package/dist/bot/logic/mission/missions/expansionMission.js.map +1 -1
- package/dist/bot/logic/mission/missions/missionBehaviour.js +2 -0
- package/dist/bot/logic/mission/missions/missionBehaviour.js.map +1 -0
- package/dist/bot/logic/mission/missions/retreatMission.js +31 -5
- package/dist/bot/logic/mission/missions/retreatMission.js.map +1 -1
- package/dist/bot/logic/mission/missions/scoutingMission.js +103 -6
- package/dist/bot/logic/mission/missions/scoutingMission.js.map +1 -1
- package/dist/bot/logic/mission/missions/squads/combatSquad.js +116 -0
- package/dist/bot/logic/mission/missions/squads/combatSquad.js.map +1 -0
- package/dist/bot/logic/mission/missions/squads/common.js +58 -0
- package/dist/bot/logic/mission/missions/squads/common.js.map +1 -0
- package/dist/bot/logic/mission/missions/squads/squad.js +2 -0
- package/dist/bot/logic/mission/missions/squads/squad.js.map +1 -0
- package/dist/bot/logic/squad/behaviours/attackSquad.js +63 -56
- package/dist/bot/logic/squad/behaviours/combatSquad.js +21 -25
- package/dist/bot/logic/squad/behaviours/combatSquad.js.map +1 -1
- package/dist/bot/logic/squad/behaviours/common.js +11 -26
- package/dist/bot/logic/squad/behaviours/common.js.map +1 -1
- package/dist/bot/logic/squad/behaviours/defenceSquad.js +15 -2
- package/dist/bot/logic/squad/behaviours/engineerSquad.js +2 -4
- package/dist/bot/logic/squad/behaviours/engineerSquad.js.map +1 -1
- package/dist/bot/logic/squad/behaviours/expansionSquad.js +2 -4
- package/dist/bot/logic/squad/behaviours/expansionSquad.js.map +1 -1
- package/dist/bot/logic/squad/behaviours/retreatSquad.js +1 -4
- package/dist/bot/logic/squad/behaviours/retreatSquad.js.map +1 -1
- package/dist/bot/logic/squad/behaviours/scoutingSquad.js +18 -25
- package/dist/bot/logic/squad/behaviours/scoutingSquad.js.map +1 -1
- package/dist/bot/logic/squad/squad.js +10 -10
- package/dist/bot/logic/squad/squad.js.map +1 -1
- package/dist/bot/logic/squad/squadBehaviour.js.map +1 -1
- package/dist/bot/logic/squad/squadController.js +5 -17
- package/dist/bot/logic/squad/squadController.js.map +1 -1
- package/dist/bot/logic/threat/threatCalculator.js +5 -5
- package/dist/bot/logic/threat/threatCalculator.js.map +1 -1
- package/dist/exampleBot.js +45 -18
- package/dist/exampleBot.js.map +1 -1
- package/package.json +5 -4
- package/src/bot/bot.ts +19 -45
- package/src/bot/logic/awareness.ts +34 -22
- package/src/bot/logic/building/antiAirStaticDefence.ts +64 -0
- package/src/bot/logic/building/antiGroundStaticDefence.ts +7 -20
- package/src/bot/logic/building/artilleryUnit.ts +2 -28
- package/src/bot/logic/building/basicAirUnit.ts +2 -33
- package/src/bot/logic/building/basicBuilding.ts +8 -6
- package/src/bot/logic/building/basicGroundUnit.ts +2 -46
- package/src/bot/logic/building/buildingRules.ts +15 -9
- package/src/bot/logic/building/common.ts +23 -0
- package/src/bot/logic/building/harvester.ts +2 -1
- package/src/bot/logic/building/queueController.ts +98 -43
- package/src/bot/logic/common/utils.ts +28 -0
- package/src/bot/logic/composition/alliedCompositions.ts +22 -0
- package/src/bot/logic/composition/common.ts +3 -0
- package/src/bot/logic/composition/sovietCompositions.ts +21 -0
- package/src/bot/logic/{squad/behaviours → mission}/actionBatcher.ts +66 -7
- package/src/bot/logic/mission/mission.ts +186 -37
- package/src/bot/logic/mission/missionController.ts +340 -31
- package/src/bot/logic/mission/missionFactories.ts +3 -3
- package/src/bot/logic/mission/missions/attackMission.ts +181 -44
- package/src/bot/logic/mission/missions/defenceMission.ts +72 -45
- package/src/bot/logic/mission/missions/engineerMission.ts +67 -15
- package/src/bot/logic/mission/missions/expansionMission.ts +67 -14
- package/src/bot/logic/mission/missions/retreatMission.ts +50 -6
- package/src/bot/logic/mission/missions/scoutingMission.ts +138 -14
- package/src/bot/logic/{squad/behaviours → mission/missions/squads}/combatSquad.ts +56 -33
- package/src/bot/logic/{squad/behaviours → mission/missions/squads}/common.ts +11 -17
- package/src/bot/logic/mission/missions/squads/squad.ts +19 -0
- package/src/bot/logic/threat/threat.ts +15 -15
- package/src/bot/logic/threat/threatCalculator.ts +10 -10
- package/src/exampleBot.ts +50 -24
- package/.prettierrc +0 -5
- package/TODO.md +0 -15
- package/dist/bot/logic/building/artilleryUnit.js.map +0 -1
- 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/expansionMission.js +0 -32
- 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/squadExpansion.js +0 -31
- package/dist/bot/logic/squad/behaviours/squadScouters.js +0 -8
- package/rules.ini +0 -23126
- package/src/bot/logic/mission/missions/oneTimeMission.ts +0 -33
- package/src/bot/logic/squad/behaviours/engineerSquad.ts +0 -58
- package/src/bot/logic/squad/behaviours/expansionSquad.ts +0 -64
- package/src/bot/logic/squad/behaviours/retreatSquad.ts +0 -50
- package/src/bot/logic/squad/squad.ts +0 -165
- package/src/bot/logic/squad/squadBehaviour.ts +0 -66
- package/src/bot/logic/squad/squadBehaviours.ts +0 -8
- package/src/bot/logic/squad/squadController.ts +0 -271
package/dist/exampleBot.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
1
2
|
import { cdapi } from "@chronodivide/game-api";
|
|
2
3
|
import { SupalosaBot } from "./bot/bot.js";
|
|
3
4
|
async function main() {
|
|
@@ -14,6 +15,19 @@ async function main() {
|
|
|
14
15
|
|
|
15
16
|
Other maps:
|
|
16
17
|
mp03t4 large map, no oil derricks
|
|
18
|
+
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,
|
|
19
|
+
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,
|
|
20
|
+
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,
|
|
21
|
+
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,
|
|
22
|
+
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,
|
|
23
|
+
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,
|
|
24
|
+
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,
|
|
25
|
+
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,
|
|
26
|
+
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,
|
|
27
|
+
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,
|
|
28
|
+
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,
|
|
29
|
+
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,
|
|
30
|
+
offensedefense.map,ore2_startfixed.map,rekoool_fast_6players.mpr,rekoool_fast_8players.mpr,riverram.map,tourofegypt.map,unrepent.map,sinkswim_yr_port.map
|
|
17
31
|
*/
|
|
18
32
|
const mapName = "mp03t4.map";
|
|
19
33
|
// Bot names must be unique in online mode
|
|
@@ -38,35 +52,48 @@ async function main() {
|
|
|
38
52
|
7=Confederation -> Cuba
|
|
39
53
|
8=Russians
|
|
40
54
|
*/
|
|
55
|
+
const baseSettings = {
|
|
56
|
+
buildOffAlly: false,
|
|
57
|
+
cratesAppear: false,
|
|
58
|
+
credits: 10000,
|
|
59
|
+
gameMode: cdapi.getAvailableGameModes(mapName)[0],
|
|
60
|
+
gameSpeed: 6,
|
|
61
|
+
mapName,
|
|
62
|
+
mcvRepacks: true,
|
|
63
|
+
shortGame: true,
|
|
64
|
+
superWeapons: false,
|
|
65
|
+
unitCount: 0,
|
|
66
|
+
};
|
|
41
67
|
const onlineSettings = {
|
|
68
|
+
...baseSettings,
|
|
42
69
|
online: true,
|
|
43
70
|
serverUrl: process.env.SERVER_URL,
|
|
44
71
|
clientUrl: process.env.CLIENT_URL,
|
|
45
|
-
agents: [
|
|
72
|
+
agents: [
|
|
73
|
+
new SupalosaBot(process.env.ONLINE_BOT_NAME ?? firstBotName, "Americans"),
|
|
74
|
+
{ name: process.env.PLAYER_NAME ?? secondBotName, country: "French" },
|
|
75
|
+
],
|
|
76
|
+
botPassword: process.env.ONLINE_BOT_PASSWORD ?? "default",
|
|
46
77
|
};
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
78
|
+
const offlineSettings1v1 = {
|
|
79
|
+
...baseSettings,
|
|
80
|
+
online: false,
|
|
81
|
+
agents: [
|
|
82
|
+
new SupalosaBot(firstBotName, "French", [], true).setDebugMode(true),
|
|
83
|
+
new SupalosaBot(secondBotName, "Russians", [], false),
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
const offlineSettings2v2 = {
|
|
87
|
+
...baseSettings,
|
|
88
|
+
online: false,
|
|
50
89
|
agents: [
|
|
51
90
|
new SupalosaBot(firstBotName, "French", [firstBotName], false),
|
|
52
|
-
|
|
91
|
+
new SupalosaBot(secondBotName, "Russians", [firstBotName], true).setDebugMode(true),
|
|
53
92
|
new SupalosaBot(thirdBotName, "Russians", [fourthBotName], false),
|
|
54
93
|
new SupalosaBot(fourthBotName, "French", [thirdBotName], false),
|
|
55
94
|
],
|
|
56
95
|
};
|
|
57
|
-
const game = await cdapi.createGame(
|
|
58
|
-
...offlineSettings,
|
|
59
|
-
buildOffAlly: false,
|
|
60
|
-
cratesAppear: false,
|
|
61
|
-
credits: 10000,
|
|
62
|
-
gameMode: cdapi.getAvailableGameModes(mapName)[0],
|
|
63
|
-
gameSpeed: 6,
|
|
64
|
-
mapName,
|
|
65
|
-
mcvRepacks: true,
|
|
66
|
-
shortGame: true,
|
|
67
|
-
superWeapons: false,
|
|
68
|
-
unitCount: 0,
|
|
69
|
-
});
|
|
96
|
+
const game = await cdapi.createGame(process.env.ONLINE_MATCH ? onlineSettings : offlineSettings1v1);
|
|
70
97
|
while (!game.isFinished()) {
|
|
71
98
|
await game.update();
|
|
72
99
|
}
|
package/dist/exampleBot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exampleBot.js","sourceRoot":"","sources":["../src/exampleBot.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"exampleBot.js","sourceRoot":"","sources":["../src/exampleBot.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supalosa/chronodivide-bot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Example bot for Chrono Divide",
|
|
5
5
|
"repository": "https://github.com/Supalosa/supalosa-chronodivide-bot",
|
|
6
6
|
"main": "dist/exampleBot.js",
|
|
@@ -13,16 +13,17 @@
|
|
|
13
13
|
},
|
|
14
14
|
"license": "UNLICENSED",
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@chronodivide/game-api": "^0.
|
|
16
|
+
"@chronodivide/game-api": "^0.50.1",
|
|
17
17
|
"@types/node": "^14.17.32",
|
|
18
18
|
"prettier": "3.0.3",
|
|
19
19
|
"typescript": "^4.3.5"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
|
-
"@chronodivide/game-api": "^0.
|
|
22
|
+
"@chronodivide/game-api": "^0.50.1"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@datastructures-js/priority-queue": "^6.3.0",
|
|
26
|
-
"@timohausmann/quadtree-ts": "2.2.2"
|
|
26
|
+
"@timohausmann/quadtree-ts": "2.2.2",
|
|
27
|
+
"dotenv": "^16.3.1"
|
|
27
28
|
}
|
|
28
29
|
}
|
package/src/bot/bot.ts
CHANGED
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ApiEventType,
|
|
3
|
-
Bot,
|
|
4
|
-
GameApi,
|
|
5
|
-
ApiEvent,
|
|
6
|
-
QueueStatus,
|
|
7
|
-
ObjectType,
|
|
8
|
-
FactoryType,
|
|
9
|
-
Size,
|
|
10
|
-
} from "@chronodivide/game-api";
|
|
1
|
+
import { ApiEventType, Bot, GameApi, ApiEvent, ObjectType, FactoryType, Size } from "@chronodivide/game-api";
|
|
11
2
|
|
|
12
3
|
import { determineMapBounds } from "./logic/map/map.js";
|
|
13
4
|
import { SectorCache } from "./logic/map/sector.js";
|
|
14
5
|
import { MissionController } from "./logic/mission/missionController.js";
|
|
15
|
-
import {
|
|
16
|
-
import { QUEUES, QueueController, queueTypeToName } from "./logic/building/queueController.js";
|
|
6
|
+
import { QueueController } from "./logic/building/queueController.js";
|
|
17
7
|
import { MatchAwareness, MatchAwarenessImpl } from "./logic/awareness.js";
|
|
18
8
|
import { formatTimeDuration } from "./logic/common/utils.js";
|
|
19
9
|
|
|
@@ -27,7 +17,6 @@ export class SupalosaBot extends Bot {
|
|
|
27
17
|
private tickRatio?: number;
|
|
28
18
|
private knownMapBounds: Size | undefined;
|
|
29
19
|
private missionController: MissionController;
|
|
30
|
-
private squadController: SquadController;
|
|
31
20
|
private queueController: QueueController;
|
|
32
21
|
private tickOfLastAttackOrder: number = 0;
|
|
33
22
|
|
|
@@ -41,7 +30,6 @@ export class SupalosaBot extends Bot {
|
|
|
41
30
|
) {
|
|
42
31
|
super(name, country);
|
|
43
32
|
this.missionController = new MissionController((message, sayInGame) => this.logBotStatus(message, sayInGame));
|
|
44
|
-
this.squadController = new SquadController((message, sayInGame) => this.logBotStatus(message, sayInGame));
|
|
45
33
|
this.queueController = new QueueController();
|
|
46
34
|
}
|
|
47
35
|
|
|
@@ -105,6 +93,13 @@ export class SupalosaBot extends Bot {
|
|
|
105
93
|
this.actionsApi.quitGame();
|
|
106
94
|
}
|
|
107
95
|
|
|
96
|
+
// Mission logic every 3 ticks
|
|
97
|
+
if (this.gameApi.getCurrentTick() % 3 === 0) {
|
|
98
|
+
this.missionController.onAiUpdate(game, this.actionsApi, myPlayer, this.matchAwareness);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const unitTypeRequests = this.missionController.getRequestedUnitTypes();
|
|
102
|
+
|
|
108
103
|
// Build logic.
|
|
109
104
|
this.queueController.onAiUpdate(
|
|
110
105
|
game,
|
|
@@ -112,18 +107,9 @@ export class SupalosaBot extends Bot {
|
|
|
112
107
|
this.actionsApi,
|
|
113
108
|
myPlayer,
|
|
114
109
|
threatCache,
|
|
110
|
+
unitTypeRequests,
|
|
115
111
|
(message) => this.logBotStatus(message),
|
|
116
112
|
);
|
|
117
|
-
|
|
118
|
-
// Mission logic every 6 ticks
|
|
119
|
-
if (this.gameApi.getCurrentTick() % 6 === 0) {
|
|
120
|
-
this.missionController.onAiUpdate(game, myPlayer, this.matchAwareness, this.squadController);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Squad logic every 3 ticks
|
|
124
|
-
if (this.gameApi.getCurrentTick() % 3 === 0) {
|
|
125
|
-
this.squadController.onAiUpdate(game, this.actionsApi, myPlayer, this.matchAwareness);
|
|
126
|
-
}
|
|
127
113
|
}
|
|
128
114
|
}
|
|
129
115
|
|
|
@@ -146,31 +132,19 @@ export class SupalosaBot extends Bot {
|
|
|
146
132
|
if (!this.getDebugMode()) {
|
|
147
133
|
return;
|
|
148
134
|
}
|
|
149
|
-
|
|
135
|
+
// Update the global debug text.
|
|
150
136
|
const myPlayer = game.getPlayerData(this.name);
|
|
151
|
-
const queueState = QUEUES.reduce((prev, queueType) => {
|
|
152
|
-
if (this.productionApi.getQueueData(queueType).size === 0) {
|
|
153
|
-
return prev;
|
|
154
|
-
}
|
|
155
|
-
const paused = this.productionApi.getQueueData(queueType).status === QueueStatus.OnHold;
|
|
156
|
-
return (
|
|
157
|
-
prev +
|
|
158
|
-
" [" +
|
|
159
|
-
queueTypeToName(queueType) +
|
|
160
|
-
(paused ? " PAUSED" : "") +
|
|
161
|
-
": " +
|
|
162
|
-
this.productionApi.getQueueData(queueType).items.map((item) => item.rules.name + "x" + item.quantity) +
|
|
163
|
-
"]"
|
|
164
|
-
);
|
|
165
|
-
}, "");
|
|
166
|
-
let globalDebugText = `Cash: ${myPlayer.credits} | Queues: ${queueState}\n`;
|
|
167
137
|
const harvesters = game.getVisibleUnits(this.name, "self", (r) => r.harvester).length;
|
|
168
|
-
|
|
169
|
-
globalDebugText
|
|
170
|
-
this.
|
|
138
|
+
|
|
139
|
+
let globalDebugText = `Cash: ${myPlayer.credits} | Harvesters: ${harvesters}\n`;
|
|
140
|
+
globalDebugText += this.queueController.getGlobalDebugText(this.gameApi, this.productionApi);
|
|
141
|
+
globalDebugText += this.missionController.getGlobalDebugText(this.gameApi);
|
|
142
|
+
globalDebugText += this.matchAwareness?.getGlobalDebugText();
|
|
143
|
+
|
|
144
|
+
this.missionController.updateDebugText(this.actionsApi);
|
|
171
145
|
|
|
172
146
|
// Tag enemy units with IDs
|
|
173
|
-
game.getVisibleUnits(this.name, "
|
|
147
|
+
game.getVisibleUnits(this.name, "enemy").forEach((unitId) => {
|
|
174
148
|
this.actionsApi.setUnitDebugText(unitId, unitId.toString());
|
|
175
149
|
});
|
|
176
150
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GameApi, ObjectType, PlayerData, UnitData, Vector2 } from "@chronodivide/game-api";
|
|
1
|
+
import { GameApi, GameObjectData, ObjectType, PlayerData, UnitData, Vector2 } from "@chronodivide/game-api";
|
|
2
2
|
import { SectorCache } from "./map/sector";
|
|
3
3
|
import { GlobalThreat } from "./threat/threat";
|
|
4
4
|
import { calculateGlobalThreat } from "./threat/threatCalculator.js";
|
|
@@ -23,10 +23,15 @@ export interface MatchAwareness {
|
|
|
23
23
|
getSectorCache(): SectorCache;
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Returns the enemy unit IDs in a certain radius of a point
|
|
26
|
+
* Returns the enemy unit IDs in a certain radius of a point.
|
|
27
|
+
* Warning: this may return non-combatant hostiles, such as neutral units.
|
|
27
28
|
*/
|
|
28
29
|
getHostilesNearPoint2d(point: Vector2, radius: number): UnitPositionQuery[];
|
|
29
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Returns the enemy unit IDs in a certain radius of a point.
|
|
33
|
+
* Warning: this may return non-combatant hostiles, such as neutral units.
|
|
34
|
+
*/
|
|
30
35
|
getHostilesNearPoint(x: number, y: number, radius: number): UnitPositionQuery[];
|
|
31
36
|
|
|
32
37
|
/**
|
|
@@ -49,6 +54,8 @@ export interface MatchAwareness {
|
|
|
49
54
|
shouldAttack(): boolean;
|
|
50
55
|
|
|
51
56
|
getScoutingManager(): ScoutingManager;
|
|
57
|
+
|
|
58
|
+
getGlobalDebugText(): string | undefined;
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
const SECTORS_TO_UPDATE_PER_CYCLE = 8;
|
|
@@ -59,7 +66,7 @@ const THREAT_UPDATE_INTERVAL_TICKS = 30;
|
|
|
59
66
|
|
|
60
67
|
type QTUnit = Circle<number>;
|
|
61
68
|
|
|
62
|
-
const rebuildQuadtree = (quadtree: Quadtree<QTUnit>, units:
|
|
69
|
+
const rebuildQuadtree = (quadtree: Quadtree<QTUnit>, units: GameObjectData[]) => {
|
|
63
70
|
quadtree.clear();
|
|
64
71
|
units.forEach((unit) => {
|
|
65
72
|
quadtree.insert(new Circle<number>({ x: unit.tile.rx, y: unit.tile.ry, r: 1, data: unit.id }));
|
|
@@ -91,7 +98,7 @@ export class MatchAwarenessImpl implements MatchAwareness {
|
|
|
91
98
|
const intersections = this.hostileQuadTree.retrieve(new Circle({ x: searchX, y: searchY, r: radius }));
|
|
92
99
|
return intersections
|
|
93
100
|
.map(({ x, y, data: unitId }) => ({ x, y, unitId: unitId! }))
|
|
94
|
-
.filter(({ x, y }) =>
|
|
101
|
+
.filter(({ x, y }) => new Vector2(x, y).distanceTo(new Vector2(searchX, searchY)) <= radius)
|
|
95
102
|
.filter(({ unitId }) => !!unitId);
|
|
96
103
|
}
|
|
97
104
|
|
|
@@ -160,11 +167,14 @@ export class MatchAwarenessImpl implements MatchAwareness {
|
|
|
160
167
|
.map((other) => other.name);
|
|
161
168
|
|
|
162
169
|
// Build the quadtree, if this is too slow we should consider doing this periodically.
|
|
163
|
-
const hostileUnitIds = game.getVisibleUnits(playerData.name, "
|
|
170
|
+
const hostileUnitIds = game.getVisibleUnits(playerData.name, "enemy");
|
|
164
171
|
try {
|
|
165
172
|
const hostileUnits = hostileUnitIds
|
|
166
|
-
.map((id) => game.
|
|
167
|
-
.filter(
|
|
173
|
+
.map((id) => game.getGameObjectData(id))
|
|
174
|
+
.filter(
|
|
175
|
+
(gameObjectData: GameObjectData | undefined): gameObjectData is GameObjectData =>
|
|
176
|
+
gameObjectData !== undefined,
|
|
177
|
+
);
|
|
168
178
|
|
|
169
179
|
rebuildQuadtree(this.hostileQuadTree, hostileUnits);
|
|
170
180
|
} catch (err) {
|
|
@@ -178,21 +188,6 @@ export class MatchAwarenessImpl implements MatchAwareness {
|
|
|
178
188
|
this.logger(`${Math.round(visibility * 1000.0) / 10}% of tiles visible. Calculating threat.`);
|
|
179
189
|
// Update the global threat cache
|
|
180
190
|
this.threatCache = calculateGlobalThreat(game, playerData, visibility);
|
|
181
|
-
this.logger(
|
|
182
|
-
`Threat LAND: Them ${Math.round(this.threatCache.totalOffensiveLandThreat)}, us: ${Math.round(
|
|
183
|
-
this.threatCache.totalAvailableAntiGroundFirepower,
|
|
184
|
-
)}.`,
|
|
185
|
-
);
|
|
186
|
-
this.logger(
|
|
187
|
-
`Threat DEFENSIVE: Them ${Math.round(this.threatCache.totalDefensiveThreat)}, us: ${Math.round(
|
|
188
|
-
this.threatCache.totalDefensivePower,
|
|
189
|
-
)}.`,
|
|
190
|
-
);
|
|
191
|
-
this.logger(
|
|
192
|
-
`Threat AIR: Them ${Math.round(this.threatCache.totalOffensiveAirThreat)}, us: ${Math.round(
|
|
193
|
-
this.threatCache.totalAvailableAntiAirFirepower,
|
|
194
|
-
)}.`,
|
|
195
|
-
);
|
|
196
191
|
|
|
197
192
|
// As the game approaches 2 hours, be more willing to attack. (15 ticks per second)
|
|
198
193
|
const gameLengthFactor = Math.max(0, 1.0 - game.getCurrentTick() / (15 * 7200.0));
|
|
@@ -230,4 +225,21 @@ export class MatchAwarenessImpl implements MatchAwareness {
|
|
|
230
225
|
);
|
|
231
226
|
}
|
|
232
227
|
}
|
|
228
|
+
|
|
229
|
+
public getGlobalDebugText(): string | undefined {
|
|
230
|
+
if (!this.threatCache) {
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
return (
|
|
234
|
+
`Threat LAND: Them ${Math.round(this.threatCache.totalOffensiveLandThreat)}, us: ${Math.round(
|
|
235
|
+
this.threatCache.totalAvailableAntiGroundFirepower,
|
|
236
|
+
)}.\n` +
|
|
237
|
+
`Threat DEFENSIVE: Them ${Math.round(this.threatCache.totalDefensiveThreat)}, us: ${Math.round(
|
|
238
|
+
this.threatCache.totalDefensivePower,
|
|
239
|
+
)}.\n` +
|
|
240
|
+
`Threat AIR: Them ${Math.round(this.threatCache.totalOffensiveAirThreat)}, us: ${Math.round(
|
|
241
|
+
this.threatCache.totalAvailableAntiAirFirepower,
|
|
242
|
+
)}.`
|
|
243
|
+
);
|
|
244
|
+
}
|
|
233
245
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { GameApi, PlayerData, TechnoRules, Vector2 } from "@chronodivide/game-api";
|
|
2
|
+
import { getPointTowardsOtherPoint } from "../map/map.js";
|
|
3
|
+
import { GlobalThreat } from "../threat/threat.js";
|
|
4
|
+
import { AiBuildingRules, getDefaultPlacementLocation, numBuildingsOwnedOfType } from "./buildingRules.js";
|
|
5
|
+
|
|
6
|
+
export class AntiAirStaticDefence implements AiBuildingRules {
|
|
7
|
+
constructor(
|
|
8
|
+
private basePriority: number,
|
|
9
|
+
private baseAmount: number,
|
|
10
|
+
private airStrength: number,
|
|
11
|
+
) {}
|
|
12
|
+
|
|
13
|
+
getPlacementLocation(
|
|
14
|
+
game: GameApi,
|
|
15
|
+
playerData: PlayerData,
|
|
16
|
+
technoRules: TechnoRules,
|
|
17
|
+
): { rx: number; ry: number } | undefined {
|
|
18
|
+
// Prefer front towards enemy.
|
|
19
|
+
let startLocation = playerData.startLocation;
|
|
20
|
+
let players = game.getPlayers();
|
|
21
|
+
let enemyFacingLocationCandidates: Vector2[] = [];
|
|
22
|
+
for (let i = 0; i < players.length; ++i) {
|
|
23
|
+
let playerName = players[i];
|
|
24
|
+
if (playerName == playerData.name) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
let enemyPlayer = game.getPlayerData(playerName);
|
|
28
|
+
enemyFacingLocationCandidates.push(
|
|
29
|
+
getPointTowardsOtherPoint(game, startLocation, enemyPlayer.startLocation, 4, 16, 1.5),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
let selectedLocation =
|
|
33
|
+
enemyFacingLocationCandidates[Math.floor(game.generateRandom() * enemyFacingLocationCandidates.length)];
|
|
34
|
+
return getDefaultPlacementLocation(game, playerData, selectedLocation, technoRules, false, 0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getPriority(
|
|
38
|
+
game: GameApi,
|
|
39
|
+
playerData: PlayerData,
|
|
40
|
+
technoRules: TechnoRules,
|
|
41
|
+
threatCache: GlobalThreat | null,
|
|
42
|
+
): number {
|
|
43
|
+
if (threatCache) {
|
|
44
|
+
let denominator = threatCache.totalAvailableAntiAirFirepower + this.airStrength;
|
|
45
|
+
if (threatCache.totalOffensiveAirThreat > denominator * 1.1) {
|
|
46
|
+
return this.basePriority * (threatCache.totalOffensiveAirThreat / Math.max(1, denominator));
|
|
47
|
+
} else {
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const strengthPerCost = (this.airStrength / technoRules.cost) * 1000;
|
|
52
|
+
const numOwned = numBuildingsOwnedOfType(game, playerData, technoRules);
|
|
53
|
+
return this.basePriority * (1.0 - numOwned / this.baseAmount) * strengthPerCost;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getMaxCount(
|
|
57
|
+
game: GameApi,
|
|
58
|
+
playerData: PlayerData,
|
|
59
|
+
technoRules: TechnoRules,
|
|
60
|
+
threatCache: GlobalThreat | null,
|
|
61
|
+
): number | null {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -2,12 +2,13 @@ import { GameApi, PlayerData, TechnoRules, Vector2 } from "@chronodivide/game-ap
|
|
|
2
2
|
import { getPointTowardsOtherPoint } from "../map/map.js";
|
|
3
3
|
import { GlobalThreat } from "../threat/threat.js";
|
|
4
4
|
import { AiBuildingRules, getDefaultPlacementLocation, numBuildingsOwnedOfType } from "./buildingRules.js";
|
|
5
|
+
import { getStaticDefencePlacement } from "./common.js";
|
|
5
6
|
|
|
6
7
|
export class AntiGroundStaticDefence implements AiBuildingRules {
|
|
7
8
|
constructor(
|
|
8
9
|
private basePriority: number,
|
|
9
10
|
private baseAmount: number,
|
|
10
|
-
private
|
|
11
|
+
private groundStrength: number,
|
|
11
12
|
) {}
|
|
12
13
|
|
|
13
14
|
getPlacementLocation(
|
|
@@ -15,23 +16,7 @@ export class AntiGroundStaticDefence implements AiBuildingRules {
|
|
|
15
16
|
playerData: PlayerData,
|
|
16
17
|
technoRules: TechnoRules,
|
|
17
18
|
): { rx: number; ry: number } | undefined {
|
|
18
|
-
|
|
19
|
-
let startLocation = playerData.startLocation;
|
|
20
|
-
let players = game.getPlayers();
|
|
21
|
-
let enemyFacingLocationCandidates: Vector2[] = [];
|
|
22
|
-
for (let i = 0; i < players.length; ++i) {
|
|
23
|
-
let playerName = players[i];
|
|
24
|
-
if (playerName == playerData.name) {
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
let enemyPlayer = game.getPlayerData(playerName);
|
|
28
|
-
enemyFacingLocationCandidates.push(
|
|
29
|
-
getPointTowardsOtherPoint(game, startLocation, enemyPlayer.startLocation, 4, 16, 1.5),
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
let selectedLocation =
|
|
33
|
-
enemyFacingLocationCandidates[Math.floor(game.generateRandom() * enemyFacingLocationCandidates.length)];
|
|
34
|
-
return getDefaultPlacementLocation(game, playerData, selectedLocation, technoRules, false, 0);
|
|
19
|
+
return getStaticDefencePlacement(game, playerData, technoRules);
|
|
35
20
|
}
|
|
36
21
|
|
|
37
22
|
getPriority(
|
|
@@ -43,12 +28,14 @@ export class AntiGroundStaticDefence implements AiBuildingRules {
|
|
|
43
28
|
// If the enemy's ground power is increasing we should try to keep up.
|
|
44
29
|
if (threatCache) {
|
|
45
30
|
let denominator =
|
|
46
|
-
threatCache.totalAvailableAntiGroundFirepower + threatCache.totalDefensivePower + this.
|
|
31
|
+
threatCache.totalAvailableAntiGroundFirepower + threatCache.totalDefensivePower + this.groundStrength;
|
|
47
32
|
if (threatCache.totalOffensiveLandThreat > denominator * 1.1) {
|
|
48
33
|
return this.basePriority * (threatCache.totalOffensiveLandThreat / Math.max(1, denominator));
|
|
34
|
+
} else {
|
|
35
|
+
return 0;
|
|
49
36
|
}
|
|
50
37
|
}
|
|
51
|
-
const strengthPerCost = (this.
|
|
38
|
+
const strengthPerCost = (this.groundStrength / technoRules.cost) * 1000;
|
|
52
39
|
const numOwned = numBuildingsOwnedOfType(game, playerData, technoRules);
|
|
53
40
|
return this.basePriority * (1.0 - numOwned / this.baseAmount) * strengthPerCost;
|
|
54
41
|
}
|
|
@@ -24,34 +24,8 @@ export class ArtilleryUnit implements AiBuildingRules {
|
|
|
24
24
|
technoRules: TechnoRules,
|
|
25
25
|
threatCache: GlobalThreat | null,
|
|
26
26
|
): number {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
// If the enemy's defensive power is increasing we will start to build these.
|
|
30
|
-
if (threatCache && threatCache.totalDefensivePower > threatCache.totalAvailableAntiGroundFirepower) {
|
|
31
|
-
priority +=
|
|
32
|
-
this.artilleryPower *
|
|
33
|
-
(threatCache.totalAvailableAntiGroundFirepower / Math.max(1, threatCache.totalDefensivePower));
|
|
34
|
-
}
|
|
35
|
-
if (threatCache && this.antiGroundPower > 0) {
|
|
36
|
-
// If the enemy's power is increasing we should try to keep up.
|
|
37
|
-
if (threatCache.totalOffensiveLandThreat > threatCache.totalAvailableAntiGroundFirepower) {
|
|
38
|
-
priority +=
|
|
39
|
-
this.antiGroundPower *
|
|
40
|
-
this.basePriority *
|
|
41
|
-
(threatCache.totalOffensiveLandThreat / Math.max(1, threatCache.totalAvailableAntiGroundFirepower));
|
|
42
|
-
} else {
|
|
43
|
-
// But also, if our power dwarfs the enemy, keep pressing the advantage.
|
|
44
|
-
priority +=
|
|
45
|
-
(this.antiGroundPower *
|
|
46
|
-
this.basePriority *
|
|
47
|
-
GameMath.sqrt(
|
|
48
|
-
threatCache.totalAvailableAntiGroundFirepower /
|
|
49
|
-
Math.max(1, threatCache.totalOffensiveLandThreat + threatCache.totalDefensiveThreat),
|
|
50
|
-
)) /
|
|
51
|
-
(numOwned + 1);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return priority * (1.0 - numOwned / this.baseAmount);
|
|
27
|
+
// Units aren't built automatically, but are instead requested by missions.
|
|
28
|
+
return 0;
|
|
55
29
|
}
|
|
56
30
|
|
|
57
31
|
getMaxCount(
|
|
@@ -24,39 +24,8 @@ export class BasicAirUnit implements AiBuildingRules {
|
|
|
24
24
|
technoRules: TechnoRules,
|
|
25
25
|
threatCache: GlobalThreat | null,
|
|
26
26
|
): number {
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
let priority = 0;
|
|
30
|
-
if (
|
|
31
|
-
this.antiGroundPower > 0 &&
|
|
32
|
-
threatCache.totalOffensiveLandThreat > threatCache.totalAvailableAntiGroundFirepower
|
|
33
|
-
) {
|
|
34
|
-
priority +=
|
|
35
|
-
this.basePriority *
|
|
36
|
-
(threatCache.totalOffensiveLandThreat / Math.max(1, threatCache.totalAvailableAntiGroundFirepower));
|
|
37
|
-
}
|
|
38
|
-
if (
|
|
39
|
-
this.antiAirPower > 0 &&
|
|
40
|
-
threatCache.totalOffensiveAirThreat > threatCache.totalAvailableAntiAirFirepower
|
|
41
|
-
) {
|
|
42
|
-
priority +=
|
|
43
|
-
this.basePriority *
|
|
44
|
-
(threatCache.totalOffensiveAirThreat / Math.max(1, threatCache.totalAvailableAntiAirFirepower));
|
|
45
|
-
}
|
|
46
|
-
// sqrt so we don't build too much of one unit type.
|
|
47
|
-
priority += Math.min(
|
|
48
|
-
1.0,
|
|
49
|
-
Math.max(
|
|
50
|
-
1,
|
|
51
|
-
GameMath.sqrt(
|
|
52
|
-
threatCache.totalAvailableAirPower / Math.max(1, threatCache.totalOffensiveAntiAirThreat),
|
|
53
|
-
),
|
|
54
|
-
),
|
|
55
|
-
);
|
|
56
|
-
return this.baseAmount * priority;
|
|
57
|
-
}
|
|
58
|
-
const numOwned = numBuildingsOwnedOfType(game, playerData, technoRules);
|
|
59
|
-
return this.basePriority * (1.0 - numOwned / this.baseAmount);
|
|
27
|
+
// Units aren't built automatically, but are instead requested by missions.
|
|
28
|
+
return 0;
|
|
60
29
|
}
|
|
61
30
|
|
|
62
31
|
getMaxCount(
|
|
@@ -6,13 +6,13 @@ export class BasicBuilding implements AiBuildingRules {
|
|
|
6
6
|
constructor(
|
|
7
7
|
protected basePriority: number,
|
|
8
8
|
protected maxNeeded: number,
|
|
9
|
-
protected onlyBuildWhenFloatingCreditsAmount?: number
|
|
9
|
+
protected onlyBuildWhenFloatingCreditsAmount?: number,
|
|
10
10
|
) {}
|
|
11
11
|
|
|
12
12
|
getPlacementLocation(
|
|
13
13
|
game: GameApi,
|
|
14
14
|
playerData: PlayerData,
|
|
15
|
-
technoRules: TechnoRules
|
|
15
|
+
technoRules: TechnoRules,
|
|
16
16
|
): { rx: number; ry: number } | undefined {
|
|
17
17
|
return getDefaultPlacementLocation(game, playerData, playerData.startLocation, technoRules);
|
|
18
18
|
}
|
|
@@ -21,7 +21,7 @@ export class BasicBuilding implements AiBuildingRules {
|
|
|
21
21
|
game: GameApi,
|
|
22
22
|
playerData: PlayerData,
|
|
23
23
|
technoRules: TechnoRules,
|
|
24
|
-
threatCache: GlobalThreat | null
|
|
24
|
+
threatCache: GlobalThreat | null,
|
|
25
25
|
): number {
|
|
26
26
|
const numOwned = numBuildingsOwnedOfType(game, playerData, technoRules);
|
|
27
27
|
const calcMaxCount = this.getMaxCount(game, playerData, technoRules, threatCache);
|
|
@@ -29,18 +29,20 @@ export class BasicBuilding implements AiBuildingRules {
|
|
|
29
29
|
return -100;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
const priority = this.basePriority * (1.0 - numOwned / this.maxNeeded);
|
|
33
|
+
|
|
32
34
|
if (this.onlyBuildWhenFloatingCreditsAmount && playerData.credits < this.onlyBuildWhenFloatingCreditsAmount) {
|
|
33
|
-
return
|
|
35
|
+
return priority * (playerData.credits / this.onlyBuildWhenFloatingCreditsAmount);
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
return
|
|
38
|
+
return priority;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
getMaxCount(
|
|
40
42
|
game: GameApi,
|
|
41
43
|
playerData: PlayerData,
|
|
42
44
|
technoRules: TechnoRules,
|
|
43
|
-
threatCache: GlobalThreat | null
|
|
45
|
+
threatCache: GlobalThreat | null,
|
|
44
46
|
): number | null {
|
|
45
47
|
return this.maxNeeded;
|
|
46
48
|
}
|
|
@@ -24,52 +24,8 @@ export class BasicGroundUnit implements AiBuildingRules {
|
|
|
24
24
|
technoRules: TechnoRules,
|
|
25
25
|
threatCache: GlobalThreat | null,
|
|
26
26
|
): number {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
let priority = this.basePriority;
|
|
30
|
-
if (this.antiGroundPower > 0) {
|
|
31
|
-
// If the enemy's power is increasing we should try to keep up.
|
|
32
|
-
if (threatCache.totalOffensiveLandThreat > threatCache.totalAvailableAntiGroundFirepower) {
|
|
33
|
-
priority +=
|
|
34
|
-
this.antiGroundPower *
|
|
35
|
-
this.basePriority *
|
|
36
|
-
(threatCache.totalOffensiveLandThreat /
|
|
37
|
-
Math.max(1, threatCache.totalAvailableAntiGroundFirepower));
|
|
38
|
-
} else {
|
|
39
|
-
// But also, if our power dwarfs the enemy, keep pressing the advantage.
|
|
40
|
-
priority +=
|
|
41
|
-
(this.antiGroundPower *
|
|
42
|
-
this.basePriority *
|
|
43
|
-
GameMath.sqrt(
|
|
44
|
-
threatCache.totalAvailableAntiGroundFirepower /
|
|
45
|
-
Math.max(
|
|
46
|
-
1,
|
|
47
|
-
threatCache.totalOffensiveLandThreat + threatCache.totalDefensiveThreat,
|
|
48
|
-
),
|
|
49
|
-
)) /
|
|
50
|
-
(numOwned + 1);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (this.antiAirPower > 0) {
|
|
54
|
-
if (threatCache.totalOffensiveAirThreat > threatCache.totalAvailableAntiAirFirepower) {
|
|
55
|
-
priority +=
|
|
56
|
-
this.antiAirPower *
|
|
57
|
-
this.basePriority *
|
|
58
|
-
(threatCache.totalOffensiveAirThreat / Math.max(1, threatCache.totalAvailableAntiAirFirepower));
|
|
59
|
-
} else {
|
|
60
|
-
priority +=
|
|
61
|
-
(this.antiAirPower *
|
|
62
|
-
this.basePriority *
|
|
63
|
-
GameMath.sqrt(
|
|
64
|
-
threatCache.totalAvailableAntiAirFirepower /
|
|
65
|
-
Math.max(1, threatCache.totalOffensiveAirThreat + threatCache.totalDefensiveThreat),
|
|
66
|
-
)) /
|
|
67
|
-
(numOwned + 1);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return priority;
|
|
71
|
-
}
|
|
72
|
-
return this.basePriority * (1.0 - numOwned / this.baseAmount);
|
|
27
|
+
// Units aren't built automatically, but are instead requested by missions.
|
|
28
|
+
return 0;
|
|
73
29
|
}
|
|
74
30
|
|
|
75
31
|
getMaxCount(
|