@supalosa/chronodivide-bot 0.5.4 → 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 -103
- package/dist/bot/bot.js +105 -105
- 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 -34
- 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 -175
- package/dist/bot/logic/building/common.js +19 -19
- 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 -95
- 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 -100
- 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 -55
- 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 -250
- package/src/bot/logic/building/common.ts +21 -21
- 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 -120
- 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/threat.ts +15 -15
- package/src/bot/logic/threat/threatCalculator.ts +100 -100
- package/src/exampleBot.ts +111 -111
- package/tsconfig.json +73 -73
- package/dist/bot/logic/awarenessImpl.js +0 -132
- package/dist/bot/logic/awarenessImpl.js.map +0 -1
- package/dist/bot/logic/building/building.js +0 -126
- package/dist/bot/logic/building/building.js.map +0 -1
- 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 -58
- 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/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/attackSquad.js +0 -89
- package/dist/bot/logic/squad/behaviours/combatSquad.js +0 -102
- package/dist/bot/logic/squad/behaviours/combatSquad.js.map +0 -1
- package/dist/bot/logic/squad/behaviours/common.js +0 -40
- package/dist/bot/logic/squad/behaviours/common.js.map +0 -1
- package/dist/bot/logic/squad/behaviours/defenceSquad.js +0 -61
- package/dist/bot/logic/squad/behaviours/engineerSquad.js +0 -36
- package/dist/bot/logic/squad/behaviours/engineerSquad.js.map +0 -1
- package/dist/bot/logic/squad/behaviours/expansionSquad.js +0 -43
- package/dist/bot/logic/squad/behaviours/expansionSquad.js.map +0 -1
- package/dist/bot/logic/squad/behaviours/retreatSquad.js +0 -28
- package/dist/bot/logic/squad/behaviours/retreatSquad.js.map +0 -1
- package/dist/bot/logic/squad/behaviours/scoutingSquad.js +0 -86
- package/dist/bot/logic/squad/behaviours/scoutingSquad.js.map +0 -1
- 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 -199
- package/dist/bot/logic/squad/squadController.js.map +0 -1
- /package/dist/bot/logic/building/{ArtilleryUnit.js.map → artilleryUnit.js.map} +0 -0
|
@@ -1,186 +1,186 @@
|
|
|
1
|
-
import { ActionsApi, GameApi, OrderType, PlayerData, Vector2 } from "@chronodivide/game-api";
|
|
2
|
-
import { MissionFactory } from "../missionFactories.js";
|
|
3
|
-
import { MatchAwareness } from "../../awareness.js";
|
|
4
|
-
import { Mission, MissionAction, disbandMission, noop, requestUnits } from "../mission.js";
|
|
5
|
-
import { AttackMission } from "./attackMission.js";
|
|
6
|
-
import { MissionController } from "../missionController.js";
|
|
7
|
-
import { DebugLogger } from "../../common/utils.js";
|
|
8
|
-
import { ActionBatcher } from "../actionBatcher.js";
|
|
9
|
-
import { getDistanceBetweenTileAndPoint } from "../../map/map.js";
|
|
10
|
-
import { PrioritisedScoutTarget } from "../../common/scout.js";
|
|
11
|
-
|
|
12
|
-
const SCOUT_MOVE_COOLDOWN_TICKS = 30;
|
|
13
|
-
|
|
14
|
-
// Max units to spend on a particular scout target.
|
|
15
|
-
const MAX_ATTEMPTS_PER_TARGET = 5;
|
|
16
|
-
|
|
17
|
-
// Maximum ticks to spend trying to scout a target *without making progress towards it*.
|
|
18
|
-
// Every time a unit gets closer to the target, the timer refreshes.
|
|
19
|
-
const MAX_TICKS_PER_TARGET = 600;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* A mission that tries to scout around the map with a cheap, fast unit (usually attack dogs)
|
|
23
|
-
*/
|
|
24
|
-
export class ScoutingMission extends Mission {
|
|
25
|
-
private scoutTarget: Vector2 | null = null;
|
|
26
|
-
private attemptsOnCurrentTarget: number = 0;
|
|
27
|
-
private scoutTargetRefreshedAt: number = 0;
|
|
28
|
-
private lastMoveCommandTick: number = 0;
|
|
29
|
-
private scoutTargetIsPermanent: boolean = false;
|
|
30
|
-
|
|
31
|
-
// Minimum distance from a scout to the target.
|
|
32
|
-
private scoutMinDistance?: number;
|
|
33
|
-
|
|
34
|
-
private hadUnit: boolean = false;
|
|
35
|
-
|
|
36
|
-
constructor(
|
|
37
|
-
uniqueName: string,
|
|
38
|
-
private priority: number,
|
|
39
|
-
logger: DebugLogger,
|
|
40
|
-
) {
|
|
41
|
-
super(uniqueName, logger);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
public _onAiUpdate(
|
|
45
|
-
gameApi: GameApi,
|
|
46
|
-
actionsApi: ActionsApi,
|
|
47
|
-
playerData: PlayerData,
|
|
48
|
-
matchAwareness: MatchAwareness,
|
|
49
|
-
actionBatcher: ActionBatcher,
|
|
50
|
-
): MissionAction {
|
|
51
|
-
const scoutNames = ["ADOG", "DOG", "E1", "E2", "FV", "HTK"];
|
|
52
|
-
const scouts = this.getUnitsOfTypes(gameApi, ...scoutNames);
|
|
53
|
-
|
|
54
|
-
if ((matchAwareness.getSectorCache().getOverallVisibility() || 0) > 0.9) {
|
|
55
|
-
return disbandMission();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (scouts.length === 0) {
|
|
59
|
-
// Count the number of times the scout dies trying to uncover the current scoutTarget.
|
|
60
|
-
if (this.scoutTarget && this.hadUnit) {
|
|
61
|
-
this.attemptsOnCurrentTarget++;
|
|
62
|
-
this.hadUnit = false;
|
|
63
|
-
}
|
|
64
|
-
return requestUnits(scoutNames, this.priority);
|
|
65
|
-
} else if (this.scoutTarget) {
|
|
66
|
-
this.hadUnit = true;
|
|
67
|
-
if (!this.scoutTargetIsPermanent) {
|
|
68
|
-
if (this.attemptsOnCurrentTarget > MAX_ATTEMPTS_PER_TARGET) {
|
|
69
|
-
this.logger(
|
|
70
|
-
`Scout target ${this.scoutTarget.x},${this.scoutTarget.y} took too many attempts, moving to next`,
|
|
71
|
-
);
|
|
72
|
-
this.setScoutTarget(null, 0);
|
|
73
|
-
return noop();
|
|
74
|
-
}
|
|
75
|
-
if (gameApi.getCurrentTick() > this.scoutTargetRefreshedAt + MAX_TICKS_PER_TARGET) {
|
|
76
|
-
this.logger(
|
|
77
|
-
`Scout target ${this.scoutTarget.x},${this.scoutTarget.y} took too long, moving to next`,
|
|
78
|
-
);
|
|
79
|
-
this.setScoutTarget(null, 0);
|
|
80
|
-
return noop();
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
const targetTile = gameApi.mapApi.getTile(this.scoutTarget.x, this.scoutTarget.y);
|
|
84
|
-
if (!targetTile) {
|
|
85
|
-
throw new Error(`target tile ${this.scoutTarget.x},${this.scoutTarget.y} does not exist`);
|
|
86
|
-
}
|
|
87
|
-
if (gameApi.getCurrentTick() > this.lastMoveCommandTick + SCOUT_MOVE_COOLDOWN_TICKS) {
|
|
88
|
-
this.lastMoveCommandTick = gameApi.getCurrentTick();
|
|
89
|
-
scouts.forEach((unit) => {
|
|
90
|
-
if (this.scoutTarget) {
|
|
91
|
-
actionsApi.orderUnits([unit.id], OrderType.AttackMove, this.scoutTarget.x, this.scoutTarget.y);
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
// Check that a scout is actually moving closer to the target.
|
|
95
|
-
const distances = scouts.map((unit) => getDistanceBetweenTileAndPoint(unit.tile, this.scoutTarget!));
|
|
96
|
-
const newMinDistance = Math.min(...distances);
|
|
97
|
-
if (!this.scoutMinDistance || newMinDistance < this.scoutMinDistance) {
|
|
98
|
-
this.logger(
|
|
99
|
-
`Scout timeout refreshed because unit moved closer to point (${newMinDistance} < ${this.scoutMinDistance})`,
|
|
100
|
-
);
|
|
101
|
-
this.scoutTargetRefreshedAt = gameApi.getCurrentTick();
|
|
102
|
-
this.scoutMinDistance = newMinDistance;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
if (gameApi.mapApi.isVisibleTile(targetTile, playerData.name)) {
|
|
106
|
-
this.logger(
|
|
107
|
-
`Scout target ${this.scoutTarget.x},${this.scoutTarget.y} successfully scouted, moving to next`,
|
|
108
|
-
);
|
|
109
|
-
this.setScoutTarget(null, gameApi.getCurrentTick());
|
|
110
|
-
}
|
|
111
|
-
} else {
|
|
112
|
-
const nextScoutTarget = matchAwareness.getScoutingManager().getNewScoutTarget();
|
|
113
|
-
if (!nextScoutTarget) {
|
|
114
|
-
this.logger(`No more scouting targets available, disbanding.`);
|
|
115
|
-
return disbandMission();
|
|
116
|
-
}
|
|
117
|
-
this.setScoutTarget(nextScoutTarget, gameApi.getCurrentTick());
|
|
118
|
-
}
|
|
119
|
-
return noop();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
setScoutTarget(target: PrioritisedScoutTarget | null, currentTick: number) {
|
|
123
|
-
this.attemptsOnCurrentTarget = 0;
|
|
124
|
-
this.scoutTargetRefreshedAt = currentTick;
|
|
125
|
-
this.scoutTarget = target?.asVector2() ?? null;
|
|
126
|
-
this.scoutMinDistance = undefined;
|
|
127
|
-
this.scoutTargetIsPermanent = target?.isPermanent ?? false;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
public getGlobalDebugText(): string | undefined {
|
|
131
|
-
return "scouting";
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
public getPriority() {
|
|
135
|
-
return this.priority;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const SCOUT_COOLDOWN_TICKS = 300;
|
|
140
|
-
|
|
141
|
-
export class ScoutingMissionFactory implements MissionFactory {
|
|
142
|
-
constructor(private lastScoutAt: number = -SCOUT_COOLDOWN_TICKS) {}
|
|
143
|
-
|
|
144
|
-
getName(): string {
|
|
145
|
-
return "ScoutingMissionFactory";
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
maybeCreateMissions(
|
|
149
|
-
gameApi: GameApi,
|
|
150
|
-
playerData: PlayerData,
|
|
151
|
-
matchAwareness: MatchAwareness,
|
|
152
|
-
missionController: MissionController,
|
|
153
|
-
logger: DebugLogger,
|
|
154
|
-
): void {
|
|
155
|
-
if (gameApi.getCurrentTick() < this.lastScoutAt + SCOUT_COOLDOWN_TICKS) {
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
if (!matchAwareness.getScoutingManager().hasScoutTargets()) {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
if (!missionController.addMission(new ScoutingMission("globalScout", 10, logger))) {
|
|
162
|
-
this.lastScoutAt = gameApi.getCurrentTick();
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
onMissionFailed(
|
|
167
|
-
gameApi: GameApi,
|
|
168
|
-
playerData: PlayerData,
|
|
169
|
-
matchAwareness: MatchAwareness,
|
|
170
|
-
failedMission: Mission<any>,
|
|
171
|
-
failureReason: undefined,
|
|
172
|
-
missionController: MissionController,
|
|
173
|
-
logger: DebugLogger,
|
|
174
|
-
): void {
|
|
175
|
-
if (gameApi.getCurrentTick() < this.lastScoutAt + SCOUT_COOLDOWN_TICKS) {
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
if (!matchAwareness.getScoutingManager().hasScoutTargets()) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
if (failedMission instanceof AttackMission) {
|
|
182
|
-
missionController.addMission(new ScoutingMission("globalScout", 10, logger));
|
|
183
|
-
this.lastScoutAt = gameApi.getCurrentTick();
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
1
|
+
import { ActionsApi, GameApi, OrderType, PlayerData, Vector2 } from "@chronodivide/game-api";
|
|
2
|
+
import { MissionFactory } from "../missionFactories.js";
|
|
3
|
+
import { MatchAwareness } from "../../awareness.js";
|
|
4
|
+
import { Mission, MissionAction, disbandMission, noop, requestUnits } from "../mission.js";
|
|
5
|
+
import { AttackMission } from "./attackMission.js";
|
|
6
|
+
import { MissionController } from "../missionController.js";
|
|
7
|
+
import { DebugLogger } from "../../common/utils.js";
|
|
8
|
+
import { ActionBatcher } from "../actionBatcher.js";
|
|
9
|
+
import { getDistanceBetweenTileAndPoint } from "../../map/map.js";
|
|
10
|
+
import { PrioritisedScoutTarget } from "../../common/scout.js";
|
|
11
|
+
|
|
12
|
+
const SCOUT_MOVE_COOLDOWN_TICKS = 30;
|
|
13
|
+
|
|
14
|
+
// Max units to spend on a particular scout target.
|
|
15
|
+
const MAX_ATTEMPTS_PER_TARGET = 5;
|
|
16
|
+
|
|
17
|
+
// Maximum ticks to spend trying to scout a target *without making progress towards it*.
|
|
18
|
+
// Every time a unit gets closer to the target, the timer refreshes.
|
|
19
|
+
const MAX_TICKS_PER_TARGET = 600;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A mission that tries to scout around the map with a cheap, fast unit (usually attack dogs)
|
|
23
|
+
*/
|
|
24
|
+
export class ScoutingMission extends Mission {
|
|
25
|
+
private scoutTarget: Vector2 | null = null;
|
|
26
|
+
private attemptsOnCurrentTarget: number = 0;
|
|
27
|
+
private scoutTargetRefreshedAt: number = 0;
|
|
28
|
+
private lastMoveCommandTick: number = 0;
|
|
29
|
+
private scoutTargetIsPermanent: boolean = false;
|
|
30
|
+
|
|
31
|
+
// Minimum distance from a scout to the target.
|
|
32
|
+
private scoutMinDistance?: number;
|
|
33
|
+
|
|
34
|
+
private hadUnit: boolean = false;
|
|
35
|
+
|
|
36
|
+
constructor(
|
|
37
|
+
uniqueName: string,
|
|
38
|
+
private priority: number,
|
|
39
|
+
logger: DebugLogger,
|
|
40
|
+
) {
|
|
41
|
+
super(uniqueName, logger);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public _onAiUpdate(
|
|
45
|
+
gameApi: GameApi,
|
|
46
|
+
actionsApi: ActionsApi,
|
|
47
|
+
playerData: PlayerData,
|
|
48
|
+
matchAwareness: MatchAwareness,
|
|
49
|
+
actionBatcher: ActionBatcher,
|
|
50
|
+
): MissionAction {
|
|
51
|
+
const scoutNames = ["ADOG", "DOG", "E1", "E2", "FV", "HTK"];
|
|
52
|
+
const scouts = this.getUnitsOfTypes(gameApi, ...scoutNames);
|
|
53
|
+
|
|
54
|
+
if ((matchAwareness.getSectorCache().getOverallVisibility() || 0) > 0.9) {
|
|
55
|
+
return disbandMission();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (scouts.length === 0) {
|
|
59
|
+
// Count the number of times the scout dies trying to uncover the current scoutTarget.
|
|
60
|
+
if (this.scoutTarget && this.hadUnit) {
|
|
61
|
+
this.attemptsOnCurrentTarget++;
|
|
62
|
+
this.hadUnit = false;
|
|
63
|
+
}
|
|
64
|
+
return requestUnits(scoutNames, this.priority);
|
|
65
|
+
} else if (this.scoutTarget) {
|
|
66
|
+
this.hadUnit = true;
|
|
67
|
+
if (!this.scoutTargetIsPermanent) {
|
|
68
|
+
if (this.attemptsOnCurrentTarget > MAX_ATTEMPTS_PER_TARGET) {
|
|
69
|
+
this.logger(
|
|
70
|
+
`Scout target ${this.scoutTarget.x},${this.scoutTarget.y} took too many attempts, moving to next`,
|
|
71
|
+
);
|
|
72
|
+
this.setScoutTarget(null, 0);
|
|
73
|
+
return noop();
|
|
74
|
+
}
|
|
75
|
+
if (gameApi.getCurrentTick() > this.scoutTargetRefreshedAt + MAX_TICKS_PER_TARGET) {
|
|
76
|
+
this.logger(
|
|
77
|
+
`Scout target ${this.scoutTarget.x},${this.scoutTarget.y} took too long, moving to next`,
|
|
78
|
+
);
|
|
79
|
+
this.setScoutTarget(null, 0);
|
|
80
|
+
return noop();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const targetTile = gameApi.mapApi.getTile(this.scoutTarget.x, this.scoutTarget.y);
|
|
84
|
+
if (!targetTile) {
|
|
85
|
+
throw new Error(`target tile ${this.scoutTarget.x},${this.scoutTarget.y} does not exist`);
|
|
86
|
+
}
|
|
87
|
+
if (gameApi.getCurrentTick() > this.lastMoveCommandTick + SCOUT_MOVE_COOLDOWN_TICKS) {
|
|
88
|
+
this.lastMoveCommandTick = gameApi.getCurrentTick();
|
|
89
|
+
scouts.forEach((unit) => {
|
|
90
|
+
if (this.scoutTarget) {
|
|
91
|
+
actionsApi.orderUnits([unit.id], OrderType.AttackMove, this.scoutTarget.x, this.scoutTarget.y);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
// Check that a scout is actually moving closer to the target.
|
|
95
|
+
const distances = scouts.map((unit) => getDistanceBetweenTileAndPoint(unit.tile, this.scoutTarget!));
|
|
96
|
+
const newMinDistance = Math.min(...distances);
|
|
97
|
+
if (!this.scoutMinDistance || newMinDistance < this.scoutMinDistance) {
|
|
98
|
+
this.logger(
|
|
99
|
+
`Scout timeout refreshed because unit moved closer to point (${newMinDistance} < ${this.scoutMinDistance})`,
|
|
100
|
+
);
|
|
101
|
+
this.scoutTargetRefreshedAt = gameApi.getCurrentTick();
|
|
102
|
+
this.scoutMinDistance = newMinDistance;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (gameApi.mapApi.isVisibleTile(targetTile, playerData.name)) {
|
|
106
|
+
this.logger(
|
|
107
|
+
`Scout target ${this.scoutTarget.x},${this.scoutTarget.y} successfully scouted, moving to next`,
|
|
108
|
+
);
|
|
109
|
+
this.setScoutTarget(null, gameApi.getCurrentTick());
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
const nextScoutTarget = matchAwareness.getScoutingManager().getNewScoutTarget();
|
|
113
|
+
if (!nextScoutTarget) {
|
|
114
|
+
this.logger(`No more scouting targets available, disbanding.`);
|
|
115
|
+
return disbandMission();
|
|
116
|
+
}
|
|
117
|
+
this.setScoutTarget(nextScoutTarget, gameApi.getCurrentTick());
|
|
118
|
+
}
|
|
119
|
+
return noop();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
setScoutTarget(target: PrioritisedScoutTarget | null, currentTick: number) {
|
|
123
|
+
this.attemptsOnCurrentTarget = 0;
|
|
124
|
+
this.scoutTargetRefreshedAt = currentTick;
|
|
125
|
+
this.scoutTarget = target?.asVector2() ?? null;
|
|
126
|
+
this.scoutMinDistance = undefined;
|
|
127
|
+
this.scoutTargetIsPermanent = target?.isPermanent ?? false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public getGlobalDebugText(): string | undefined {
|
|
131
|
+
return "scouting";
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public getPriority() {
|
|
135
|
+
return this.priority;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const SCOUT_COOLDOWN_TICKS = 300;
|
|
140
|
+
|
|
141
|
+
export class ScoutingMissionFactory implements MissionFactory {
|
|
142
|
+
constructor(private lastScoutAt: number = -SCOUT_COOLDOWN_TICKS) {}
|
|
143
|
+
|
|
144
|
+
getName(): string {
|
|
145
|
+
return "ScoutingMissionFactory";
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
maybeCreateMissions(
|
|
149
|
+
gameApi: GameApi,
|
|
150
|
+
playerData: PlayerData,
|
|
151
|
+
matchAwareness: MatchAwareness,
|
|
152
|
+
missionController: MissionController,
|
|
153
|
+
logger: DebugLogger,
|
|
154
|
+
): void {
|
|
155
|
+
if (gameApi.getCurrentTick() < this.lastScoutAt + SCOUT_COOLDOWN_TICKS) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (!matchAwareness.getScoutingManager().hasScoutTargets()) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (!missionController.addMission(new ScoutingMission("globalScout", 10, logger))) {
|
|
162
|
+
this.lastScoutAt = gameApi.getCurrentTick();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
onMissionFailed(
|
|
167
|
+
gameApi: GameApi,
|
|
168
|
+
playerData: PlayerData,
|
|
169
|
+
matchAwareness: MatchAwareness,
|
|
170
|
+
failedMission: Mission<any>,
|
|
171
|
+
failureReason: undefined,
|
|
172
|
+
missionController: MissionController,
|
|
173
|
+
logger: DebugLogger,
|
|
174
|
+
): void {
|
|
175
|
+
if (gameApi.getCurrentTick() < this.lastScoutAt + SCOUT_COOLDOWN_TICKS) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (!matchAwareness.getScoutingManager().hasScoutTargets()) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (failedMission instanceof AttackMission) {
|
|
182
|
+
missionController.addMission(new ScoutingMission("globalScout", 10, logger));
|
|
183
|
+
this.lastScoutAt = gameApi.getCurrentTick();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|