From 0017256ddc114f2344e7c56349731f55d4496d73 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 3 Aug 2023 20:29:42 +0200 Subject: [PATCH 01/41] .editorconfig --- .editorconfig | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.editorconfig b/.editorconfig index 02ff606f3..ca2573dc0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,6 @@ [*] charset=utf-8 -end_of_line=crlf +end_of_line=lf insert_final_newline=false indent_style=space indent_size=4 @@ -8,12 +8,17 @@ indent_size=4 [{.babelrc,.stylelintrc,.eslintrc,jest.config,*.json,*.jsb3,*.jsb2,*.bowerrc}] indent_style=space indent_size=2 +end_of_line=lf +trim_trailing_whitespace=true -[{*.ats,*.ts}] +[{*.ats,*.ts,*.js}] indent_style=tab tab_width=4 +end_of_line=lf +trim_trailing_whitespace=true [tslint.json] indent_style=space indent_size=2 - +end_of_line=lf +trim_trailing_whitespace=true From c6e5b62aeb56f686018f47bf0556ab982db3e405 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Fri, 4 Aug 2023 16:47:06 +0200 Subject: [PATCH 02/41] .tool-versions --- .tool-versions | 1 + 1 file changed, 1 insertion(+) create mode 100644 .tool-versions diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 000000000..a61cf126e --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +nodejs 10.24.1 From 7037fd60a7ccfa33f782d2bab9b38ab42aab8c29 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sun, 10 Sep 2023 23:50:02 +0200 Subject: [PATCH 03/41] Cleanup .gitignore --- .gitignore | 76 ------------------------------------------------------ 1 file changed, 76 deletions(-) diff --git a/.gitignore b/.gitignore index 3b4899caf..0d6f2e546 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ screeps.json /dist /node_modules /typings -/.rpt2_cache /tsc-out # Ignore Mathematica notebooks so they don't add 50 billion lines to contribution count @@ -27,78 +26,3 @@ screeps.json # Screeps config file /config.json - -# Numerous always-ignore extensions -*.diff -*.err -*.orig -*.log -*.rej -*.swo -*.swp -*.zip -*.vi - -# Editor folders -.cache -.project -.settings -.tmproj -*.esproj -nbproject -*.sublime-project -*.sublime-workspace -.idea - -# ========================= -# Operating System Files -# ========================= - -# OSX -# ========================= - -.DS_Store -.AppleDouble -.LSOverride - -# Thumbnails -._* - -# Files that might appear on external disk -.Spotlight-V100 -.Trashes - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -# Windows -# ========================= - -# Windows image file caches -Thumbs.db -ehthumbs.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msm -*.msp - -# Windows shortcuts -*.lnk - -# VStudio files -applicationhost.config -*.suo -*.njsproj -*.sln \ No newline at end of file From f9facc7e466e88fe8df4498158b92a0ac60b8625 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 3 Aug 2023 18:25:52 +0200 Subject: [PATCH 04/41] Check room status when selecting rooms in RandomWalkerScoutOverlord --- src/overlords/scouting/randomWalker.ts | 30 ++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/overlords/scouting/randomWalker.ts b/src/overlords/scouting/randomWalker.ts index 367255489..609fa1cee 100644 --- a/src/overlords/scouting/randomWalker.ts +++ b/src/overlords/scouting/randomWalker.ts @@ -32,17 +32,35 @@ export class RandomWalkerScoutOverlord extends Overlord { // scout.goTo(enemyConstructionSites[0].pos); // return; // } + // Check if room might be connected to newbie/respawn zone const indestructibleWalls = _.filter(scout.room.walls, wall => wall.hits == undefined); if (indestructibleWalls.length > 0) { // go back to origin colony if you find a room near newbie zone scout.task = Tasks.goToRoom(this.colony.room.name); // todo: make this more precise - } else { - // Pick a new room - const neighboringRooms = _.values(Game.map.describeExits(scout.pos.roomName)) as string[]; - const roomName = _.sample(neighboringRooms); - if (Game.map.isRoomAvailable(roomName)) { - scout.task = Tasks.goToRoom(roomName); + return; + } + + const roomStatus = Game.map.getRoomStatus(scout.room.name); + + let neighboringRooms = _.values(Game.map.describeExits(scout.pos.roomName)); + neighboringRooms = _.shuffle(neighboringRooms); + + // Pick a new random room from the neighboring rooms, making sure they have compatible room status + let neighboringRoom; + while ((neighboringRoom = neighboringRooms.shift())) { + + const neighborStatus = Game.map.getRoomStatus(scout.room.name); + if (roomStatus.status !== neighborStatus.status) { + continue; } + + scout.task = Tasks.goToRoom(neighboringRoom); + break; + } + + // Just move back to the colony and start over + if (!scout.task) { + scout.task = Tasks.goToRoom(this.colony.room.name); } } From 94d64561abd52cb56400ba6b40f0055ba2385e3c Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 3 Aug 2023 18:28:13 +0200 Subject: [PATCH 05/41] Only plan expansion into rooms that have the same status as the colony --- src/strategy/ExpansionPlanner.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strategy/ExpansionPlanner.ts b/src/strategy/ExpansionPlanner.ts index 2b0ea4cc4..afa5daeec 100644 --- a/src/strategy/ExpansionPlanner.ts +++ b/src/strategy/ExpansionPlanner.ts @@ -122,8 +122,9 @@ export class ExpansionPlanner implements IExpansionPlanner { score += CATALYST_BONUS; } } + // Update best choices - if (score > bestScore && Game.map.isRoomAvailable(roomName)) { + if (score > bestScore && Game.map.getRoomStatus(roomName).status === Game.map.getRoomStatus(colony.room.name).status) { bestScore = score; bestRoom = roomName; } From 2f944a55405757765a8f5cd22530bd0858970c22 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 3 Aug 2023 18:30:22 +0200 Subject: [PATCH 06/41] Check for room status when computing outpost candidates --- src/Overseer.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Overseer.ts b/src/Overseer.ts index 68664c3b3..b01c3f795 100644 --- a/src/Overseer.ts +++ b/src/Overseer.ts @@ -356,6 +356,7 @@ export class Overseer implements IOverseer { } private computePossibleOutposts(colony: Colony, depth = 3): string[] { + const colonyRoomStatus = Game.map.getRoomStatus(colony.room.name).status; return _.filter(Cartographer.findRoomsInRange(colony.room.name, depth), roomName => { if (Cartographer.roomType(roomName) != ROOMTYPE_CONTROLLER) { return false; @@ -378,7 +379,7 @@ export class Overseer implements IOverseer { } const neighboringRooms = _.values(Game.map.describeExits(roomName)) as string[]; const isReachableFromColony = _.any(neighboringRooms, r => colony.roomNames.includes(r)); - return isReachableFromColony && Game.map.isRoomAvailable(roomName); + return isReachableFromColony && Game.map.getRoomStatus(roomName).status === colonyRoomStatus; }); } From 5a7dbd6551a1c83e7a064b7b6d151abb1040db66 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 3 Aug 2023 18:54:23 +0200 Subject: [PATCH 07/41] Hack to get deref working again --- src/console/globals.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/console/globals.ts b/src/console/globals.ts index 8b5c15210..07f944422 100644 --- a/src/console/globals.ts +++ b/src/console/globals.ts @@ -4,7 +4,7 @@ global.__VERSION__ = '0.5.2'; declare function deref(ref: string): RoomObject | null; global.deref = function(ref: string): RoomObject | null { // dereference any object from identifier - return Game.getObjectById(ref) || Game.flags[ref] || Game.creeps[ref] || Game.spawns[ref] || null; + return Game.getObjectById(ref) as any as RoomObject || Game.flags[ref] || Game.creeps[ref] || Game.spawns[ref] || null; }; declare function derefRoomPosition(protoPos: ProtoPos): RoomPosition; From 45a22197bc31c662022c3b7428e8f4d5a6679cb2 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 3 Aug 2023 19:07:46 +0200 Subject: [PATCH 08/41] Ensure typing of exceptions in Overseer.try() --- src/Overseer.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Overseer.ts b/src/Overseer.ts index b01c3f795..916355984 100644 --- a/src/Overseer.ts +++ b/src/Overseer.ts @@ -90,13 +90,17 @@ export class Overseer implements IOverseer { try { callback(); } catch (e) { - if (identifier) { - e.name = `Caught unhandled exception at ${'' + callback} (identifier: ${identifier}): \n` - + e.name + '\n' + e.stack; + if (e instanceof Error) { + if (identifier) { + e.name = `Caught unhandled exception at ${'' + callback} (identifier: ${identifier}): \n` + + e.name + '\n' + e.stack; + } else { + e.name = `Caught unhandled exception at ${'' + callback}: \n` + e.name + '\n' + e.stack; + } + Overmind.exceptions.push(e); } else { - e.name = `Caught unhandled exception at ${'' + callback}: \n` + e.name + '\n' + e.stack; + log.error(`Got a non-Error exception`, e); } - Overmind.exceptions.push(e); } } else { callback(); From dda2043c8c14440f015d9a1e0ff80a5fd1887f4b Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 3 Aug 2023 19:08:08 +0200 Subject: [PATCH 09/41] Fix a few more _HasId warts --- src/directives/targeting/modularDismantle.ts | 2 +- src/overlords/mining/extractor.ts | 2 +- src/overlords/situational/dismantler.ts | 2 +- src/reinforcementLearning/actionParser.ts | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/directives/targeting/modularDismantle.ts b/src/directives/targeting/modularDismantle.ts index 87a01f5a5..d158bf161 100644 --- a/src/directives/targeting/modularDismantle.ts +++ b/src/directives/targeting/modularDismantle.ts @@ -7,7 +7,7 @@ import {Directive} from '../Directive'; interface DirectiveModularDismantleMemory extends FlagMemory { - targetId?: string; + targetId?: Id>; numberSpots?: number; attackInsteadOfDismantle?: boolean; onlyKillRampart?: boolean; diff --git a/src/overlords/mining/extractor.ts b/src/overlords/mining/extractor.ts index 9f756c203..35acc5f1f 100644 --- a/src/overlords/mining/extractor.ts +++ b/src/overlords/mining/extractor.ts @@ -38,7 +38,7 @@ export class ExtractorOverlord extends Overlord { // If mineral is ready to be mined, make a container private shouldHaveContainer() { - return this.mineral && (this.mineral.mineralAmount > 0 || this.mineral.ticksToRegeneration < 2000); + return this.mineral && (this.mineral.mineralAmount > 0 || (this.mineral.ticksToRegeneration || 0) < 2000); } private populateStructures() { diff --git a/src/overlords/situational/dismantler.ts b/src/overlords/situational/dismantler.ts index 293764b85..7520def4d 100644 --- a/src/overlords/situational/dismantler.ts +++ b/src/overlords/situational/dismantler.ts @@ -68,7 +68,7 @@ export class DismantleOverlord extends Overlord { } else { if (!this.target) { if (this.directive.memory.targetId) { - this.target = Game.getObjectById(this.directive.memory.targetId.toString()) || undefined; + this.target = Game.getObjectById(this.directive.memory.targetId) || undefined; } this.target = this.target || this.directive.getTarget(); if (!this.target) { diff --git a/src/reinforcementLearning/actionParser.ts b/src/reinforcementLearning/actionParser.ts index d6cbc407d..9767f5f5a 100644 --- a/src/reinforcementLearning/actionParser.ts +++ b/src/reinforcementLearning/actionParser.ts @@ -41,14 +41,14 @@ export class ActionParser { const command: string = action[0]; const predicate: any = action[1]; - const targ: RoomObject | null = typeof predicate == 'string' ? Game.getObjectById(predicate) : null; + const targ: _HasId | null = typeof predicate == 'string' ? Game.getObjectById(predicate) : null; switch (command) { case 'move': actor.move(predicate); break; case 'goTo': - if (targ) actor.goTo(targ); + if (targ) actor.goTo(targ as any as RoomObject); break; case 'attack': if (targ) actor.attack(targ); From 1a3bf4faffe629f957411dde09b538d04b94ae16 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 3 Aug 2023 20:31:15 +0200 Subject: [PATCH 10/41] Fix types now that Store exist --- src/Overseer.ts | 4 ++-- src/utilities/utils.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Overseer.ts b/src/Overseer.ts index 916355984..9b6e99a62 100644 --- a/src/Overseer.ts +++ b/src/Overseer.ts @@ -186,8 +186,8 @@ export class Overseer implements IOverseer { } // Place a logistics request directive for every tombstone with non-empty store that isn't on a container for (const tombstone of colony.tombstones) { - if (_.sum(tombstone.store) > LogisticsNetwork.settings.droppedEnergyThreshold - || _.sum(tombstone.store) > tombstone.store.energy) { + if (tombstone.store.getUsedCapacity() > LogisticsNetwork.settings.droppedEnergyThreshold + || tombstone.store.getUsedCapacity() > tombstone.store.energy) { if (colony.bunker && tombstone.pos.isEqualTo(colony.bunker.anchor)) continue; colony.logisticsNetwork.requestOutput(tombstone, {resourceType: 'all'}); } diff --git a/src/utilities/utils.ts b/src/utilities/utils.ts index 1763ab8e2..8560170d1 100644 --- a/src/utilities/utils.ts +++ b/src/utilities/utils.ts @@ -54,7 +54,7 @@ export function minMax(value: number, min: number, max: number): number { return Math.max(Math.min(value, max), min); } -export function hasMinerals(store: { [resourceType: string]: number }): boolean { +export function hasMinerals(store: StoreDefinition): boolean { for (const resourceType in store) { if (resourceType != RESOURCE_ENERGY && (store[resourceType] || 0) > 0) { return true; From 661b643120efb0fc894d4928914281719b45650a Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 3 Aug 2023 20:32:13 +0200 Subject: [PATCH 11/41] Check empty memory with isEmpty instead of an object compare --- src/console/Console.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/console/Console.ts b/src/console/Console.ts index 004ee7e8a..d59055a59 100644 --- a/src/console/Console.ts +++ b/src/console/Console.ts @@ -610,7 +610,7 @@ export class OvermindConsole { } // Suicide any creeps which have no memory for (const i in Game.creeps) { - if (Game.creeps[i].memory == {}) { + if (_.isEmpty(Game.creeps[i].memory)) { Game.creeps[i].suicide(); } } From 817b471f196880104699e364303a1ccc2abbb51e Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Fri, 4 Aug 2023 03:45:39 +0200 Subject: [PATCH 12/41] Make Task generic over its target type --- src/logistics/RoadLogistics.ts | 4 +- src/overlords/core/queen_bunker.ts | 12 ++--- src/tasks/Task.ts | 65 ++++++++++++++++++------- src/tasks/Tasks.ts | 4 +- src/tasks/initializer.ts | 4 +- src/tasks/instances/attack.ts | 6 +-- src/tasks/instances/build.ts | 4 +- src/tasks/instances/claim.ts | 4 +- src/tasks/instances/dismantle.ts | 3 +- src/tasks/instances/drop.ts | 9 ++-- src/tasks/instances/fortify.ts | 3 +- src/tasks/instances/generateSafeMode.ts | 4 +- src/tasks/instances/getBoosted.ts | 5 +- src/tasks/instances/getRenewed.ts | 4 +- src/tasks/instances/goTo.ts | 6 +-- src/tasks/instances/goToRoom.ts | 6 +-- src/tasks/instances/harvest.ts | 4 +- src/tasks/instances/heal.ts | 5 +- src/tasks/instances/invalid.ts | 4 +- src/tasks/instances/meleeAttack.ts | 4 +- src/tasks/instances/pickup.ts | 4 +- src/tasks/instances/rangedAttack.ts | 4 +- src/tasks/instances/recharge.ts | 8 ++- src/tasks/instances/repair.ts | 4 +- src/tasks/instances/reserve.ts | 4 +- src/tasks/instances/signController.ts | 4 +- src/tasks/instances/transfer.ts | 4 +- src/tasks/instances/transferAll.ts | 4 +- src/tasks/instances/upgrade.ts | 4 +- src/tasks/instances/withdraw.ts | 4 +- src/tasks/instances/withdrawAll.ts | 5 +- src/zerg/Zerg.ts | 6 +-- 32 files changed, 97 insertions(+), 118 deletions(-) diff --git a/src/logistics/RoadLogistics.ts b/src/logistics/RoadLogistics.ts index aca4bc1fb..b08f41252 100644 --- a/src/logistics/RoadLogistics.ts +++ b/src/logistics/RoadLogistics.ts @@ -163,10 +163,10 @@ export class RoadLogistics { } } - buildPavingManifest(worker: Zerg, room: Room): Task | null { + buildPavingManifest(worker: Zerg, room: Room): Task | null { let energy = worker.carry.energy; const targetRefs: { [ref: string]: boolean } = {}; - const tasks: Task[] = []; + const tasks: Task[] = []; let target: StructureRoad | undefined; let previousPos: RoomPosition | undefined; while (true) { diff --git a/src/overlords/core/queen_bunker.ts b/src/overlords/core/queen_bunker.ts index f08c695db..1ec829e89 100644 --- a/src/overlords/core/queen_bunker.ts +++ b/src/overlords/core/queen_bunker.ts @@ -117,8 +117,8 @@ export class BunkerQueenOverlord extends Overlord { } // Builds a series of tasks to empty unnecessary carry contents, withdraw required resources, and supply structures - private buildSupplyTaskManifest(queen: Zerg): Task | null { - let tasks: Task[] = []; + private buildSupplyTaskManifest(queen: Zerg): Task | null { + let tasks: Task[] = []; // Step 1: empty all contents (this shouldn't be necessary since queen is normally empty at this point) let queenPos = queen.pos; if (_.sum(queen.carry) > 0) { @@ -143,7 +143,7 @@ export class BunkerQueenOverlord extends Overlord { } } } - const supplyTasks: Task[] = []; + const supplyTasks: Task[] = []; for (const request of supplyRequests) { // stop when carry will be full const remainingAmount = queen.carryCapacity - _.sum(queenCarry); @@ -161,7 +161,7 @@ export class BunkerQueenOverlord extends Overlord { supplyTasks.push(Tasks.transfer(request.target, request.resourceType, amount)); } // Step 3: make withdraw tasks to get the needed resources - const withdrawTasks: Task[] = []; + const withdrawTasks: Task[] = []; const neededResources = _.keys(queenCarry) as ResourceConstant[]; const targets: AnyStoreStructure[] = _.filter(this.storeStructures, s => _.all(neededResources, resource => (s.store[resource] || 0) >= (queenCarry[resource] || 0))); @@ -211,8 +211,8 @@ export class BunkerQueenOverlord extends Overlord { } // Builds a series of tasks to withdraw required resources from targets - private buildWithdrawTaskManifest(queen: Zerg): Task | null { - const tasks: Task[] = []; + private buildWithdrawTaskManifest(queen: Zerg): Task | null { + const tasks: Task[] = []; const transferTarget = this.colony.terminal || this.colony.storage || this.batteries[0]; // Step 1: empty all contents (this shouldn't be necessary since queen is normally empty at this point) if (_.sum(queen.carry) > 0) { diff --git a/src/tasks/Task.ts b/src/tasks/Task.ts index 17bf699f9..fe2564b94 100644 --- a/src/tasks/Task.ts +++ b/src/tasks/Task.ts @@ -17,7 +17,24 @@ import {profile} from '../profiler/decorator'; import {Zerg} from '../zerg/Zerg'; import {initializeTask} from './initializer'; -type targetType = { ref: string, pos: ProtoPos }; // overwrite this variable to specify more precise typing +interface AbstractTaskTarget { + ref: string; // Target id or name + _pos: ProtoPos; // Target position's coordinates in case vision is lost +} + +type ConcreteTaskTarget = HasRef | HasPos | RoomPosition; + +function isAbstractTarget(target: any): target is AbstractTaskTarget { + return target && target._pos !== undefined; +} + +function isRoomRefTarget(target: any): target is HasRef & HasPos { + return target && target.ref !== undefined; +} + +function isRoomObjectTarget(target: any): target is RoomObject { + return target && target.pos !== undefined; +} /** * An abstract class for encapsulating creep actions. This generalizes the concept of "do action X to thing Y until @@ -26,18 +43,15 @@ type targetType = { ref: string, pos: ProtoPos }; // overwrite this variable to * to continue. */ @profile -export abstract class Task { +export abstract class Task { static taskName: string; name: string; // Name of the task type, e.g. 'upgrade' - _creep: { // Data for the creep the task is assigned to" + _creep: { // Data for the creep the task is assigned to name: string; // Name of the creep }; - _target: { // Data for the target the task is directed to: - ref: string; // Target id or name - _pos: ProtoPos; // Target position's coordinates in case vision is lost - }; + _target: AbstractTaskTarget;// Data for the target the task is directed to: _parent: ProtoTask | null; // The parent of this task, if any. Task is changed to parent upon completion. tick: number; // When the task was set settings: TaskSettings; // Settings for a given type of task; shouldn't be modified on an instance-basis @@ -46,17 +60,33 @@ export abstract class Task { private _targetPos: RoomPosition; - constructor(taskName: string, target: targetType, options = {} as TaskOptions) { + constructor(taskName: string, target: TargetType | AbstractTaskTarget, options = {} as TaskOptions) { // Parameters for the task this.name = taskName; this._creep = { name: '', }; - if (target) { // Handles edge cases like when you're done building something and target disappears + // Handles edge cases like when you're done building something and target disappears + if (target instanceof RoomPosition) { + this._target = { + ref: '', + _pos: { x: target.x, y: target.y, roomName: target.room!.name }, + } + } else if (isAbstractTarget(target)) { + this._target = { + ref : target.ref, + _pos: target._pos, + }; + } else if (isRoomRefTarget(target)) { this._target = { ref : target.ref, _pos: target.pos, }; + } else if (isRoomObjectTarget(target)) { + this._target = { + ref: '', + _pos: target.pos, + } } else { this._target = { ref : '', @@ -67,6 +97,7 @@ export abstract class Task { } }; } + // log.debug(`creating task ${this.constructor.name}, ${taskName}, target: ${target}, ${print(this._target)}`); this._parent = null; this.settings = { targetRange: 1, // range at which you can perform action @@ -129,8 +160,8 @@ export abstract class Task { /** * Dereferences the Task's target */ - get target(): RoomObject | null { - return deref(this._target.ref); + get target(): TargetType { + return deref(this._target.ref) as TargetType; } /** @@ -140,7 +171,7 @@ export abstract class Task { // refresh if you have visibility of the target if (!this._targetPos) { if (this.target) { - this._target._pos = this.target.pos; + this._target._pos = (this.target as HasPos).pos; } this._targetPos = derefRoomPosition(this._target._pos); } @@ -150,14 +181,14 @@ export abstract class Task { /** * Get the Task's parent */ - get parent(): Task | null { + get parent(): Task | null { return (this._parent ? initializeTask(this._parent) : null); } /** * Set the Task's parent */ - set parent(parentTask: Task | null) { + set parent(parentTask: Task | null) { this._parent = parentTask ? parentTask.proto : null; // If the task is already assigned to a creep, update their memory if (this.creep) { @@ -168,8 +199,8 @@ export abstract class Task { /** * Return a list of [this, this.parent, this.parent.parent, ...] as tasks */ - get manifest(): Task[] { - const manifest: Task[] = [this]; + get manifest(): Task[] { + const manifest: Task[] = [this]; let parent = this.parent; while (parent) { manifest.push(parent); @@ -207,7 +238,7 @@ export abstract class Task { /** * Fork the task, assigning a new task to the creep with this task as its parent */ - fork(newTask: Task): Task { + fork(newTask: Task): Task { newTask.parent = this; if (this.creep) { this.creep.task = newTask; diff --git a/src/tasks/Tasks.ts b/src/tasks/Tasks.ts index d9469d594..3fd11620e 100644 --- a/src/tasks/Tasks.ts +++ b/src/tasks/Tasks.ts @@ -32,7 +32,7 @@ import {Task} from './Task'; @profile export class Tasks { - static chain(tasks: Task[], setNextPos = true): Task | null { + static chain(tasks: Task[], setNextPos = true): Task | null { if (tasks.length == 0) { // log.error(`Tasks.chain was passed an empty array of tasks!`); return null; @@ -118,7 +118,7 @@ export class Tasks { } static recharge(minEnergy = 0, options = {} as TaskOptions): TaskRecharge { - return new TaskRecharge(null, minEnergy, options); + return new TaskRecharge(minEnergy, options); } static repair(target: repairTargetType, options = {} as TaskOptions): TaskRepair { diff --git a/src/tasks/initializer.ts b/src/tasks/initializer.ts index 27df18904..fa87a44b1 100644 --- a/src/tasks/initializer.ts +++ b/src/tasks/initializer.ts @@ -33,7 +33,7 @@ import {Task} from './Task'; /** * The task initializer maps serialized prototasks to Task instances */ -export function initializeTask(protoTask: ProtoTask): Task { +export function initializeTask(protoTask: ProtoTask): Task { // Retrieve name and target data from the ProtoTask const taskName = protoTask.name; const target = deref(protoTask._target.ref); @@ -91,7 +91,7 @@ export function initializeTask(protoTask: ProtoTask): Task { task = new TaskRangedAttack(target as rangedAttackTargetType); break; case rechargeTaskName: - task = new TaskRecharge(null); + task = new TaskRecharge(); break; case repairTaskName: task = new TaskRepair(target as repairTargetType); diff --git a/src/tasks/instances/attack.ts b/src/tasks/instances/attack.ts index c5f11ea0f..57076cda7 100644 --- a/src/tasks/instances/attack.ts +++ b/src/tasks/instances/attack.ts @@ -13,11 +13,9 @@ export type attackTargetType = Creep | Structure; export const attackTaskName = 'attack'; @profile -export class TaskAttack extends Task { - target: attackTargetType; - +export class TaskAttack extends Task { constructor(target: attackTargetType, options = {} as TaskOptions) { - super(attackTaskName, target, options); + super(attackTaskName, { ref: target.ref, _pos: target.pos }, options); // Settings this.settings.targetRange = 3; } diff --git a/src/tasks/instances/build.ts b/src/tasks/instances/build.ts index 3155e6250..01393bcd0 100644 --- a/src/tasks/instances/build.ts +++ b/src/tasks/instances/build.ts @@ -5,9 +5,7 @@ export type buildTargetType = ConstructionSite; export const buildTaskName = 'build'; @profile -export class TaskBuild extends Task { - target: buildTargetType; - +export class TaskBuild extends Task { constructor(target: buildTargetType, options = {} as TaskOptions) { super(buildTaskName, target, options); // Settings diff --git a/src/tasks/instances/claim.ts b/src/tasks/instances/claim.ts index d131a82f1..0555fc367 100644 --- a/src/tasks/instances/claim.ts +++ b/src/tasks/instances/claim.ts @@ -5,9 +5,7 @@ export type claimTargetType = StructureController; export const claimTaskName = 'claim'; @profile -export class TaskClaim extends Task { - target: claimTargetType; - +export class TaskClaim extends Task { constructor(target: claimTargetType, options = {} as TaskOptions) { super(claimTaskName, target, options); // Settings diff --git a/src/tasks/instances/dismantle.ts b/src/tasks/instances/dismantle.ts index a78b5389d..48fd9ab14 100644 --- a/src/tasks/instances/dismantle.ts +++ b/src/tasks/instances/dismantle.ts @@ -6,8 +6,7 @@ export type dismantleTargetType = Structure; export const dismantleTaskName = 'dismantle'; @profile -export class TaskDismantle extends Task { - target: dismantleTargetType; +export class TaskDismantle extends Task { constructor(target: dismantleTargetType, options = {} as TaskOptions) { super(dismantleTaskName, target, options); diff --git a/src/tasks/instances/drop.ts b/src/tasks/instances/drop.ts index 1079e2d76..b615552a9 100644 --- a/src/tasks/instances/drop.ts +++ b/src/tasks/instances/drop.ts @@ -1,14 +1,13 @@ import {profile} from '../../profiler/decorator'; import {Task} from '../Task'; -export type dropTargetType = { pos: RoomPosition } | RoomPosition; +export type dropTargetType = HasRef & HasPos | RoomPosition; export const dropTaskName = 'drop'; @profile -export class TaskDrop extends Task { +export class TaskDrop extends Task { static taskName = 'drop'; - target: null; data: { resourceType: ResourceConstant amount: number | undefined @@ -19,9 +18,9 @@ export class TaskDrop extends Task { amount?: number, options = {} as TaskOptions) { if (target instanceof RoomPosition) { - super(TaskDrop.taskName, {ref: '', pos: target}, options); + super(TaskDrop.taskName, {ref: '', _pos: target}, options); } else { - super(TaskDrop.taskName, {ref: '', pos: target.pos}, options); + super(TaskDrop.taskName, {ref: target.ref, _pos: target.pos}, options); } // Settings this.settings.targetRange = 0; diff --git a/src/tasks/instances/fortify.ts b/src/tasks/instances/fortify.ts index 3d57919a8..0bba5390b 100644 --- a/src/tasks/instances/fortify.ts +++ b/src/tasks/instances/fortify.ts @@ -6,8 +6,7 @@ export type fortifyTargetType = StructureWall | StructureRampart; export const fortifyTaskName = 'fortify'; @profile -export class TaskFortify extends Task { - target: fortifyTargetType; +export class TaskFortify extends Task { data: { hitsMax: number | undefined; }; diff --git a/src/tasks/instances/generateSafeMode.ts b/src/tasks/instances/generateSafeMode.ts index 29ea7fb16..f28989ba8 100644 --- a/src/tasks/instances/generateSafeMode.ts +++ b/src/tasks/instances/generateSafeMode.ts @@ -5,9 +5,7 @@ export type generateSafeModeTargetType = StructureController; export const generateSafeModeTaskName = 'generateSafeMode'; @profile -export class TaskGenerateSafeMode extends Task { - target: generateSafeModeTargetType; - +export class TaskGenerateSafeMode extends Task { constructor(target: generateSafeModeTargetType, options = {} as TaskOptions) { super(generateSafeModeTaskName, target, options); } diff --git a/src/tasks/instances/getBoosted.ts b/src/tasks/instances/getBoosted.ts index 7fb6aa23f..a7f4e1d5f 100644 --- a/src/tasks/instances/getBoosted.ts +++ b/src/tasks/instances/getBoosted.ts @@ -9,10 +9,7 @@ export const getBoostedTaskName = 'getBoosted'; export const MIN_LIFETIME_FOR_BOOST = 0.85; @profile -export class TaskGetBoosted extends Task { - - target: getBoostedTargetType; - +export class TaskGetBoosted extends Task { data: { resourceType: ResourceConstant; amount: number | undefined; diff --git a/src/tasks/instances/getRenewed.ts b/src/tasks/instances/getRenewed.ts index 2479f8e8f..d773dde4b 100644 --- a/src/tasks/instances/getRenewed.ts +++ b/src/tasks/instances/getRenewed.ts @@ -5,9 +5,7 @@ export type getRenewedTargetType = StructureSpawn; export const getRenewedTaskName = 'getRenewed'; @profile -export class TaskGetRenewed extends Task { - target: getRenewedTargetType; - +export class TaskGetRenewed extends Task { constructor(target: getRenewedTargetType, options = {} as TaskOptions) { super(getRenewedTaskName, target, options); } diff --git a/src/tasks/instances/goTo.ts b/src/tasks/instances/goTo.ts index f6f9f02ff..9faeb5c73 100644 --- a/src/tasks/instances/goTo.ts +++ b/src/tasks/instances/goTo.ts @@ -2,13 +2,11 @@ import {hasPos} from '../../declarations/typeGuards'; import {profile} from '../../profiler/decorator'; import {Task} from '../Task'; -export type goToTargetType = { pos: RoomPosition } | RoomPosition; +export type goToTargetType = _HasRoomPosition | RoomPosition; export const goToTaskName = 'goTo'; @profile -export class TaskGoTo extends Task { - target: null; - +export class TaskGoTo extends Task { constructor(target: goToTargetType, options = {} as TaskOptions) { if (hasPos(target)) { super(goToTaskName, {ref: '', pos: target.pos}, options); diff --git a/src/tasks/instances/goToRoom.ts b/src/tasks/instances/goToRoom.ts index 55ac505d3..d320a249e 100644 --- a/src/tasks/instances/goToRoom.ts +++ b/src/tasks/instances/goToRoom.ts @@ -6,12 +6,10 @@ export type goToRoomTargetType = string; export const goToRoomTaskName = 'goToRoom'; @profile -export class TaskGoToRoom extends Task { - - target: null; +export class TaskGoToRoom extends Task { constructor(roomName: goToRoomTargetType, options = {} as TaskOptions) { - super(goToRoomTaskName, {ref: '', pos: new RoomPosition(25, 25, roomName)}, options); + super(goToRoomTaskName, {ref: '', _pos: new RoomPosition(25, 25, roomName)}, options); // Settings this.settings.targetRange = 23; // Target is almost always controller flag, so range of 2 is acceptable } diff --git a/src/tasks/instances/harvest.ts b/src/tasks/instances/harvest.ts index ca94de5af..ad25a732e 100644 --- a/src/tasks/instances/harvest.ts +++ b/src/tasks/instances/harvest.ts @@ -6,9 +6,7 @@ export type harvestTargetType = Source | Mineral; export const harvestTaskName = 'harvest'; @profile -export class TaskHarvest extends Task { - target: harvestTargetType; - +export class TaskHarvest extends Task { constructor(target: harvestTargetType, options = {} as TaskOptions) { super(harvestTaskName, target, options); } diff --git a/src/tasks/instances/heal.ts b/src/tasks/instances/heal.ts index feadd6659..c373f8bd9 100644 --- a/src/tasks/instances/heal.ts +++ b/src/tasks/instances/heal.ts @@ -5,16 +5,13 @@ export type healTargetType = Creep; export const healTaskName = 'heal'; @profile -export class TaskHeal extends Task { - target: healTargetType; - +export class TaskHeal extends Task { constructor(target: healTargetType, options = {} as TaskOptions) { super(healTaskName, target, options); // Settings this.settings.targetRange = 3; } - isValidTask() { return (this.creep.getActiveBodyparts(HEAL) > 0); } diff --git a/src/tasks/instances/invalid.ts b/src/tasks/instances/invalid.ts index 1dd58c901..c930a02d8 100644 --- a/src/tasks/instances/invalid.ts +++ b/src/tasks/instances/invalid.ts @@ -13,12 +13,10 @@ const invalidTarget = { }; @profile -export class TaskInvalid extends Task { - target: any; +export class TaskInvalid extends Task { constructor() { super('INVALID', invalidTarget); - } isValidTask() { diff --git a/src/tasks/instances/meleeAttack.ts b/src/tasks/instances/meleeAttack.ts index 0146d75da..88a58adce 100644 --- a/src/tasks/instances/meleeAttack.ts +++ b/src/tasks/instances/meleeAttack.ts @@ -5,9 +5,7 @@ export type meleeAttackTargetType = Creep | Structure; export const meleeAttackTaskName = 'meleeAttack'; @profile -export class TaskMeleeAttack extends Task { - target: meleeAttackTargetType; - +export class TaskMeleeAttack extends Task { constructor(target: meleeAttackTargetType, options = {} as TaskOptions) { super(meleeAttackTaskName, target, options); // Settings diff --git a/src/tasks/instances/pickup.ts b/src/tasks/instances/pickup.ts index 186922376..0a4723531 100644 --- a/src/tasks/instances/pickup.ts +++ b/src/tasks/instances/pickup.ts @@ -5,9 +5,7 @@ export type pickupTargetType = Resource; export const pickupTaskName = 'pickup'; @profile -export class TaskPickup extends Task { - target: pickupTargetType; - +export class TaskPickup extends Task { constructor(target: pickupTargetType, options = {} as TaskOptions) { super('pickup', target, options); this.settings.oneShot = true; diff --git a/src/tasks/instances/rangedAttack.ts b/src/tasks/instances/rangedAttack.ts index 25c4fac39..69b3cc1ec 100644 --- a/src/tasks/instances/rangedAttack.ts +++ b/src/tasks/instances/rangedAttack.ts @@ -5,9 +5,7 @@ export type rangedAttackTargetType = Creep | Structure; export const rangedAttackTaskName = 'rangedAttack'; @profile -export class TaskRangedAttack extends Task { - target: rangedAttackTargetType; - +export class TaskRangedAttack extends Task { constructor(target: rangedAttackTargetType, options = {} as TaskOptions) { super(rangedAttackTaskName, target, options); // Settings diff --git a/src/tasks/instances/recharge.ts b/src/tasks/instances/recharge.ts index 7b2dbaa54..6a298f16e 100644 --- a/src/tasks/instances/recharge.ts +++ b/src/tasks/instances/recharge.ts @@ -14,15 +14,13 @@ export const rechargeTaskName = 'recharge'; // This is a "dispenser task" which is not itself a valid task, but dispenses a task when assigned to a creep. @profile -export class TaskRecharge extends Task { - target: rechargeTargetType; - +export class TaskRecharge extends Task { data: { minEnergy: number; }; - constructor(target: rechargeTargetType, minEnergy = 0, options = {} as TaskOptions) { - super(rechargeTaskName, {ref: '', pos: {x: -1, y: -1, roomName: ''}}, options); + constructor(minEnergy = 0, options = {} as TaskOptions) { + super(rechargeTaskName, null, options); this.data.minEnergy = minEnergy; } diff --git a/src/tasks/instances/repair.ts b/src/tasks/instances/repair.ts index 7a04bb9ac..ea9ede838 100644 --- a/src/tasks/instances/repair.ts +++ b/src/tasks/instances/repair.ts @@ -5,9 +5,7 @@ export type repairTargetType = Structure; export const repairTaskName = 'repair'; @profile -export class TaskRepair extends Task { - target: repairTargetType; - +export class TaskRepair extends Task { constructor(target: repairTargetType, options = {} as TaskOptions) { super(repairTaskName, target, options); // Settings diff --git a/src/tasks/instances/reserve.ts b/src/tasks/instances/reserve.ts index 176016287..22c58e769 100644 --- a/src/tasks/instances/reserve.ts +++ b/src/tasks/instances/reserve.ts @@ -6,9 +6,7 @@ export type reserveTargetType = StructureController; export const reserveTaskName = 'colony'; @profile -export class TaskReserve extends Task { - target: reserveTargetType; - +export class TaskReserve extends Task { constructor(target: reserveTargetType, options = {} as TaskOptions) { super(reserveTaskName, target, options); } diff --git a/src/tasks/instances/signController.ts b/src/tasks/instances/signController.ts index f0f01af22..0d36a8dc9 100644 --- a/src/tasks/instances/signController.ts +++ b/src/tasks/instances/signController.ts @@ -5,9 +5,7 @@ export type signControllerTargetType = StructureController; export const signControllerTaskName = 'signController'; @profile -export class TaskSignController extends Task { - target: signControllerTargetType; - +export class TaskSignController extends Task { constructor(target: signControllerTargetType, options = {} as TaskOptions) { super(signControllerTaskName, target, options); } diff --git a/src/tasks/instances/transfer.ts b/src/tasks/instances/transfer.ts index 98cc77b87..950657e06 100644 --- a/src/tasks/instances/transfer.ts +++ b/src/tasks/instances/transfer.ts @@ -9,9 +9,7 @@ export type transferTargetType = export const transferTaskName = 'transfer'; @profile -export class TaskTransfer extends Task { - - target: transferTargetType; +export class TaskTransfer extends Task { data: { resourceType: ResourceConstant amount: number | undefined diff --git a/src/tasks/instances/transferAll.ts b/src/tasks/instances/transferAll.ts index 6d0d495c7..9b63718db 100644 --- a/src/tasks/instances/transferAll.ts +++ b/src/tasks/instances/transferAll.ts @@ -7,9 +7,7 @@ export type transferAllTargetType = StructureStorage | StructureTerminal | Struc export const transferAllTaskName = 'transferAll'; @profile -export class TaskTransferAll extends Task { - - target: transferAllTargetType; +export class TaskTransferAll extends Task { data: { skipEnergy?: boolean; }; diff --git a/src/tasks/instances/upgrade.ts b/src/tasks/instances/upgrade.ts index 166b6cdd6..ef5cb773f 100644 --- a/src/tasks/instances/upgrade.ts +++ b/src/tasks/instances/upgrade.ts @@ -6,9 +6,7 @@ export const upgradeTaskName = 'upgrade'; @profile -export class TaskUpgrade extends Task { - target: upgradeTargetType; - +export class TaskUpgrade extends Task { constructor(target: upgradeTargetType, options = {} as TaskOptions) { super(upgradeTaskName, target, options); // Settings diff --git a/src/tasks/instances/withdraw.ts b/src/tasks/instances/withdraw.ts index 26a2e5418..1617c0fcb 100644 --- a/src/tasks/instances/withdraw.ts +++ b/src/tasks/instances/withdraw.ts @@ -9,9 +9,7 @@ export type withdrawTargetType = AnyStoreStructure export const withdrawTaskName = 'withdraw'; @profile -export class TaskWithdraw extends Task { - - target: withdrawTargetType; +export class TaskWithdraw extends Task { data: { resourceType: ResourceConstant, amount: number | undefined, diff --git a/src/tasks/instances/withdrawAll.ts b/src/tasks/instances/withdrawAll.ts index 36b2acb09..f0459d5a4 100644 --- a/src/tasks/instances/withdrawAll.ts +++ b/src/tasks/instances/withdrawAll.ts @@ -8,10 +8,7 @@ export type withdrawAllTargetType = AnyStoreStructure; export const withdrawAllTaskName = 'withdrawAll'; @profile -export class TaskWithdrawAll extends Task { - - target: withdrawAllTargetType; - +export class TaskWithdrawAll extends Task { constructor(target: withdrawAllTargetType, options = {} as TaskOptions) { super(withdrawAllTaskName, target, options); } diff --git a/src/zerg/Zerg.ts b/src/zerg/Zerg.ts index 3a242bb01..bbb63cf6c 100644 --- a/src/zerg/Zerg.ts +++ b/src/zerg/Zerg.ts @@ -78,7 +78,7 @@ export class Zerg extends AnyZerg { blockMovement: boolean; // Whether the zerg is allowed to move or not // Cached properties - private _task: Task | null; + private _task: Task | null; private _neededBoosts: { [boostResource: string]: number } | undefined; constructor(creep: Creep, notifyWhenAttacked = true) { @@ -557,7 +557,7 @@ export class Zerg extends AnyZerg { /** * Wrapper for _task */ - get task(): Task | null { + get task(): Task | null { if (!this._task) { this._task = this.memory.task ? initializeTask(this.memory.task) : null; } @@ -567,7 +567,7 @@ export class Zerg extends AnyZerg { /** * Assign the creep a task with the setter, replacing creep.assign(Task) */ - set task(task: Task | null) { + set task(task: Task | null) { // Unregister target from old task if applicable const oldProtoTask = this.memory.task; if (oldProtoTask) { From 01851dc63330e3a1eb832365d1351a4732b2d956 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Fri, 4 Aug 2023 03:46:02 +0200 Subject: [PATCH 13/41] Fix a type inconsistency with the superclass --- src/hiveClusters/sporeCrawler.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/hiveClusters/sporeCrawler.ts b/src/hiveClusters/sporeCrawler.ts index 731abde72..20c629f8e 100644 --- a/src/hiveClusters/sporeCrawler.ts +++ b/src/hiveClusters/sporeCrawler.ts @@ -15,6 +15,7 @@ import {HiveCluster} from './_HiveCluster'; export class SporeCrawler extends HiveCluster { towers: StructureTower[]; + memory: undefined; static settings = { requestThreshold : 500, @@ -36,10 +37,6 @@ export class SporeCrawler extends HiveCluster { } - get memory(): undefined { - return undefined; - } - private registerEnergyRequests() { // Request energy from transporters if below request threshold for (const tower of this.towers) { From c2142b87b9be8977a9f85e15d3b9012e419a712b Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Fri, 4 Aug 2023 03:50:54 +0200 Subject: [PATCH 14/41] Use a variable instead of deleting a mandatory property --- src/movement/Movement.ts | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/movement/Movement.ts b/src/movement/Movement.ts index 1bd36306e..4b8fbb2da 100644 --- a/src/movement/Movement.ts +++ b/src/movement/Movement.ts @@ -238,6 +238,7 @@ export class Movement { } } + let shouldRepath = false; const state = this.deserializeState(moveData, destination); // // verify creep is in the location it thinks it should be in @@ -267,7 +268,7 @@ export class Movement { } if (state.stuckCount >= opts.stuckValue && Math.random() > .5) { pathOpts.blockCreeps = true; - delete moveData.path; + shouldRepath = true; } // delete path cache if destination is different @@ -276,14 +277,14 @@ export class Movement { moveData.path += state.destination.getDirectionTo(destination); state.destination = destination; } else { - delete moveData.path; + shouldRepath = true; } } // randomly repath with specified probability if (opts.repathChance && Math.random() < opts.repathChance) { - delete moveData.path; + shouldRepath = true; } // TODO: repath if you are not on expected next position @@ -291,7 +292,7 @@ export class Movement { // pathfinding let newPath = false; - if (!moveData.path || moveData.path.length == 0) { + if (shouldRepath || !moveData.path || moveData.path.length == 0) { newPath = true; if (isStandardZerg(creep) && creep.spawning) { return ERR_BUSY; @@ -827,6 +828,7 @@ export class Movement { return NO_ACTION; } + let shouldRepath = false; const state = this.deserializeState(moveData, destination); // check if swarm is stuck @@ -851,21 +853,21 @@ export class Movement { } if (state.stuckCount >= opts.stuckValue && Math.random() > .5) { opts.blockCreeps = true; - delete moveData.path; + shouldRepath = true; } // delete path cache if destination is different if (!destination.isEqualTo(state.destination)) { - delete moveData.path; + shouldRepath = true; } if (opts.repathChance && Math.random() < opts.repathChance) { // randomly repath with some probability - delete moveData.path; + shouldRepath = true; } // pathfinding let newPath = false; - if (!moveData.path) { + if (shouldRepath || !moveData.path) { newPath = true; state.destination = destination; const cpu = Game.cpu.getUsed(); @@ -1282,6 +1284,7 @@ export class Movement { moveData.fleeWait = 2; + let shouldRepath = false; // Invalidate path if needed if (moveData.path) { if (moveData.path.length > 0) { @@ -1290,16 +1293,16 @@ export class Movement { if (!pos.isEdge) { const newClosest = pos.findClosestByRange(avoidGoals); if (newClosest && normalizePos(newClosest).getRangeTo(pos) < rangeToClosest) { - delete moveData.path; + shouldRepath = true; } } } else { - delete moveData.path; + shouldRepath = true; } } // Re-calculate path if needed - if (!moveData.path || !moveData.destination) { + if (shouldRepath || !moveData.path || !moveData.destination) { const ret = Pathing.findFleePath(creep.pos, avoidGoals, opts.pathOpts || {}); if (ret.path.length == 0) { return NO_ACTION; From 61eaf71c39e20205887f280de0ee2848cd6f8494 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Fri, 4 Aug 2023 21:12:16 +0200 Subject: [PATCH 15/41] Strict type a few Colony properties --- src/Colony.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Colony.ts b/src/Colony.ts index 4b503ee91..145261068 100644 --- a/src/Colony.ts +++ b/src/Colony.ts @@ -167,8 +167,8 @@ export class Colony { // praiseSite: PraiseSite | undefined; // Operational state level: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8; // Level of the colony's main room - stage: number; // The stage of the colony "lifecycle" - defcon: number; // + stage: ColonyStage; // The stage of the colony "lifecycle" + defcon: DEFCON; // state: { bootstrapping?: boolean; // Whether colony is bootstrapping or recovering from crash isIncubating?: boolean; // If the colony is incubating From b561071a4802c8a9cc7a6a9c7f4fd517ea948b59 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 02:09:32 +0200 Subject: [PATCH 16/41] TS all the prototypes --- src/declarations/prototypes.d.ts | 35 +++++++++++++++-- src/directives/Directive.ts | 23 +++++------ src/prototypes/Creep.ts | 22 +++++------ src/prototypes/Game.ts | 2 +- src/prototypes/Miscellaneous.ts | 10 ++--- src/prototypes/PowerCreep.ts | 2 +- src/prototypes/Room.ts | 54 +++++++++++++------------- src/prototypes/RoomObject.ts | 6 +-- src/prototypes/RoomPosition.ts | 65 +++++++++++++++++--------------- src/prototypes/RoomStructures.ts | 50 +++++++++++++++--------- src/prototypes/RoomVisual.ts | 57 ++++++++++++++-------------- src/prototypes/Structures.ts | 2 +- 12 files changed, 184 insertions(+), 144 deletions(-) diff --git a/src/declarations/prototypes.d.ts b/src/declarations/prototypes.d.ts index b9dc5da62..6bf475b31 100644 --- a/src/declarations/prototypes.d.ts +++ b/src/declarations/prototypes.d.ts @@ -8,6 +8,12 @@ interface Creep { approxMoveSpeed: number; bodypartCounts: { [bodypart in BodyPartConstant]: number }; isHuman: true; + + // private + _boosts: ResourceConstant[]; + _boostCounts: { [boostType: string]: number }; + _inRampart: boolean; + _moveSpeed: number; } interface PowerCreep { @@ -131,6 +137,26 @@ interface Room { // _priorityMatrices: { [priority: number]: CostMatrix }; // _skMatrix: CostMatrix; _kitingMatrix: CostMatrix; + + // private caching + _creeps: Creep[]; + _hostiles: Creep[]; + _friendlies: Creep[]; + _invaders: Creep[]; + _sourceKeepers: Creep[]; + _dangerousHostiles: Creep[]; + _playerHostiles: Creep[]; + _dangerousPlayerHostiles: Creep[]; + _fleeDefaults: HasPos[]; + _allStructures: Structure[]; + _hostileStructures: Structure[]; + _flags: Flag[]; + _constructionSites: ConstructionSite[]; + _allConstructionSites: ConstructionSite[]; + _hostileConstructionSites: ConstructionSite[]; + _tombstones: Tombstone[]; + _ruins: Ruin[]; + _drops: { [resourceType: string]: Resource[] }; } interface RoomObject { @@ -166,8 +192,6 @@ interface RoomPosition { getOffsetPos(dx: number, dy: number): RoomPosition; - lookFor(structureType: T): Array; - lookForStructure(structureType: StructureConstant): Structure | undefined; isWalkable(ignoreCreeps?: boolean): boolean; @@ -178,8 +202,9 @@ interface RoomPosition { getMultiRoomRangeTo(pos: RoomPosition): number; - findClosestByLimitedRange(objects: T[] | RoomPosition[], rangeLimit: number, - opts?: { filter: any | string; }): T | undefined; + findClosestByLimitedRange(this: RoomPosition, + objects: T[], rangeLimit: number, + opts?: { filter: any | string; }): T | undefined; findClosestByMultiRoomRange(objects: T[]): T | undefined; @@ -187,6 +212,8 @@ interface RoomPosition { } interface RoomVisual { + roads: Point[]; + box(x: number, y: number, w: number, h: number, style?: LineStyle): RoomVisual; infoBox(info: string[], x: number, y: number, opts?: { [option: string]: any }): RoomVisual; diff --git a/src/directives/Directive.ts b/src/directives/Directive.ts index e10118cbb..80f3301a2 100644 --- a/src/directives/Directive.ts +++ b/src/directives/Directive.ts @@ -136,12 +136,10 @@ export abstract class Directive { for (const overlordName in this.overlords) { msg += tab + `${overlordName}:\n`; const olInfo: { [left: string]: string } = {}; - const overlord = this.overlords[overlordName] as any; + const overlord = this.overlords[overlordName]; olInfo[tab + tab + 'Creep usage:'] = JSON.stringify(overlord.creepUsageReport); - olInfo[tab + tab + 'Zerg:'] = _.mapValues(overlord._zerg, - zergOfRole => _.map(zergOfRole, (zerg: any) => zerg.print)); - olInfo[tab + tab + 'CombatZerg:'] = _.mapValues(overlord._combatZerg, - zergOfRole => _.map(zergOfRole, (zerg: any) => zerg.print)); + olInfo[tab + tab + 'Zerg:'] = overlord.getAllZerg().map(z => z.print).join(', '); + olInfo[tab + tab + 'CombatZerg:'] = overlord.getAllCombatZerg().map(z => z.print).join(', '); msg += toColumns(olInfo).join('\n'); } msg += 'Memory:\n' + print(this.memory); @@ -194,11 +192,10 @@ export abstract class Directive { const ret = Pathing.findPath(this.colony.pos, this.pos, {maxOps: DIRECTIVE_PATH_TIMEOUT}); const terrainCache: { [room: string]: RoomTerrain } = {}; const terrainWeighted = _.sum(ret.path, pos => { - let terrain: RoomTerrain; if (!terrainCache[pos.roomName]) { terrainCache[pos.roomName] = Game.map.getRoomTerrain(pos.roomName); } - terrain = terrainCache[pos.roomName]; + const terrain = terrainCache[pos.roomName]; return terrain.get(pos.x, pos.y) == TERRAIN_MASK_SWAMP ? 5 : 1; }); this.memory[MEM.DISTANCE] = { @@ -370,12 +367,12 @@ export abstract class Directive { return true; // usually we want to do something if directive isn't present; so this minimizes bad results } if (typeof posOrRoomName === 'string') { - const roomName = posOrRoomName as string; - const directivesInRoom = Overmind.overseer.getDirectivesInRoom(roomName) as Directive[]; + const roomName = posOrRoomName; + const directivesInRoom = Overmind.overseer.getDirectivesInRoom(roomName); return _.filter(directivesInRoom, directive => this.filter(directive.flag)).length > 0; } else { - const pos = posOrRoomName as RoomPosition; - const directivesInRoom = Overmind.overseer.getDirectivesInRoom(pos.roomName) as Directive[]; + const pos = posOrRoomName; + const directivesInRoom = Overmind.overseer.getDirectivesInRoom(pos.roomName); return _.filter(directivesInRoom, directive => this.filter(directive.flag) && equalXYR(pos, directive.pos)).length > 0; } @@ -456,7 +453,7 @@ export abstract class Directive { * Map a list of flags to directive using the filter of the subclassed directive */ static findInRoom(roomName: string): Directive[] { - const directivesInRoom = Overmind.overseer.getDirectivesInRoom(roomName) as Directive[]; + const directivesInRoom = Overmind.overseer.getDirectivesInRoom(roomName); return _.filter(directivesInRoom, directive => this.filter(directive.flag)); } @@ -464,7 +461,7 @@ export abstract class Directive { * Map a list of flags to directive using the filter of the subclassed directive */ static findInColony(colony: Colony): Directive[] { - const directivesInColony = Overmind.overseer.getDirectivesForColony(colony) as Directive[]; + const directivesInColony = Overmind.overseer.getDirectivesForColony(colony); return _.filter(directivesInColony, directive => this.filter(directive.flag)); } diff --git a/src/prototypes/Creep.ts b/src/prototypes/Creep.ts index 744e7f860..62f2e9e51 100644 --- a/src/prototypes/Creep.ts +++ b/src/prototypes/Creep.ts @@ -3,9 +3,9 @@ // Boosting logic ------------------------------------------------------------------------------------------------------ Object.defineProperty(Creep.prototype, 'boosts', { - get() { + get(this: Creep) { if (!this._boosts) { - this._boosts = _.compact(_.unique(_.map(this.body as BodyPartDefinition[], bodyPart => bodyPart.boost))); + this._boosts = _.compact(_.unique(_.map(this.body, bodyPart => bodyPart.boost))); } return this._boosts; }, @@ -13,9 +13,9 @@ Object.defineProperty(Creep.prototype, 'boosts', { }); Object.defineProperty(Creep.prototype, 'boostCounts', { - get() { + get(this: Creep) { if (!this._boostCounts) { - this._boostCounts = _.countBy(this.body as BodyPartDefinition[], bodyPart => bodyPart.boost); + this._boostCounts = _.countBy(this.body, bodyPart => bodyPart.boost); } return this._boostCounts; }, @@ -23,16 +23,16 @@ Object.defineProperty(Creep.prototype, 'boostCounts', { }); Object.defineProperty(Creep.prototype, 'approxMoveSpeed', { - get() { + get(this: Creep) { if (this._moveSpeed == undefined) { - const movePower = _.sum(this.body, (part: BodyPartDefinition) => { + const movePower = _.sum(this.body, (part) => { if (part.type == MOVE && part.boost) { - return BOOSTS.move[<'ZO' | 'ZHO2' | 'XZHO2'>part.boost].fatigue; + return BOOSTS.move[part.boost].fatigue; } else { return 0; } }); - const nonMoveParts = _.sum(this.body, (part: BodyPartDefinition) => part.type != MOVE ? 1 : 0); + const nonMoveParts = _.sum(this.body, (part) => part.type != MOVE ? 1 : 0); this._moveSpeed = Math.max(movePower / nonMoveParts, 1); // if nonMoveParts == 0, this will be Infinity -> 1 } return this._moveSpeed; @@ -41,7 +41,7 @@ Object.defineProperty(Creep.prototype, 'approxMoveSpeed', { }); Object.defineProperty(Creep.prototype, 'inRampart', { - get() { + get(this: Creep) { return !!this.pos.lookForStructure(STRUCTURE_RAMPART); // this assumes hostile creeps can't stand in my ramparts }, configurable: true, @@ -50,7 +50,7 @@ Object.defineProperty(Creep.prototype, 'inRampart', { // Permanently cached properties PERMACACHE.bodypartCounts = PERMACACHE.bodypartCounts || {}; Object.defineProperty(Creep.prototype, 'bodypartCounts', { - get() { + get(this: Creep) { if (PERMACACHE.bodypartCounts[this.id] === undefined) { PERMACACHE.bodypartCounts[this.id] = _.countBy(this.body, (part: BodyPartDefinition) => part.type); _.defaults(PERMACACHE.bodypartCounts[this.id], { @@ -71,7 +71,7 @@ Object.defineProperty(Creep.prototype, 'bodypartCounts', { PERMACACHE.isPlayer = PERMACACHE.isPlayer || {}; Object.defineProperty(Creep.prototype, 'isPlayer', { - get() { + get(this: Creep) { if (PERMACACHE.isPlayer[this.id] === undefined) { PERMACACHE.isPlayer[this.id] = this.owner.username != 'Invader' && this.owner.username != 'Source Keeper' && diff --git a/src/prototypes/Game.ts b/src/prototypes/Game.ts index 6f78ba175..14348b674 100644 --- a/src/prototypes/Game.ts +++ b/src/prototypes/Game.ts @@ -1,7 +1,7 @@ // Modifications to Game-level functions const _marketDeal = Game.market.deal; -Game.market.deal = function(orderId: string, amount: number, targetRoomName?: string): ScreepsReturnCode { +Game.market.deal = function(this: Market, orderId: string, amount: number, targetRoomName?: string): ScreepsReturnCode { const response = _marketDeal(orderId, amount, targetRoomName); if (response == OK) { if (targetRoomName && Game.rooms[targetRoomName] && Game.rooms[targetRoomName].terminal diff --git a/src/prototypes/Miscellaneous.ts b/src/prototypes/Miscellaneous.ts index a797dc742..bc6f968e7 100644 --- a/src/prototypes/Miscellaneous.ts +++ b/src/prototypes/Miscellaneous.ts @@ -1,16 +1,16 @@ -String.prototype.padRight = function(length: number, char = ' '): string { +String.prototype.padRight = function(this: string, length: number, char = ' '): string { return this + char.repeat(Math.max(length - this.length, 0)); }; -String.prototype.padLeft = function(length: number, char = ' '): string { +String.prototype.padLeft = function(this: string, length: number, char = ' '): string { return char.repeat(Math.max(length - this.length, 0)) + this; }; -Number.prototype.toPercent = function(decimals = 0): string { +Number.prototype.toPercent = function(this: number, decimals = 0): string { return (this * 100).toFixed(decimals) + '%'; }; -Number.prototype.truncate = function(decimals: number): number { +Number.prototype.truncate = function(this: number, decimals: number): number { const re = new RegExp('(\\d+\\.\\d{' + decimals + '})(\\d)'), m = this.toString().match(re); return m ? parseFloat(m[1]) : this.valueOf(); @@ -18,7 +18,7 @@ Number.prototype.truncate = function(decimals: number): number { PERMACACHE.structureWalkability = PERMACACHE.structureWalkability || {}; Object.defineProperty(ConstructionSite.prototype, 'isWalkable', { - get() { + get(this: ConstructionSite) { if (PERMACACHE.structureWalkability[this.id] === undefined) { PERMACACHE.structureWalkability[this.id] = this.structureType == STRUCTURE_ROAD || this.structureType == STRUCTURE_CONTAINER || diff --git a/src/prototypes/PowerCreep.ts b/src/prototypes/PowerCreep.ts index 51419cdff..68def4cd5 100644 --- a/src/prototypes/PowerCreep.ts +++ b/src/prototypes/PowerCreep.ts @@ -1,5 +1,5 @@ Object.defineProperty(PowerCreep.prototype, 'inRampart', { - get() { + get(this: PowerCreep) { return !!this.pos.lookForStructure(STRUCTURE_RAMPART); // this assumes hostile creeps can't stand in my ramparts }, configurable: true, diff --git a/src/prototypes/Room.ts b/src/prototypes/Room.ts index 8c4342a40..5938ea2a8 100644 --- a/src/prototypes/Room.ts +++ b/src/prototypes/Room.ts @@ -5,7 +5,7 @@ import {MY_USERNAME} from '../~settings'; // Logging ============================================================================================================= Object.defineProperty(Room.prototype, 'print', { - get() { + get(this: Room) { return '' + this.name + ''; }, configurable: true, @@ -14,14 +14,14 @@ Object.defineProperty(Room.prototype, 'print', { // Room properties ===================================================================================================== Object.defineProperty(Room.prototype, 'my', { - get() { + get(this: Room) { return this.controller && this.controller.my; }, configurable: true, }); Object.defineProperty(Room.prototype, 'isColony', { - get() { + get(this: Room) { return Overmind.colonies[this.name] != undefined; }, configurable: true, @@ -29,28 +29,28 @@ Object.defineProperty(Room.prototype, 'isColony', { Object.defineProperty(Room.prototype, 'isOutpost', { - get() { + get(this: Room) { return Overmind.colonyMap[this.name] != undefined; }, configurable: true, }); Object.defineProperty(Room.prototype, 'owner', { - get() { + get(this: Room) { return this.controller && this.controller.owner ? this.controller.owner.username : undefined; }, configurable: true, }); Object.defineProperty(Room.prototype, 'reservedByMe', { - get() { + get(this: Room) { return this.controller && this.controller.reservation && this.controller.reservation.username == MY_USERNAME; }, configurable: true, }); Object.defineProperty(Room.prototype, 'signedByMe', { - get() { + get(this: Room) { return this.controller && this.controller.sign && this.controller.sign.text == Memory.settings.signature; }, configurable: true, @@ -60,7 +60,7 @@ Object.defineProperty(Room.prototype, 'signedByMe', { // Creeps physically in the room Object.defineProperty(Room.prototype, 'creeps', { - get() { + get(this: Room) { if (!this._creeps) { this._creeps = this.find(FIND_MY_CREEPS); } @@ -72,7 +72,7 @@ Object.defineProperty(Room.prototype, 'creeps', { // Room properties: hostiles =========================================================================================== Object.defineProperty(Room.prototype, 'hostiles', { - get() { + get(this: Room) { if (!this._hostiles) { this._hostiles = this.find(FIND_HOSTILE_CREEPS, {filter: (creep: Creep) => !isAlly(creep.owner.username)}); } @@ -82,7 +82,7 @@ Object.defineProperty(Room.prototype, 'hostiles', { }); Object.defineProperty(Room.prototype, 'friendlies', { - get() { + get(this: Room) { if (!this._friendlies) { this._friendlies = this.find(FIND_HOSTILE_CREEPS, {filter: (creep: Creep) => isAlly(creep.owner.username)}); } @@ -92,7 +92,7 @@ Object.defineProperty(Room.prototype, 'friendlies', { }); Object.defineProperty(Room.prototype, 'invaders', { - get() { + get(this: Room) { if (!this._invaders) { this._invaders = _.filter(this.hostiles, (creep: Creep) => creep.owner.username == 'Invader'); } @@ -102,7 +102,7 @@ Object.defineProperty(Room.prototype, 'invaders', { }); Object.defineProperty(Room.prototype, 'sourceKeepers', { - get() { + get(this: Room) { if (!this._sourceKeepers) { this._sourceKeepers = _.filter(this.hostiles, (creep: Creep) => creep.owner.username == 'Source Keeper'); } @@ -112,7 +112,7 @@ Object.defineProperty(Room.prototype, 'sourceKeepers', { }); Object.defineProperty(Room.prototype, 'playerHostiles', { - get() { + get(this: Room) { if (!this._playerHostiles) { this._playerHostiles = _.filter(this.hostiles, (creep: Creep) => creep.isHuman); } @@ -122,7 +122,7 @@ Object.defineProperty(Room.prototype, 'playerHostiles', { }); Object.defineProperty(Room.prototype, 'dangerousHostiles', { - get() { + get(this: Room) { if (!this._dangerousHostiles) { if (this.my) { this._dangerousHostiles = _.filter(this.hostiles, @@ -141,7 +141,7 @@ Object.defineProperty(Room.prototype, 'dangerousHostiles', { }); Object.defineProperty(Room.prototype, 'dangerousPlayerHostiles', { - get() { + get(this: Room) { if (!this._dangerousPlayerHostiles) { if (this.my) { this._dangerousPlayerHostiles = _.filter(this.playerHostiles, @@ -160,7 +160,7 @@ Object.defineProperty(Room.prototype, 'dangerousPlayerHostiles', { }); Object.defineProperty(Room.prototype, 'fleeDefaults', { - get() { + get(this: Room) { if (!this._fleeDefaults) { this._fleeDefaults = [ ...this.dangerousHostiles, @@ -174,7 +174,7 @@ Object.defineProperty(Room.prototype, 'fleeDefaults', { // Hostile structures currently in the room Object.defineProperty(Room.prototype, 'structures', { - get() { + get(this: Room) { if (!this._allStructures) { this._allStructures = this.find(FIND_STRUCTURES); } @@ -186,7 +186,7 @@ Object.defineProperty(Room.prototype, 'structures', { // Hostile structures currently in the room Object.defineProperty(Room.prototype, 'hostileStructures', { - get() { + get(this: Room) { if (!this._hostileStructures) { this._hostileStructures = this.find(FIND_HOSTILE_STRUCTURES, { filter: (s: Structure) => (s.hitsMax) && !isAlly(_.get(s, ['owner', 'username'])) @@ -201,7 +201,7 @@ Object.defineProperty(Room.prototype, 'hostileStructures', { // Flags physically in this room Object.defineProperty(Room.prototype, 'flags', { - get() { + get(this: Room) { if (!this._flags) { this._flags = this.find(FIND_FLAGS); } @@ -213,7 +213,7 @@ Object.defineProperty(Room.prototype, 'flags', { // Room properties: structures ========================================================================================= Object.defineProperty(Room.prototype, 'constructionSites', { - get() { + get(this: Room) { if (!this._constructionSites) { this._constructionSites = this.find(FIND_MY_CONSTRUCTION_SITES); } @@ -223,7 +223,7 @@ Object.defineProperty(Room.prototype, 'constructionSites', { }); Object.defineProperty(Room.prototype, 'allConstructionSites', { - get() { + get(this: Room) { if (!this._allConstructionSites) { this._allConstructionSites = this.find(FIND_CONSTRUCTION_SITES); } @@ -233,7 +233,7 @@ Object.defineProperty(Room.prototype, 'allConstructionSites', { }); Object.defineProperty(Room.prototype, 'hostileConstructionSites', { - get() { + get(this: Room) { if (!this._hostileConstructionSites) { this._hostileConstructionSites = this.find(FIND_HOSTILE_CONSTRUCTION_SITES); } @@ -243,7 +243,7 @@ Object.defineProperty(Room.prototype, 'hostileConstructionSites', { }); Object.defineProperty(Room.prototype, 'tombstones', { - get() { + get(this: Room) { if (!this._tombstones) { this._tombstones = this.find(FIND_TOMBSTONES); } @@ -253,7 +253,7 @@ Object.defineProperty(Room.prototype, 'tombstones', { }); Object.defineProperty(Room.prototype, 'ruins', { - get() { + get(this: Room) { if (!this._ruins) { this._ruins = this.find(FIND_RUINS); } @@ -263,7 +263,7 @@ Object.defineProperty(Room.prototype, 'ruins', { }); Object.defineProperty(Room.prototype, 'drops', { - get() { + get(this: Room) { if (!this._drops) { this._drops = _.groupBy(this.find(FIND_DROPPED_RESOURCES), (r: Resource) => r.resourceType); } @@ -273,14 +273,14 @@ Object.defineProperty(Room.prototype, 'drops', { }); Object.defineProperty(Room.prototype, 'droppedEnergy', { - get() { + get(this: Room) { return this.drops[RESOURCE_ENERGY] || []; }, configurable: true, }); Object.defineProperty(Room.prototype, 'droppedPower', { - get() { + get(this: Room) { return this.drops[RESOURCE_POWER] || []; }, configurable: true, diff --git a/src/prototypes/RoomObject.ts b/src/prototypes/RoomObject.ts index b63375f81..51639d48b 100644 --- a/src/prototypes/RoomObject.ts +++ b/src/prototypes/RoomObject.ts @@ -1,20 +1,20 @@ // RoomObject prototypes Object.defineProperty(RoomObject.prototype, 'ref', { // reference object; see globals.deref (which includes Creep) - get : function() { + get: function(this: _HasId & { name:string }) { return this.id || this.name || ''; }, configurable: true, }); Object.defineProperty(RoomObject.prototype, 'targetedBy', { // List of creep names with tasks targeting this object - get : function() { + get: function(this: RoomObject) { return Overmind.cache.targets[this.ref] || []; }, configurable: true, }); -RoomObject.prototype.serialize = function(): ProtoRoomObject { +RoomObject.prototype.serialize = function(this: RoomObject): ProtoRoomObject { const pos: ProtoPos = { x : this.pos.x, y : this.pos.y, diff --git a/src/prototypes/RoomPosition.ts b/src/prototypes/RoomPosition.ts index 0ef0b24ee..b57c93b59 100644 --- a/src/prototypes/RoomPosition.ts +++ b/src/prototypes/RoomPosition.ts @@ -2,7 +2,7 @@ import {Cartographer} from '../utilities/Cartographer'; import {minBy, mod} from '../utilities/utils'; Object.defineProperty(RoomPosition.prototype, 'print', { - get() { + get(this: RoomPosition) { return '[' + this.roomName + ', ' + this.x + ', ' + this.y + ']'; }, @@ -10,25 +10,25 @@ Object.defineProperty(RoomPosition.prototype, 'print', { }); Object.defineProperty(RoomPosition.prototype, 'printPlain', { - get() { + get(this: RoomPosition) { return `[${this.roomName}, ${this.x}, ${this.y}]`; }, configurable: true, }); Object.defineProperty(RoomPosition.prototype, 'room', { - get : function() { + get(this: RoomPosition) { return Game.rooms[this.roomName]; }, configurable: true, }); -RoomPosition.prototype.toCoord = function(): Coord { +RoomPosition.prototype.toCoord = function(this: RoomPosition): Coord { return {x: this.x, y: this.y}; }; Object.defineProperty(RoomPosition.prototype, 'readableName', { // identifier for the pos, used in caching - get : function() { + get: function(this: RoomPosition) { return this.roomName + ':' + this.x + ':' + this.y; }, configurable: true, @@ -41,11 +41,11 @@ Object.defineProperty(RoomPosition.prototype, 'readableName', { // identifier fo // configurable: true, // }); -RoomPosition.prototype.lookForStructure = function(structureType: StructureConstant): Structure | undefined { +RoomPosition.prototype.lookForStructure = function(this: RoomPosition, structureType: StructureConstant): Structure | undefined { return _.find(this.lookFor(LOOK_STRUCTURES), s => s.structureType === structureType); }; -RoomPosition.prototype.getOffsetPos = function(dx: number, dy: number): RoomPosition { +RoomPosition.prototype.getOffsetPos = function(this: RoomPosition, dx: number, dy: number): RoomPosition { let roomName = this.roomName; let x = this.x + dx; if (x < 0 || x > 49) { @@ -67,28 +67,28 @@ RoomPosition.prototype.getOffsetPos = function(dx: number, dy: number): RoomPosi // } Object.defineProperty(RoomPosition.prototype, 'isEdge', { // if the position is at the edge of a room - get : function() { + get: function(this: RoomPosition) { return this.x === 0 || this.x === 49 || this.y === 0 || this.y === 49; }, configurable: true, }); Object.defineProperty(RoomPosition.prototype, 'isVisible', { // if the position is in a defined room - get : function() { + get: function(this: RoomPosition) { return Game.rooms[this.roomName] != undefined; }, configurable: true, }); Object.defineProperty(RoomPosition.prototype, 'rangeToEdge', { // range to the nearest room edge - get : function() { + get: function(this: RoomPosition) { return _.min([this.x, 49 - this.x, this.y, 49 - this.y]); }, configurable: true, }); Object.defineProperty(RoomPosition.prototype, 'roomCoords', { - get : function() { + get: function(this: RoomPosition) { const parsed = /^[WE]([0-9]+)[NS]([0-9]+)$/.exec(this.roomName); let x = parseInt(parsed![1], 10); let y = parseInt(parsed![2], 10); @@ -100,7 +100,7 @@ Object.defineProperty(RoomPosition.prototype, 'roomCoords', { }); Object.defineProperty(RoomPosition.prototype, 'neighbors', { - get : function() { + get: function(this: RoomPosition) { const adjPos: RoomPosition[] = []; for (const dx of [-1, 0, 1]) { for (const dy of [-1, 0, 1]) { @@ -118,23 +118,24 @@ Object.defineProperty(RoomPosition.prototype, 'neighbors', { configurable: true, }); -RoomPosition.prototype.inRangeToPos = function(pos: RoomPosition, range: number): boolean { +RoomPosition.prototype.inRangeToPos = function(this: RoomPosition, pos: RoomPosition, range: number): boolean { return this.roomName === pos.roomName && ((pos.x - this.x) < 0 ? (this.x - pos.x) : (pos.x - this.x)) <= range && ((pos.y - this.y) < 0 ? (this.y - pos.y) : (pos.y - this.y)) <= range; }; -RoomPosition.prototype.inRangeToXY = function(x: number, y: number, range: number) { +RoomPosition.prototype.inRangeToXY = function(this: RoomPosition, x: number, y: number, range: number) { return ((x - this.x) < 0 ? (this.x - x) : (x - this.x)) <= range && ((y - this.y) < 0 ? (this.y - y) : (y - this.y)) <= range; }; -RoomPosition.prototype.getRangeToXY = function(x: number, y: number) { +RoomPosition.prototype.getRangeToXY = function(this: RoomPosition, x: number, y: number) { return Math.max((x - this.x) < 0 ? (this.x - x) : (x - this.x), ((y - this.y) < 0 ? (this.y - y) : (y - this.y))); }; -RoomPosition.prototype.getPositionsInRange = function(range: number, - includeWalls = false, includeEdges = false): RoomPosition[] { +RoomPosition.prototype.getPositionsInRange = function(this: RoomPosition, + range: number, + includeWalls = false, includeEdges = false): RoomPosition[] { const terrain = Game.map.getRoomTerrain(this.roomName); const adjPos: RoomPosition[] = []; @@ -154,8 +155,9 @@ RoomPosition.prototype.getPositionsInRange = function(range: number, return adjPos; }; -RoomPosition.prototype.getPositionsAtRange = function(range: number, - includeWalls = false, includeEdges = false): RoomPosition[] { +RoomPosition.prototype.getPositionsAtRange = function(this: RoomPosition, + range: number, + includeWalls = false, includeEdges = false): RoomPosition[] { const terrain = Game.map.getRoomTerrain(this.roomName); const adjPos: RoomPosition[] = []; const [xmin, xmax] = includeEdges ? [0, 49] : [1, 48]; @@ -177,7 +179,7 @@ RoomPosition.prototype.getPositionsAtRange = function(range: number, return adjPos; }; -RoomPosition.prototype.isWalkable = function(ignoreCreeps = false): boolean { +RoomPosition.prototype.isWalkable = function(this: RoomPosition, ignoreCreeps = false): boolean { // Is terrain passable? if (Game.map.getRoomTerrain(this.roomName).get(this.x, this.y) == TERRAIN_MASK_WALL) return false; if (this.isVisible) { @@ -189,11 +191,11 @@ RoomPosition.prototype.isWalkable = function(ignoreCreeps = false): boolean { return true; }; -RoomPosition.prototype.availableNeighbors = function(ignoreCreeps = false): RoomPosition[] { +RoomPosition.prototype.availableNeighbors = function(this: RoomPosition, ignoreCreeps = false): RoomPosition[] { return _.filter(this.neighbors, pos => pos.isWalkable(ignoreCreeps)); }; -RoomPosition.prototype.getPositionAtDirection = function(direction: DirectionConstant, range = 1): RoomPosition { +RoomPosition.prototype.getPositionAtDirection = function(this: RoomPosition, direction: DirectionConstant, range = 1): RoomPosition { let dx = 0; let dy = 0; switch (direction) { @@ -249,7 +251,7 @@ RoomPosition.prototype.getPositionAtDirection = function(direction: DirectionCon // }); // Get an estimate for the distance to another room position in a possibly different room -RoomPosition.prototype.getMultiRoomRangeTo = function(pos: RoomPosition): number { +RoomPosition.prototype.getMultiRoomRangeTo = function(this: RoomPosition, pos: RoomPosition): number { if (this.roomName == pos.roomName) { return this.getRangeTo(pos); } else { @@ -261,26 +263,27 @@ RoomPosition.prototype.getMultiRoomRangeTo = function(pos: RoomPosition): number } }; -RoomPosition.prototype.findClosestByLimitedRange = function (objects: T[] | RoomPosition[], rangeLimit: number, - opts?: { filter: any | string; }): T | undefined { - const objectsInRange = this.findInRange(objects, rangeLimit, opts); - return this.findClosestByRange(objectsInRange, opts); +RoomPosition.prototype.findClosestByLimitedRange = function (this: RoomPosition, + objects: T[], rangeLimit: number, + opts?: { filter: any | string; }): T | undefined { + const objectsInRange = this.findInRange(objects, rangeLimit, opts); + return this.findClosestByRange(objectsInRange, opts) || undefined; }; -RoomPosition.prototype.findClosestByMultiRoomRange = function (objects: T[]): +RoomPosition.prototype.findClosestByMultiRoomRange = function (this: RoomPosition, objects: T[]): T | undefined { return minBy(objects, (obj: T) => this.getMultiRoomRangeTo(obj.pos)); }; // This should only be used within a single room -RoomPosition.prototype.findClosestByRangeThenPath = function (objects: T[]): T { +RoomPosition.prototype.findClosestByRangeThenPath = function (this: RoomPosition, objects: T[]): T | undefined { const distances = _.map(objects, obj => this.getRangeTo(obj)); const minDistance = _.min(distances); if (minDistance > 4) { - return this.findClosestByRange(objects); + return this.findClosestByRange(objects) || undefined; } else { const closestObjects = _.filter(objects, obj => this.getRangeTo(obj) == minDistance); - return this.findClosestByPath(closestObjects); // don't clutter up pathing.distance cached values + return this.findClosestByPath(closestObjects) || undefined; // don't clutter up pathing.distance cached values } }; diff --git a/src/prototypes/RoomStructures.ts b/src/prototypes/RoomStructures.ts index 647783c3e..8ea577cb7 100644 --- a/src/prototypes/RoomStructures.ts +++ b/src/prototypes/RoomStructures.ts @@ -3,6 +3,18 @@ import {getCacheExpiration, onPublicServer} from '../utilities/utils'; +declare global { + interface Room { + _storageUnits: StorageUnit[]; + _sources: Source[]; + _mineral: Mineral | undefined; + _repairables: (Structure | null)[]; + _rechargeables: rechargeObjectType[]; + _walkableRamparts: (StructureRampart | null)[]; + _barriers: (StructureWall | StructureRampart)[] | undefined; + } +} + const roomStructureIDs: { [roomName: string]: { [structureType: string]: string[] } } = {}; const roomStructuresExpiration: { [roomName: string]: number } = {}; @@ -36,7 +48,7 @@ Room.prototype._refreshStructureCache = function() { multipleList.forEach(function(type) { Object.defineProperty(Room.prototype, type + 's', { - get : function() { + get: function() { if (this['_' + type + 's']) { return this['_' + type + 's']; } else { @@ -55,7 +67,7 @@ multipleList.forEach(function(type) { singleList.forEach(function(type) { Object.defineProperty(Room.prototype, type, { - get : function() { + get: function() { if (this['_' + type]) { return this['_' + type]; } else { @@ -73,9 +85,10 @@ singleList.forEach(function(type) { Object.defineProperty(Room.prototype, 'storageUnits', { - get() { + get(this: Room) { if (!this._storageUnits) { - this._storageUnits = _.compact([this.storage, this.terminal]).concat(this.containers); + const special: (StorageUnit | undefined)[] = [this.storage, this.terminal]; + this._storageUnits = _.compact(special).concat(this.containers); } return this._storageUnits; }, @@ -83,7 +96,7 @@ Object.defineProperty(Room.prototype, 'storageUnits', { }); Object.defineProperty(Room.prototype, 'sources', { - get() { + get(this: Room) { if (!this._sources) { this._sources = this.find(FIND_SOURCES); } @@ -93,7 +106,7 @@ Object.defineProperty(Room.prototype, 'sources', { }); Object.defineProperty(Room.prototype, 'mineral', { - get() { + get(this: Room) { if (!this._mineral) { this._mineral = this.find(FIND_MINERALS)[0]; } @@ -103,25 +116,26 @@ Object.defineProperty(Room.prototype, 'mineral', { }); Object.defineProperty(Room.prototype, 'repairables', { - get() { + get(this: Room) { if (!this._repairables) { this._refreshStructureCache(); if (roomStructureIDs[this.name].repairables) { return this._repairables = _.compact(_.map(roomStructureIDs[this.name].repairables, - Game.getObjectById)); + o => Game.getObjectById(o))); } else { let repairables: Structure[] = []; for (const structureType of singleList) { - if (this[structureType]) { - repairables.push(this[structureType]); - } + const o = this[structureType]; + if (!o) continue; + repairables.push(o); } for (const structureType of multipleList) { if (structureType != STRUCTURE_WALL && structureType != STRUCTURE_RAMPART && structureType != STRUCTURE_ROAD && !notRepairable.includes(structureType)) { - repairables = repairables.concat(this[structureType + 's']); + const obj = <{[p: string]: Structure[]}>this; + repairables = repairables.concat(obj[structureType + 's']); } } roomStructureIDs[this.name].repairables = _.map(repairables, s => s.id); @@ -136,12 +150,12 @@ Object.defineProperty(Room.prototype, 'repairables', { // TODO: this is expensive and easy to over-use. Perhaps remove this. Object.defineProperty(Room.prototype, 'walkableRamparts', { - get() { + get(this: Room) { if (!this._walkableRamparts) { this._refreshStructureCache(); if (roomStructureIDs[this.name].walkableRamparts) { return this._walkableRamparts = _.compact(_.map(roomStructureIDs[this.name].walkableRamparts, - Game.getObjectById)); + (o) => Game.getObjectById(o))); } else { const walkableRamparts = _.filter(this.ramparts, (r: StructureRampart) => r.pos.isWalkable(true)); @@ -155,7 +169,7 @@ Object.defineProperty(Room.prototype, 'walkableRamparts', { }); Object.defineProperty(Room.prototype, 'rechargeables', { - get() { + get(this: Room) { if (!this._rechargeables) { this._rechargeables = [...this.storageUnits, ...this.droppedEnergy, @@ -168,9 +182,9 @@ Object.defineProperty(Room.prototype, 'rechargeables', { }); Object.defineProperty(Room.prototype, 'barriers', { - get() { + get(this: Room) { if (!this._barriers) { - this._barriers = [].concat(this.ramparts, this.constructedWalls); + this._barriers = (<(StructureRampart | StructureWall)[]>[]).concat(this.ramparts, this.constructedWalls); } return this._barriers; }, @@ -178,7 +192,7 @@ Object.defineProperty(Room.prototype, 'barriers', { }); Object.defineProperty(Room.prototype, 'walls', { - get() { + get(this: Room) { return this.constructedWalls; }, configurable: true, diff --git a/src/prototypes/RoomVisual.ts b/src/prototypes/RoomVisual.ts index 54748090d..e21226aca 100644 --- a/src/prototypes/RoomVisual.ts +++ b/src/prototypes/RoomVisual.ts @@ -1,4 +1,7 @@ -RoomVisual.prototype.infoBox = function(info: string[], x: number, y: number, opts = {}): RoomVisual { +type Point = [number, number]; +type Points = Point[] | RoomPosition[]; + +RoomVisual.prototype.infoBox = function(this: RoomVisual, info: string[], x: number, y: number, opts = {}): RoomVisual { _.defaults(opts, { color : colors.infoBoxGood, textstyle: false, @@ -13,7 +16,7 @@ RoomVisual.prototype.infoBox = function(info: string[], x: number, y: number, op } fontstring += opts.textsize + ' ' + opts.textfont; - let pointer = [ + let pointer: Points = [ [.9, -0.25], [.9, 0.25], [0.3, 0.0], @@ -61,7 +64,7 @@ RoomVisual.prototype.infoBox = function(info: string[], x: number, y: number, op return this; }; -RoomVisual.prototype.multitext = function(textLines: string[], x: number, y: number, opts = {}): RoomVisual { +RoomVisual.prototype.multitext = function(this: RoomVisual, textLines: string[], x: number, y: number, opts = {}): RoomVisual { _.defaults(opts, { color : colors.infoBoxGood, textstyle: false, @@ -100,7 +103,7 @@ RoomVisual.prototype.multitext = function(textLines: string[], x: number, y: num return this; }; -RoomVisual.prototype.box = function(x: number, y: number, w: number, h: number, style?: LineStyle): RoomVisual { +RoomVisual.prototype.box = function(this: RoomVisual, x: number, y: number, w: number, h: number, style?: LineStyle): RoomVisual { return this.line(x, y, x + w, y, style) .line(x + w, y, x + w, y + h, style) .line(x + w, y + h, x, y + h, style) @@ -127,7 +130,7 @@ const colors = { const speechSize = 0.5; const speechFont = 'Times New Roman'; -RoomVisual.prototype.structure = function(x: number, y: number, type: string, opts = {}): RoomVisual { +RoomVisual.prototype.structure = function(this: RoomVisual, x: number, y: number, type: string, opts = {}): RoomVisual { _.defaults(opts, {opacity: 0.5}); switch (type) { case STRUCTURE_EXTENSION: @@ -176,13 +179,13 @@ RoomVisual.prototype.structure = function(x: number, y: number, type: string, op case STRUCTURE_LINK: { // let osize = 0.3; // let isize = 0.2; - let outer = [ + let outer: Points = [ [0.0, -0.5], [0.4, 0.0], [0.0, 0.5], [-0.4, 0.0] ]; - let inner = [ + let inner: Points = [ [0.0, -0.3], [0.25, 0.0], [0.0, 0.3], @@ -200,13 +203,12 @@ RoomVisual.prototype.structure = function(x: number, y: number, type: string, op }); this.poly(inner, { fill : colors.gray, - stroke : false, opacity: opts.opacity }); break; } case STRUCTURE_TERMINAL: { - let outer = [ + let outer: Points = [ [0.0, -0.8], [0.55, -0.55], [0.8, 0.0], @@ -216,7 +218,7 @@ RoomVisual.prototype.structure = function(x: number, y: number, type: string, op [-0.8, 0.0], [-0.55, -0.55], ]; - let inner = [ + let inner: Points = [ [0.0, -0.65], [0.45, -0.45], [0.65, 0.0], @@ -238,7 +240,6 @@ RoomVisual.prototype.structure = function(x: number, y: number, type: string, op }); this.poly(inner, { fill : colors.light, - stroke : false, opacity: opts.opacity }); this.rect(x - 0.45, y - 0.45, 0.9, 0.9, { @@ -264,11 +265,10 @@ RoomVisual.prototype.structure = function(x: number, y: number, type: string, op }); this.rect(x - 0.45, y + 0.3, 0.9, 0.25, { fill : colors.dark, - stroke : false, opacity: opts.opacity }); { - let box = [ + let box: Points = [ [-0.45, 0.3], [-0.45, 0.55], [0.45, 0.55], @@ -305,7 +305,6 @@ RoomVisual.prototype.structure = function(x: number, y: number, type: string, op this.circle(x, y, { radius : 0.175, fill : colors.road, - stroke : false, opacity: opts.opacity }); if (!this.roads) this.roads = []; @@ -367,7 +366,7 @@ RoomVisual.prototype.structure = function(x: number, y: number, type: string, op }); break; case STRUCTURE_NUKER: - let outline = [ + let outline: Points = [ [0, -1], [-0.47, 0.2], [-0.5, 0.5], @@ -382,7 +381,7 @@ RoomVisual.prototype.structure = function(x: number, y: number, type: string, op fill : colors.dark, opacity : opts.opacity }); - let inline = [ + let inline: Points = [ [0, -.80], [-0.40, 0.2], [0.40, 0.2], @@ -430,7 +429,7 @@ const dirs = [ [-1, -1] ]; -RoomVisual.prototype.connectRoads = function(opts = {}): RoomVisual | void { +RoomVisual.prototype.connectRoads = function(this: RoomVisual, opts = {}): RoomVisual | void { _.defaults(opts, {opacity: 0.5}); const color = opts.color || colors.road || 'white'; if (!this.roads) return; @@ -456,7 +455,7 @@ RoomVisual.prototype.connectRoads = function(opts = {}): RoomVisual | void { }; -RoomVisual.prototype.speech = function(text: string, x: number, y: number, opts = {}): RoomVisual { +RoomVisual.prototype.speech = function(this: RoomVisual, text: string, x: number, y: number, opts = {}): RoomVisual { const background = !!opts.background ? opts.background : colors.speechBackground; const textcolor = !!opts.textcolor ? opts.textcolor : colors.speechText; // noinspection PointlessBooleanExpressionJS @@ -471,7 +470,7 @@ RoomVisual.prototype.speech = function(text: string, x: number, y: number, opts } fontstring += textsize + ' ' + textfont; - let pointer = [ + let pointer: Points = [ [-0.2, -0.8], [0.2, -0.8], [0, -0.3] @@ -498,7 +497,7 @@ RoomVisual.prototype.speech = function(text: string, x: number, y: number, opts }; -RoomVisual.prototype.animatedPosition = function(x: number, y: number, opts = {}): RoomVisual { +RoomVisual.prototype.animatedPosition = function(this: RoomVisual, x: number, y: number, opts = {}): RoomVisual { const color = !!opts.color ? opts.color : 'blue'; const opacity = !!opts.opacity ? opts.opacity : 0.5; @@ -513,7 +512,7 @@ RoomVisual.prototype.animatedPosition = function(x: number, y: number, opts = {} const sizeMod = Math.abs(Game.time % frames - frames / 2) / 10; radius += radius * sizeMod; - const points = [ + const points: Points = [ rotate(0, -radius, s, c, x, y), rotate(radius, 0, s, c, x, y), rotate(0, radius, s, c, x, y), @@ -526,14 +525,14 @@ RoomVisual.prototype.animatedPosition = function(x: number, y: number, opts = {} return this; }; -function rotate(x: number, y: number, s: number, c: number, px: number, py: number): { x: number, y: number } { +function rotate(x: number, y: number, s: number, c: number, px: number, py: number): Point { const xDelta = x * c - y * s; const yDelta = x * s + y * c; - return {x: px + xDelta, y: py + yDelta}; + return [px + xDelta, py + yDelta]; } -function relPoly(x: number, y: number, poly: number[][]): number[][] { +function relPoly(x: number, y: number, poly: Point[]): Point[] { return poly.map(p => { p[0] += x; p[1] += y; @@ -541,7 +540,7 @@ function relPoly(x: number, y: number, poly: number[][]): number[][] { }); } -RoomVisual.prototype.test = function(): RoomVisual { +RoomVisual.prototype.test = function(this: RoomVisual): RoomVisual { const demopos = [19, 24]; this.clear(); this.structure(demopos[0] + 0, demopos[1] + 0, STRUCTURE_LAB); @@ -622,7 +621,7 @@ const ResourceColors: { [color: string]: [string, string] } = { }; -RoomVisual.prototype.resource = function(type, x, y, size = 0.25, opacity = 1) { +RoomVisual.prototype.resource = function(this: RoomVisual, type, x, y, size = 0.25, opacity = 1) { if (type == RESOURCE_ENERGY || type == RESOURCE_POWER) { this._fluid(type, x, y, size, opacity); } else if (([RESOURCE_CATALYST, RESOURCE_HYDROGEN, RESOURCE_OXYGEN, RESOURCE_LEMERGIUM, RESOURCE_UTRIUM, @@ -637,7 +636,7 @@ RoomVisual.prototype.resource = function(type, x, y, size = 0.25, opacity = 1) { return OK; }; -RoomVisual.prototype._fluid = function(type, x, y, size = 0.25, opacity = 1) { +RoomVisual.prototype._fluid = function(this: RoomVisual, type, x, y, size = 0.25, opacity = 1) { this.circle(x, y, { radius : size, fill : ResourceColors[type][0], @@ -652,7 +651,7 @@ RoomVisual.prototype._fluid = function(type, x, y, size = 0.25, opacity = 1) { }); }; -RoomVisual.prototype._mineral = function(type, x, y, size = 0.25, opacity = 1) { +RoomVisual.prototype._mineral = function(this: RoomVisual, type, x, y, size = 0.25, opacity = 1) { this.circle(x, y, { radius : size, fill : ResourceColors[type][0], @@ -672,7 +671,7 @@ RoomVisual.prototype._mineral = function(type, x, y, size = 0.25, opacity = 1) { }); }; -RoomVisual.prototype._compound = function(type, x, y, size = 0.25, opacity = 1) { +RoomVisual.prototype._compound = function(this: RoomVisual, type, x, y, size = 0.25, opacity = 1) { const label = type.replace('2', '₂'); this.text(label, x, y, { diff --git a/src/prototypes/Structures.ts b/src/prototypes/Structures.ts index 522aff36f..3cb5c5b4c 100644 --- a/src/prototypes/Structures.ts +++ b/src/prototypes/Structures.ts @@ -91,7 +91,7 @@ Object.defineProperty(StructureController.prototype, 'signedByScreeps', { }); -StructureController.prototype.needsReserving = function(reserveBuffer: number): boolean { +StructureController.prototype.needsReserving = function(this: StructureController, reserveBuffer: number): boolean { return !this.reservation || (this.reservedByMe && this.reservation.ticksToEnd < reserveBuffer); }; From 198d2045e3707084332f603bde73a05276328963 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 02:13:09 +0200 Subject: [PATCH 17/41] Strict-type the IOvermind properties --- src/declarations/index.d.ts | 12 ++++++------ src/overlords/Overlord.ts | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/declarations/index.d.ts b/src/declarations/index.d.ts index 51b024a8a..3c6f4a7ce 100644 --- a/src/declarations/index.d.ts +++ b/src/declarations/index.d.ts @@ -116,12 +116,12 @@ interface IOvermind { expiration: number; cache: ICache; // is actually GameCache overseer: IOverseer; // is actually Overseer - directives: { [flagName: string]: any }; // is actually { [flagName: string]: Directive } - zerg: { [creepName: string]: any }; // is actually { [creepName: string]: Zerg } - powerZerg: { [creepName: string]: any }; // is actually { [creepName: string]: PowerZerg } - colonies: { [roomName: string]: any }; // is actually { [roomName: string]: Colony } - overlords: { [ref: string]: any }; // is actually { [ref: string]: Overlord } - spawnGroups: { [ref: string]: any }; // is actually { [ref: string]: SpawnGroup } + directives: { [flagName: string]: import('directives/Directive').Directive }; + zerg: { [creepName: string]: import('zerg/Zerg').Zerg }; + powerZerg: { [creepName: string]: import('zerg/PowerZerg').PowerZerg }; + colonies: { [roomName: string]: import('Colony').Colony }; + overlords: { [ref: string]: import('overlords/Overlord').Overlord }; + spawnGroups: { [ref: string]: import('logistics/SpawnGroup').SpawnGroup }; colonyMap: { [roomName: string]: string }; memory: IOvermindMemory; terminalNetwork: ITerminalNetwork; // is actually TerminalNetwork diff --git a/src/overlords/Overlord.ts b/src/overlords/Overlord.ts index ff8a7f3a4..3754bcf87 100644 --- a/src/overlords/Overlord.ts +++ b/src/overlords/Overlord.ts @@ -315,7 +315,7 @@ export abstract class Overlord { for (const creep of this._creeps[role] || []) { if (!zergNames[creep.name]) { if (Overmind.zerg[creep.name] && (Overmind.zerg[creep.name]).isCombatZerg) { - this._combatZerg[role].push(Overmind.zerg[creep.name]); + this._combatZerg[role].push(Overmind.zerg[creep.name]); } else { this._combatZerg[role].push(new CombatZerg(creep, notifyWhenAttacked)); } From 4a033d3e1d800c2d1491cdefcc41bf648cbe2527 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 02:13:50 +0200 Subject: [PATCH 18/41] Fix the recharge task not accessing the correct property --- src/tasks/instances/recharge.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tasks/instances/recharge.ts b/src/tasks/instances/recharge.ts index 6a298f16e..d44963826 100644 --- a/src/tasks/instances/recharge.ts +++ b/src/tasks/instances/recharge.ts @@ -34,9 +34,9 @@ export class TaskRecharge extends Task { return false; } const otherTargeters = _.filter(_.map(obj.targetedBy, name => Overmind.zerg[name]), - zerg => !!zerg && zerg.memory._task - && (zerg.memory._task.name == withdrawTaskName - || zerg.memory._task.name == pickupTaskName)); + zerg => !!zerg && zerg.task + && (zerg.task.name == withdrawTaskName + || zerg.task.name == pickupTaskName)); const resourceOutflux = _.sum(_.map(otherTargeters, other => other.carryCapacity - _.sum(other.carry))); amount = minMax(amount - resourceOutflux, 0, creep.carryCapacity); From db0f066fc610f2db1536cf317a6e293f65bf0795 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 03:47:23 +0200 Subject: [PATCH 19/41] Fix getting energy from tombstones not on containers --- src/Overseer.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Overseer.ts b/src/Overseer.ts index 9b6e99a62..384807b0b 100644 --- a/src/Overseer.ts +++ b/src/Overseer.ts @@ -188,7 +188,8 @@ export class Overseer implements IOverseer { for (const tombstone of colony.tombstones) { if (tombstone.store.getUsedCapacity() > LogisticsNetwork.settings.droppedEnergyThreshold || tombstone.store.getUsedCapacity() > tombstone.store.energy) { - if (colony.bunker && tombstone.pos.isEqualTo(colony.bunker.anchor)) continue; + if (colony.bunker && tombstone.pos.isEqualTo(colony.bunker.anchor) + || tombstone.pos.lookForStructure(STRUCTURE_CONTAINER)) continue; colony.logisticsNetwork.requestOutput(tombstone, {resourceType: 'all'}); } } From 9c70db8e05a3823c06ed50a1882f9616168ce010 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 04:22:36 +0200 Subject: [PATCH 20/41] Grab resources from ruins in the colony --- src/Colony.ts | 6 +++++- src/Overseer.ts | 10 ++++++++++ src/directives/resource/haul.ts | 5 ++--- src/logistics/LogisticsNetwork.ts | 2 +- src/overlords/core/transporter.ts | 4 ++-- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/Colony.ts b/src/Colony.ts index 145261068..285e31b50 100644 --- a/src/Colony.ts +++ b/src/Colony.ts @@ -144,6 +144,7 @@ export class Colony { observer: StructureObserver | undefined; // | tombstones: Tombstone[]; // | Tombstones in all colony rooms drops: { [resourceType: string]: Resource[] }; // | Dropped resources in all colony rooms + ruins: Ruin[]; // | Ruins in all colony rooms sources: Source[]; // | Sources in all colony rooms extractors: StructureExtractor[]; // | All extractors in owned and remote rooms flags: Flag[]; // | Flags assigned to the colony @@ -343,6 +344,7 @@ export class Colony { this.constructionSites = _.flatten(_.map(this.rooms, room => room.constructionSites)); this.tombstones = _.flatten(_.map(this.rooms, room => room.tombstones)); this.drops = _.merge(_.map(this.rooms, room => room.drops)); + this.ruins = _.merge(_.map(this.rooms, room => room.ruins)); this.repairables = _.flatten(_.map(this.rooms, room => room.repairables)); this.rechargeables = _.flatten(_.map(this.rooms, room => room.rechargeables)); // Register assets @@ -388,6 +390,7 @@ export class Colony { $.set(this, 'constructionSites', () => _.flatten(_.map(this.rooms, room => room.constructionSites)), 10); $.set(this, 'tombstones', () => _.flatten(_.map(this.rooms, room => room.tombstones)), 5); this.drops = _.merge(_.map(this.rooms, room => room.drops)); + $.set(this, 'ruins', () => _.flatten(_.map(this.rooms, room => room.ruins)), 5); // Register assets this.assets = this.computeAssets(); } @@ -398,10 +401,11 @@ export class Colony { private refreshRoomObjects(): void { $.refresh(this, 'controller', 'extensions', 'links', 'towers', 'powerSpawn', 'nuker', 'observer', 'spawns', 'storage', 'terminal', 'factory', 'labs', 'sources', 'extractors', 'constructionSites', 'repairables', - 'rechargeables'); + 'rechargeables', 'ruins'); $.set(this, 'constructionSites', () => _.flatten(_.map(this.rooms, room => room.constructionSites)), 10); $.set(this, 'tombstones', () => _.flatten(_.map(this.rooms, room => room.tombstones)), 5); this.drops = _.merge(_.map(this.rooms, room => room.drops)); + $.set(this, 'ruins', () => _.flatten(_.map(this.rooms, room => room.ruins)), 5); // Re-compute assets this.assets = this.computeAssets(); } diff --git a/src/Overseer.ts b/src/Overseer.ts index 384807b0b..66334ccdd 100644 --- a/src/Overseer.ts +++ b/src/Overseer.ts @@ -184,6 +184,16 @@ export class Overseer implements IOverseer { } } } + + // Pick up all nontrivial ruin resources + for (const ruin of colony.ruins) { + if (ruin.store.getUsedCapacity() > LogisticsNetwork.settings.droppedEnergyThreshold + || ruin.store.getUsedCapacity() > ruin.store.energy) { + if (colony.bunker && ruin.pos.isEqualTo(colony.bunker.anchor)) continue; + colony.logisticsNetwork.requestOutput(ruin, {resourceType: 'all'}); + } + } + // Place a logistics request directive for every tombstone with non-empty store that isn't on a container for (const tombstone of colony.tombstones) { if (tombstone.store.getUsedCapacity() > LogisticsNetwork.settings.droppedEnergyThreshold diff --git a/src/directives/resource/haul.ts b/src/directives/resource/haul.ts index 250503190..e6cde3c61 100644 --- a/src/directives/resource/haul.ts +++ b/src/directives/resource/haul.ts @@ -59,14 +59,13 @@ export class DirectiveHaul extends Directive { } get storeStructure(): StructureStorage | StructureTerminal | StructureNuker | StructureContainer | Ruin | undefined { - // TODO remove me console.log(`Looking for store struct in ${this.pos.roomName} - // with ${this.pos.lookForStructure(STRUCTURE_CONTAINER)}`); if (this.pos.isVisible) { return this.pos.lookForStructure(STRUCTURE_STORAGE) || this.pos.lookForStructure(STRUCTURE_TERMINAL) || this.pos.lookForStructure(STRUCTURE_NUKER) || this.pos.lookForStructure(STRUCTURE_CONTAINER) || - this.pos.lookFor(LOOK_RUINS).filter(ruin => _.sum(ruin.store) > 0)[0]; + this.pos.lookFor(LOOK_RUINS).filter(ruin => ruin.store.getUsedCapacity() > 0)[0] || + this.pos.lookFor(LOOK_TOMBSTONES).filter(tombstone => tombstone.store.getUsedCapacity() > 0)[0]; } return undefined; } diff --git a/src/logistics/LogisticsNetwork.ts b/src/logistics/LogisticsNetwork.ts index 60e82677c..4ec535a74 100644 --- a/src/logistics/LogisticsNetwork.ts +++ b/src/logistics/LogisticsNetwork.ts @@ -29,7 +29,7 @@ export type LogisticsTarget = | Resource; export const ALL_RESOURCE_TYPE_ERROR = - `Improper logistics request: 'all' can only be used for store structure or tombstone!`; + `Improper logistics request: 'all' can only be used for store structure, tombstone, or ruin!`; export type BufferTarget = StructureStorage | StructureTerminal; diff --git a/src/overlords/core/transporter.ts b/src/overlords/core/transporter.ts index 059aada78..64536e2db 100644 --- a/src/overlords/core/transporter.ts +++ b/src/overlords/core/transporter.ts @@ -1,7 +1,7 @@ import {Colony} from '../../Colony'; import {log} from '../../console/log'; import {Roles, Setups} from '../../creepSetups/setups'; -import {isResource, isTombstone} from '../../declarations/typeGuards'; +import {isResource, isRuin, isTombstone} from '../../declarations/typeGuards'; import {ALL_RESOURCE_TYPE_ERROR, BufferTarget, LogisticsRequest} from '../../logistics/LogisticsNetwork'; import {Pathing} from '../../movement/Pathing'; import {OverlordPriority} from '../../priorities/priorities_overlords'; @@ -86,7 +86,7 @@ export class TransportOverlord extends Overlord { const amount = this.colony.logisticsNetwork.predictedRequestAmount(transporter, request); // Target is requesting input if (amount > 0) { - if (isResource(request.target) || isTombstone(request.target)) { + if (isResource(request.target) || isTombstone(request.target) || isRuin(request.target)) { log.warning(`Improper logistics request: should not request input for resource or tombstone!`); return; } else if (request.resourceType == 'all') { From 34dec1aec639f8eeabc15e0fe763aff8ec424520 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 04:23:05 +0200 Subject: [PATCH 21/41] Remove dead code --- src/logistics/LogisticsNetwork.ts | 77 +------------------------- src/logistics/TransportRequestGroup.ts | 60 -------------------- src/tasks/instances/withdraw.ts | 18 +----- 3 files changed, 3 insertions(+), 152 deletions(-) diff --git a/src/logistics/LogisticsNetwork.ts b/src/logistics/LogisticsNetwork.ts index 4ec535a74..c143d4a64 100644 --- a/src/logistics/LogisticsNetwork.ts +++ b/src/logistics/LogisticsNetwork.ts @@ -206,48 +206,12 @@ export class LogisticsNetwork { } private getInputAmount(target: LogisticsTarget, resourceType: ResourceConstant): number { - // if (target instanceof DirectivePickup) { - // return target.storeCapacity - _.sum(target.store); - // } else if (isResource(target) || isTombstone(target) || isRuin(target)) { log.error(`Improper logistics request: should not request input for resource or tombstone!`); return 0; } - // @ts-ignore return target.store.getFreeCapacity(resourceType) || 0; - - // else if (isStoreStructure(target)) { - // return target.storeCapacity - _.sum(target.store); - // } else if (isEnergyStructure(target) && resourceType == RESOURCE_ENERGY) { - // return target.energyCapacity - target.energy; - // } - // // else if (target instanceof Zerg) { - // // return target.carryCapacity - _.sum(target.carry); - // // } - // else { - // if (target instanceof StructureLab) { - // if (resourceType == target.mineralType) { - // return target.mineralCapacity - target.mineralAmount; - // } else if (resourceType == RESOURCE_ENERGY) { - // return target.energyCapacity - target.energy; - // } - // } else if (target instanceof StructureNuker) { - // if (resourceType == RESOURCE_GHODIUM) { - // return target.ghodiumCapacity - target.ghodium; - // } else if (resourceType == RESOURCE_ENERGY) { - // return target.energyCapacity - target.energy; - // } - // } else if (target instanceof StructurePowerSpawn) { - // if (resourceType == RESOURCE_POWER) { - // return target.powerCapacity - target.power; - // } else if (resourceType == RESOURCE_ENERGY) { - // return target.energyCapacity - target.energy; - // } - // } - // } - // log.warning('Could not determine input amount!'); - // return 0; } private getOutputAmount(target: LogisticsTarget, resourceType: ResourceConstant | 'all'): number { @@ -256,52 +220,15 @@ export class LogisticsNetwork { log.error(ALL_RESOURCE_TYPE_ERROR); return 0; } else { - // @ts-ignore - return target.store.getUsedCapacity(); + return target.store.getUsedCapacity() || 0; } } else { if (isResource(target)) { return target.amount; } else { - // @ts-ignore - return target.store.getUsedCapacity(resourceType); + return target.store.getUsedCapacity(resourceType) || 0; } - - // Legacy code - // else if (isTombstone(target)) { - // return target.store[resourceType] || 0; - // } else if (isStoreStructure(target)) { - // return target.store[resourceType] || 0; - // } else if (isEnergyStructure(target) && resourceType == RESOURCE_ENERGY) { - // return target.energy; - // } - // // else if (target instanceof Zerg) { - // // return target.carry[resourceType]!; - // // } - // else { - // if (target instanceof StructureLab) { - // if (resourceType == target.mineralType) { - // return target.mineralAmount; - // } else if (resourceType == RESOURCE_ENERGY) { - // return target.energy; - // } - // } else if (target instanceof StructureNuker) { - // if (resourceType == RESOURCE_GHODIUM) { - // return target.ghodium; - // } else if (resourceType == RESOURCE_ENERGY) { - // return target.energy; - // } - // } else if (target instanceof StructurePowerSpawn) { - // if (resourceType == RESOURCE_POWER) { - // return target.power; - // } else if (resourceType == RESOURCE_ENERGY) { - // return target.energy; - // } - // } - // } } - // log.warning('Could not determine output amount!'); - // return 0; } // Transporter availability and predictive functions =============================================================== diff --git a/src/logistics/TransportRequestGroup.ts b/src/logistics/TransportRequestGroup.ts index e246a552a..aa0e4fe02 100644 --- a/src/logistics/TransportRequestGroup.ts +++ b/src/logistics/TransportRequestGroup.ts @@ -155,71 +155,11 @@ export class TransportRequestGroup { // } private getInputAmount(target: TransportRequestTarget, resourceType: ResourceConstant): number { - // @ts-ignore return target.store.getFreeCapacity(resourceType) || 0; - - // Legacy code from before the structure.store refactor - // if (isStoreStructure(target)) { - // return target.storeCapacity - _.sum(target.store); - // } else if (isEnergyStructure(target) && resourceType == RESOURCE_ENERGY) { - // return target.energyCapacity - target.energy; - // } else { - // if (target instanceof StructureLab) { - // if (resourceType == target.mineralType) { - // return target.mineralCapacity - target.mineralAmount; - // } else if (resourceType == RESOURCE_ENERGY) { - // return target.energyCapacity - target.energy; - // } - // } else if (target instanceof StructureNuker) { - // if (resourceType == RESOURCE_GHODIUM) { - // return target.ghodiumCapacity - target.ghodium; - // } else if (resourceType == RESOURCE_ENERGY) { - // return target.energyCapacity - target.energy; - // } - // } else if (target instanceof StructurePowerSpawn) { - // if (resourceType == RESOURCE_POWER) { - // return target.powerCapacity - target.power; - // } else if (resourceType == RESOURCE_ENERGY) { - // return target.energyCapacity - target.energy; - // } - // } - // } - // log.warning('Could not determine requestor amount!'); - // return 0; } private getOutputAmount(target: TransportRequestTarget, resourceType: ResourceConstant): number { - // @ts-ignore return target.store.getUsedCapacity(resourceType) || 0; - - // Legacy code from before the structure.store refactor - // if (isStoreStructure(target)) { - // return target.store[resourceType]!; - // } else if (isEnergyStructure(target) && resourceType == RESOURCE_ENERGY) { - // return target.energy; - // } else { - // if (target instanceof StructureLab) { - // if (resourceType == target.mineralType) { - // return target.mineralAmount; - // } else if (resourceType == RESOURCE_ENERGY) { - // return target.energy; - // } - // } else if (target instanceof StructureNuker) { - // if (resourceType == RESOURCE_GHODIUM) { - // return target.ghodium; - // } else if (resourceType == RESOURCE_ENERGY) { - // return target.energy; - // } - // } else if (target instanceof StructurePowerSpawn) { - // if (resourceType == RESOURCE_POWER) { - // return target.power; - // } else if (resourceType == RESOURCE_ENERGY) { - // return target.energy; - // } - // } - // } - // log.warning('Could not determine provider amount!'); - // return 0; } /** diff --git a/src/tasks/instances/withdraw.ts b/src/tasks/instances/withdraw.ts index 1617c0fcb..8bc384489 100644 --- a/src/tasks/instances/withdraw.ts +++ b/src/tasks/instances/withdraw.ts @@ -1,6 +1,4 @@ /* Withdraw a resource from a target */ - -import {isRuin, isTombstone,} from '../../declarations/typeGuards'; import {profile} from '../../profiler/decorator'; import {Task} from '../Task'; @@ -31,21 +29,7 @@ export class TaskWithdraw extends Task { isValidTarget() { const amount = this.data.amount || 1; - // @ts-ignore - return this.target.store.getUsedCapacity(this.data.resourceType) >= amount; - // const target = this.target; - // if (isTombstone(target) || isRuin(target) || isStoreStructure(target)) { - // return (target.store[this.data.resourceType] || 0) >= amount; - // } else if (isEnergyStructure(target) && this.data.resourceType == RESOURCE_ENERGY) { - // return target.energy >= amount; - // } else { - // if (target instanceof StructureLab) { - // return this.data.resourceType == target.mineralType && target.mineralAmount >= amount; - // } else if (target instanceof StructurePowerSpawn) { - // return this.data.resourceType == RESOURCE_POWER && target.power >= amount; - // } - // } - // return false; + return (this.target.store.getUsedCapacity(this.data.resourceType) || 0) >= amount; } work() { From 2d4caf016c0a36211cb683ac17336bf8b63654c8 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 04:23:29 +0200 Subject: [PATCH 22/41] Give the first hauler some priority --- src/overlords/situational/hauler.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/overlords/situational/hauler.ts b/src/overlords/situational/hauler.ts index 21e2c9e44..289488f04 100644 --- a/src/overlords/situational/hauler.ts +++ b/src/overlords/situational/hauler.ts @@ -44,7 +44,11 @@ export class HaulingOverlord extends Overlord { // Calculate number of haulers const numHaulers = Math.min(Math.ceil(haulingPowerNeeded / haulingPowerPerLifetime), MAX_HAULERS); // Request the haulers - this.wishlist(numHaulers, Setups.transporters.early); + if (this.haulers.length === 0) { + this.wishlist(numHaulers, Setups.transporters.early, { priority: OverlordPriority.collectionUrgent.haul }); + } else { + this.wishlist(numHaulers, Setups.transporters.early); + } } private handleHauler(hauler: Zerg) { From 40386f1f967b410a9e7f9f6a2d9d81c10cb79354 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 05:59:51 +0200 Subject: [PATCH 23/41] Reassign fillers on bootstrap instead of suiciding --- src/directives/situational/bootstrap.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/directives/situational/bootstrap.ts b/src/directives/situational/bootstrap.ts index 4748e9dd9..18b57150c 100644 --- a/src/directives/situational/bootstrap.ts +++ b/src/directives/situational/bootstrap.ts @@ -55,10 +55,10 @@ export class DirectiveBootstrap extends Directive { return; // wait a little while at higher levels before stopping bootstrapping } log.alert(`Colony ${this.room.print} has recovered from crash; removing bootstrap directive.`); - // Suicide any fillers so they don't get in the way + // Reassign any filler to the work force const overlord = this.overlords.bootstrap as BootstrappingOverlord; for (const filler of overlord.fillers) { - filler.suicide(); + filler.reassign(this.colony.overlords.logistics, Roles.transport); } // Remove the directive this.remove(); From 9954a10385b3d816bd5e157215a0facef99a031c Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 06:01:43 +0200 Subject: [PATCH 24/41] Safe-guard the bunker-queen overlord against an invalid starting layout --- src/hiveClusters/hatchery.ts | 3 +-- src/overlords/core/queen_bunker.ts | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/hiveClusters/hatchery.ts b/src/hiveClusters/hatchery.ts index d7a1098d0..0fbd7a069 100644 --- a/src/hiveClusters/hatchery.ts +++ b/src/hiveClusters/hatchery.ts @@ -131,8 +131,7 @@ export class Hatchery extends HiveCluster { } spawnMoarOverlords() { - if (this.colony.layout == 'bunker' && (this.colony.storage || this.colony.terminal) - && this.colony.assets[RESOURCE_ENERGY] > 10000) { + if (BunkerQueenOverlord.canFunction(this.colony)) { this.overlord = new BunkerQueenOverlord(this); // use bunker queen if has storage and enough energy } else { this.overlord = new QueenOverlord(this); diff --git a/src/overlords/core/queen_bunker.ts b/src/overlords/core/queen_bunker.ts index 1ec829e89..0db860d45 100644 --- a/src/overlords/core/queen_bunker.ts +++ b/src/overlords/core/queen_bunker.ts @@ -53,6 +53,13 @@ export class BunkerQueenOverlord extends Overlord { private numActiveQueens: number; assignments: { [queenName: string]: { [id: string]: boolean } }; + static canFunction(colony: Colony): boolean { + return (colony.layout === "bunker" + && insideBunkerBounds(colony.spawns[0].pos, colony) + && (!!colony.storage || !!colony.terminal) + && colony.assets[RESOURCE_ENERGY] > 10000); + } + constructor(hatchery: Hatchery, priority = OverlordPriority.core.queen) { super(hatchery, 'supply', priority); this.queenSetup = Setups.queens.default; From c15859905bd275d8f29c377a7cec800b3d02cdf0 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 06:41:39 +0200 Subject: [PATCH 25/41] Show more info about targets in the TransportRequestGroup summary --- src/logistics/TransportRequestGroup.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/logistics/TransportRequestGroup.ts b/src/logistics/TransportRequestGroup.ts index aa0e4fe02..59889bd25 100644 --- a/src/logistics/TransportRequestGroup.ts +++ b/src/logistics/TransportRequestGroup.ts @@ -173,7 +173,9 @@ export class TransportRequestGroup { } for (const request of this.supply[priority]) { if (ignoreEnergy && request.resourceType == RESOURCE_ENERGY) continue; - console.log(` targetID: ${request.target.ref} amount: ${request.amount} ` + + console.log(` target: ${request.target.structureType}@${request.target.pos.print} ` + + `(${request.target.ref}) `+ + `amount: ${request.amount} ` + `resourceType: ${request.resourceType}`); } } @@ -184,7 +186,9 @@ export class TransportRequestGroup { } for (const request of this.withdraw[priority]) { if (ignoreEnergy && request.resourceType == RESOURCE_ENERGY) continue; - console.log(` targetID: ${request.target.ref} amount: ${request.amount} ` + + console.log(` target: ${request.target.structureType}@${request.target.pos.print} ` + + `(${request.target.ref}) `+ + `amount: ${request.amount} ` + `resourceType: ${request.resourceType}`); } } From f575b60bc856a46fb5c9bc82d77825441aed8c2e Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 06:42:13 +0200 Subject: [PATCH 26/41] Fix typo --- src/overlords/core/queen_bunker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/overlords/core/queen_bunker.ts b/src/overlords/core/queen_bunker.ts index 0db860d45..b44746abc 100644 --- a/src/overlords/core/queen_bunker.ts +++ b/src/overlords/core/queen_bunker.ts @@ -208,8 +208,8 @@ export class BunkerQueenOverlord extends Overlord { } if (!withdrawTarget && withdrawTasks.length == 0) { - log.warning(`Could not find adequate withdraw structure for ${queen.print}! (neededResources: - ${neededResources}, queenCarry: ${JSON.stringify(queenCarry)})`); + log.warning(`Could not find adequate withdraw structure for ${queen.print}! ` + + `(neededResources: ${neededResources}, queenCarry: ${JSON.stringify(queenCarry)})`); return null; } // Step 4: put all the tasks in the correct order, set nextPos for each, and chain them together @@ -328,7 +328,7 @@ export class BunkerQueenOverlord extends Overlord { Tasks.withdraw(this.colony.terminal, RESOURCE_GHODIUM, 1000), Tasks.generateSafeMode(this.colony.controller) ]); - log.alert(`${this.colony.print} has ${this.colony.controller.safeModeAvailable} safemodes avaliable, ` + + log.alert(`${this.colony.print} has ${this.colony.controller.safeModeAvailable} safemodes available, ` + `generating a new one`); } } From 1e0058b8185c35e169db28ae93c5eda0a0161c2d Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 09:01:15 +0200 Subject: [PATCH 27/41] Fix dismantling blockers for remote mines --- src/movement/Pathing.ts | 20 +++++++++++++++++--- src/overlords/mining/miner.ts | 8 ++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/movement/Pathing.ts b/src/movement/Pathing.ts index 38dc67ec6..2ad7fe0ec 100644 --- a/src/movement/Pathing.ts +++ b/src/movement/Pathing.ts @@ -1190,10 +1190,21 @@ export class Pathing { maxOps : 2000, ensurePath : false, }); - if (startPos.roomName != endPos.roomName) { - log.error(`findBlockingPos() should only be used within a single room!`); - return undefined; + if (startPos.roomName !== endPos.roomName) { + // Start and end aren't in the same room. + const pathToEnd = this.findPath(startPos, endPos, { + range: options.range!, + roadCost: "auto", + terrainCosts: { plainCost: 1, swampCost: 5 }, + }); + + let newStartPos = pathToEnd.path.find(step => step.roomName === endPos.roomName); + if (!newStartPos) + return undefined; + + startPos = newStartPos; } + const matrix = new PathFinder.CostMatrix(); _.forEach(obstacles, obstacle => { if (hasPos(obstacle)) { @@ -1210,11 +1221,14 @@ export class Pathing { maxRooms : 1, roomCallback: callback, }); + for (const pos of ret.path) { if (matrix.get(pos.x, pos.y) > 100) { return pos; } } + + return undefined; } /** diff --git a/src/overlords/mining/miner.ts b/src/overlords/mining/miner.ts index 12605db98..c03cce96b 100644 --- a/src/overlords/mining/miner.ts +++ b/src/overlords/mining/miner.ts @@ -77,10 +77,10 @@ export class MiningOverlord extends Overlord { // Check if dismantling is needed if (this.memory.dismantleNeeded || Game.time > (this.memory[DISMANTLE_CHECK] || 0)) { if (this.room) { - this.dismantlePositions = this.getDismantlePositions(); - if (this.dismantlePositions.length > 0) { + const positions = this.getDismantlePositions(); + if (positions.length > 0) { this.memory.dismantleNeeded = true; - this.dismantlePositions = this.getDismantlePositions(); + this.dismantlePositions = positions; } else { this.memory[DISMANTLE_CHECK] = getCacheExpiration(DISMANTLE_CHECK_FREQUENCY, DISMANTLE_CHECK_FREQUENCY / 5); @@ -187,7 +187,7 @@ export class MiningOverlord extends Overlord { private getDismantlePositions(): RoomPosition[] { const dismantleStructures: Structure[] = []; if (this.room) { - const targets = _.compact([...this.room.sources, this.room.controller]) as RoomObject[]; + const targets = _.compact([this.source, this.secondSource, this.container, this.link]) as RoomObject[]; for (const target of targets) { // Add blocking structures const blockingStructure = this.findBlockingStructure(target); From b69d7cf5dc4c7345c573e80e60808c139c85e263 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 09:01:46 +0200 Subject: [PATCH 28/41] Align the logistic network summary correctly --- src/logistics/LogisticsNetwork.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/logistics/LogisticsNetwork.ts b/src/logistics/LogisticsNetwork.ts index c143d4a64..739cd3c05 100644 --- a/src/logistics/LogisticsNetwork.ts +++ b/src/logistics/LogisticsNetwork.ts @@ -542,15 +542,15 @@ export class LogisticsNetwork { const transporterStr = transporter.name + ' ' + transporter.pos; const request = this._matching![transporter.name]!; const requestStr = request.target.ref + ' ' + request.target.pos.print; - console.log(`${transporterStr.padRight(30)} : ${requestStr}`); + console.log(`${transporterStr.padRight(35)} : ${requestStr}`); } for (const transporter of unmatchedTransporters) { const transporterStr = transporter.name + ' ' + transporter.pos; - console.log(`${transporterStr.padRight(30)} : ${''}`); + console.log(`${transporterStr.padRight(35)} : ${''}`); } for (const request of unmatchedRequests) { const requestStr = request.target.ref + ' ' + request.target.pos; - console.log(`${''.padRight(30)} : ${requestStr}`); + console.log(`${''.padRight(35)} : ${requestStr}`); } console.log(); } From dfd34861d6b3a01532371eeb63ac06962984d3d7 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 11:39:21 +0200 Subject: [PATCH 29/41] Improve the output of the outpost efficiency commands --- src/console/Console.ts | 90 ++++++++------------ src/overlords/mining/miner.ts | 28 +++--- src/strategy/ExpansionEvaluator.ts | 132 +++++++++++++++++------------ 3 files changed, 131 insertions(+), 119 deletions(-) diff --git a/src/console/Console.ts b/src/console/Console.ts index d59055a59..250ebd463 100644 --- a/src/console/Console.ts +++ b/src/console/Console.ts @@ -530,71 +530,55 @@ export class OvermindConsole { } static evaluateOutpostEfficiencies(): string { - const colonies = getAllColonies(); - const outpostEfficiencies: {[roomName: string]: number} = {}; - let avgEnergyPerCPU = 0; - - colonies.forEach(colony => { - if (colony.bunker) { - colony.outposts.forEach(outpost => { - const res = ExpansionEvaluator.computeTheoreticalMiningEfficiency(colony.bunker!.anchor, outpost.name); - if (typeof res === 'boolean') { - log.error(`Failed on outpost ${outpost.print}`); - } else { - outpostEfficiencies[outpost.name] = res; - avgEnergyPerCPU += res; - } - }); - } - }); + const outpostsPerColony = <[Colony, string[]][]>getAllColonies().filter(c => c.bunker) + .map(c => [c, c.outposts.map(r => r.name)]); - avgEnergyPerCPU = avgEnergyPerCPU/Object.keys(outpostEfficiencies).length; - let ret = `Suspect Outposts +25% below avg efficiency of ${avgEnergyPerCPU}: \n`; + return OvermindConsole.reportOutpostEfficiency(outpostsPerColony, (avg, colonyAvg) => avg < colonyAvg * 0.75); + } - for (const outpost in outpostEfficiencies) { - if (outpostEfficiencies[outpost] < avgEnergyPerCPU*0.75) { - ret += `${outpost} ${outpostEfficiencies[outpost]} \n`; + static evaluatePotentialOutpostEfficiencies(): string { + const outpostsPerColony = <[Colony, string[]][]>getAllColonies().filter(c => c.bunker) + .map(c => { + const outpostNames = c.outposts.map(room => room.name); + return [c, Cartographer.findRoomsInRange(c.name, 2).filter(r => !outpostNames.includes(r))]; } - } + ); - return ret; + return OvermindConsole.reportOutpostEfficiency(outpostsPerColony, (avg, colonyAvg) => avg > colonyAvg * 1.25 || avg > 20); } - static evaluatePotentialOutpostEfficiencies(): string { - const colonies = getAllColonies(); - const outpostEfficiencies: {[roomName: string]: number} = {}; - let avgEnergyPerCPU = 0; - - colonies.forEach(colony => { - if (colony.bunker) { - Cartographer.findRoomsInRange(colony.name, 2).forEach(outpost => { - if (!colony.outposts.map(room => room.name).includes(outpost)) { - const res = ExpansionEvaluator.computeTheoreticalMiningEfficiency(colony.bunker!.anchor, outpost); - if (typeof res === 'boolean') { - log.error(`Failed on outpost ${outpost}`); - } else { - outpostEfficiencies[outpost] = res; - avgEnergyPerCPU += res; - } - } - }); - } - }); + static reportOutpostEfficiency(outpostsPerColony: [Colony, string[]][], selectionCallback: (avg: number, colonyAvg: number) => boolean): string { + let msg = `Estimated outpost efficiency:\n`; + for (const [colony, outposts] of outpostsPerColony) { + let avgEnergyPerCPU = 0; + const outpostAvgEnergyPerCPU = []; - avgEnergyPerCPU = avgEnergyPerCPU/Object.keys(outpostEfficiencies).length; - let ret = `Possible new outposts above avg efficiency of ${avgEnergyPerCPU}: \n`; + msg += ` • Colony at ${colony.room.name}:\n` + for (const outpost of outposts) { + const d = ExpansionEvaluator.computeTheoreticalMiningEfficiency(colony.bunker!.anchor, outpost); - for (const outpost in outpostEfficiencies) { - // 20E/cpu is a good guideline for an efficient room - if (outpostEfficiencies[outpost] > avgEnergyPerCPU*1.25 || outpostEfficiencies[outpost] > 20) { - ret += `${outpost} ${outpostEfficiencies[outpost]} \n`; + msg += `\t - ${d.room} ${`(${d.type})`.padLeft(6)}: ${(d.energyPerSource * d.sources / ENERGY_REGEN_TIME).toFixed(2)} energy/source, Net income: ${d.netIncome.toFixed(2)}, Net energy/CPU: ${(d.netIncome / d.cpuCost).toFixed(2)}\n`; + msg += `\t Creep costs: ${d.creepEnergyCost.toFixed(2)} energy/tick, spawn time: ${d.spawnTimeCost.toFixed(2)}, CPU: ${d.cpuCost.toFixed(2)} cycles/tick\n`; + if (d.unreachableSources || d.unreachableController) { + const { unreachableSources: s, unreachableController: c } = d; + msg += `\t ${color("Unreachable:", "yellow")} ${s ? `sources: ${s}` : ""}${s && c ? ', ' : ''}${c ? `controller: ${c}` : ""}\n`; + } + + outpostAvgEnergyPerCPU.push(d.avgEnergyPerCPU); + avgEnergyPerCPU += d.avgEnergyPerCPU; } - } - return ret; - } + const bestOutposts = outpostAvgEnergyPerCPU.map((avg, idx) => { + // 20E/cpu is a good guideline for an efficient room + if (selectionCallback(avg, avgEnergyPerCPU)) return idx + 1; + return undefined; + }).filter(avg => avg); + msg += `\n Outposts with above average efficiency of ${avgEnergyPerCPU.toFixed(2)}: ${bestOutposts.join(", ")}\n`; + } + return msg; + } // Memory management =============================================================================================== diff --git a/src/overlords/mining/miner.ts b/src/overlords/mining/miner.ts index c03cce96b..8b3fcb118 100644 --- a/src/overlords/mining/miner.ts +++ b/src/overlords/mining/miner.ts @@ -1,5 +1,5 @@ import {$} from '../../caching/GlobalCache'; -import {ColonyStage} from '../../Colony'; +import {Colony, ColonyStage} from '../../Colony'; import {log} from '../../console/log'; import {bodyCost, CreepSetup} from '../../creepSetups/CreepSetup'; import {Roles, Setups} from '../../creepSetups/setups'; @@ -241,26 +241,28 @@ export class MiningOverlord extends Overlord { $.refresh(this, 'source', 'container', 'link', 'constructionSite'); } + static calculateContainerPos(source: RoomPosition, dropoffLocation?: RoomPosition): RoomPosition { + // log.debug(`Computing container position for mining overlord at ${this.pos.print}...`); + if (dropoffLocation) { + const path = Pathing.findShortestPath(source, dropoffLocation).path; + const pos = _.find(path, pos => pos.getRangeTo(source) == 1); + if (pos) return pos; + } + log.warning(`Last resort container position calculation for ${source.print}!`); + return _.first(source.availableNeighbors(true)); + } /** * Calculate where the container output will be built for this site */ private calculateContainerPos(): RoomPosition { - // log.debug(`Computing container position for mining overlord at ${this.pos.print}...`); - let originPos: RoomPosition | undefined; + let dropoff: RoomPosition | undefined; if (this.colony.storage) { - originPos = this.colony.storage.pos; + dropoff = this.colony.storage.pos; } else if (this.colony.roomPlanner.storagePos) { - originPos = this.colony.roomPlanner.storagePos; - } - if (originPos) { - const path = Pathing.findShortestPath(this.pos, originPos).path; - const pos = _.find(path, pos => pos.getRangeTo(this) == 1); - if (pos) return pos; + dropoff = this.colony.roomPlanner.storagePos; } - // Shouldn't ever get here - log.warning(`Last resort container position calculation for ${this.print}!`); - return _.first(this.pos.availableNeighbors(true)); + return MiningOverlord.calculateContainerPos(this.pos, dropoff); } /** diff --git a/src/strategy/ExpansionEvaluator.ts b/src/strategy/ExpansionEvaluator.ts index d584639d8..2830f9ce4 100644 --- a/src/strategy/ExpansionEvaluator.ts +++ b/src/strategy/ExpansionEvaluator.ts @@ -14,6 +14,8 @@ import { ROOMTYPE_SOURCEKEEPER } from '../utilities/Cartographer'; import set = Reflect.set; +import { OvermindConsole } from 'console/Console'; +import { MiningOverlord } from 'overlords/mining/miner'; export const EXPANSION_EVALUATION_FREQ = 500; export const MIN_EXPANSION_DISTANCE = 2; @@ -23,6 +25,20 @@ export interface ColonyExpansionData { expiration: number; } +export interface ExpansionEvaluatorRoomEfficiency { + room: string; + type: string; + dropoffLocation: RoomPosition; + sources: number; + unreachableSources: number; + unreachableController: boolean; + energyPerSource: number; + creepEnergyCost: number; + spawnTimeCost: number; + cpuCost: number; + netIncome: number; + avgEnergyPerCPU: number; +}; @profile export class ExpansionEvaluator { @@ -68,89 +84,101 @@ export class ExpansionEvaluator { * @param room * @param verbose */ - static computeTheoreticalMiningEfficiency(dropoffLocation: RoomPosition, room: string, verbose = false) - : boolean|number { - const roomName = room; - const roomType = Cartographer.roomType(roomName); - let cpuCost = 0; - let creepEnergyCost = 0; - let spawnTimeCost = 0; + static computeTheoreticalMiningEfficiency(dropoffLocation: RoomPosition, room: string) { + const type = Cartographer.roomType(room); const upkeepEnergyCost = 0; // todo later can factor in road damage from all creeps moving - const sourcePositions = RoomIntel.getSourceInfo(roomName); + const data : ExpansionEvaluatorRoomEfficiency = { + room: room, + type: type, + dropoffLocation: dropoffLocation, + sources: 0, + unreachableSources: 0, + unreachableController: false, + energyPerSource: 0, + creepEnergyCost: 0, + spawnTimeCost: 0, + cpuCost: 0, + netIncome: 0, + avgEnergyPerCPU: 0, + }; + + const sourcePositions = RoomIntel.getSourceInfo(room); if (sourcePositions == undefined) { - if (verbose) log.info(`No memory of outpost room: ${roomName}. Aborting score calculation!`); - return false; + log.info(`No memory of outpost room: ${room}. Aborting score calculation!`); + return data; } + // Compute Path length // TODO have it track how many swamp/plain/tunnel const sourcePathLengths: {[sourcePos: string]: number} = {}; for (const source of sourcePositions) { - if (!source.containerPos) { - log.info(`Can't find container position for source ${source} during efficiency calc`); - return false; - } + const containerPos = MiningOverlord.calculateContainerPos(source.pos, dropoffLocation); + // TODO Need to factor in where roads would go - const path = Pathing.findShortestPath(dropoffLocation, source.containerPos, - {ignoreStructures: true, allowHostile: true}); + const path = Pathing.findShortestPath(dropoffLocation, containerPos, + {ignoreStructures: true, allowHostile: true, blockCreeps: false, avoidSK: false}); if (path.incomplete) { - log.error(`Couldn't find path to source ${source} for mining efficiency calc`); - return false; + log.error(`Couldn't find path to source ${source.pos.print} for mining efficiency calc`); + data.unreachableSources++; + continue; } sourcePathLengths[source.pos.print] = path.path.length; } // Compute Energy Supply - const energyPerSource = roomType == ROOMTYPE_CONTROLLER ? SOURCE_ENERGY_CAPACITY : SOURCE_ENERGY_KEEPER_CAPACITY; + data.energyPerSource = type == ROOMTYPE_CONTROLLER ? SOURCE_ENERGY_CAPACITY : SOURCE_ENERGY_KEEPER_CAPACITY; // Compute miner upkeep for (const source of sourcePositions) { - const setup = roomType == ROOMTYPE_CONTROLLER ? Setups.drones.miners.standard.generateMaxedBody() + const setup = type == ROOMTYPE_CONTROLLER ? Setups.drones.miners.standard.generateMaxedBody() : Setups.drones.miners.sourceKeeper.generateMaxedBody(); const effectiveCreepUptime = (CREEP_LIFE_TIME - sourcePathLengths[source.pos.print]); - creepEnergyCost += bodyCost(setup)/effectiveCreepUptime; - spawnTimeCost += setup.length*CREEP_SPAWN_TIME/effectiveCreepUptime; + data.creepEnergyCost += bodyCost(setup)/effectiveCreepUptime; + data.spawnTimeCost += setup.length*CREEP_SPAWN_TIME/effectiveCreepUptime; // Always harvesting, sometimes replacement is moving - cpuCost += 0.2 + 0.2*(1-effectiveCreepUptime/CREEP_LIFE_TIME); + data.cpuCost += 0.2 + 0.2*(1-effectiveCreepUptime/CREEP_LIFE_TIME); } // Compute reserver/skReaper upkeep - if (roomType == ROOMTYPE_CONTROLLER) { - const controller = RoomIntel.getControllerInfo(roomName); + if (type == ROOMTYPE_CONTROLLER) { + const controller = RoomIntel.getControllerInfo(room); if (!controller) { - log.error(`Expansion Efficiency Calc: Can't find controller for room ${roomName}`); - return false; + log.error(`Expansion Efficiency Calc: Can't find controller for room ${room}`); + data.unreachableController = true; } else { const setup = Setups.infestors.reserve.generateMaxedBody(); const controllerPath = Pathing.findShortestPath(dropoffLocation, controller.pos, {ignoreStructures: true, allowHostile: true}); if (controllerPath.incomplete) { log.error(`Couldn't find path to controller ${controller} for mining efficiency calc`); - return false; + data.unreachableController = true; + } else { + const claimPower = _.filter(setup, (part: BodyPartConstant) => part == CLAIM).length; + const effectiveLifetimeReservationGeneration = (CREEP_CLAIM_LIFE_TIME - controllerPath.path.length) * claimPower; + data.creepEnergyCost += bodyCost(setup)/effectiveLifetimeReservationGeneration; + data.spawnTimeCost += setup.length*CREEP_SPAWN_TIME/effectiveLifetimeReservationGeneration; + data.cpuCost += 0.2 * CREEP_CLAIM_LIFE_TIME / effectiveLifetimeReservationGeneration; } - const claimPower = _.filter(setup, (part: BodyPartConstant) => part == CLAIM).length; - const effectiveLifetimeReservationGeneration = (CREEP_CLAIM_LIFE_TIME - controllerPath.path.length) * claimPower; - creepEnergyCost += bodyCost(setup)/effectiveLifetimeReservationGeneration; - spawnTimeCost += setup.length*CREEP_SPAWN_TIME/effectiveLifetimeReservationGeneration; - cpuCost += 0.2 * CREEP_CLAIM_LIFE_TIME / effectiveLifetimeReservationGeneration; } - } else if (roomType == ROOMTYPE_SOURCEKEEPER) { + } else if (type == ROOMTYPE_SOURCEKEEPER) { // Handle SK const setup = CombatSetups.zerglings.sourceKeeper.generateMaxedBody(); - const skPath = Pathing.findPathToRoom(dropoffLocation, roomName, + const skPath = Pathing.findPathToRoom(dropoffLocation, room, {ignoreStructures: true, allowHostile: true}); if (skPath.incomplete) { - log.error(`Couldn't find path to sk room ${roomName} for mining efficiency calc`); - return false; + log.error(`Couldn't find path to sk room ${room} for mining efficiency calc`); + data.unreachableController = true; + } else { + const effectiveCreepUptime = (CREEP_LIFE_TIME - skPath.path.length); + data.creepEnergyCost += bodyCost(setup)/effectiveCreepUptime; + data.spawnTimeCost += setup.length*CREEP_SPAWN_TIME/effectiveCreepUptime; + // Increased cost, always moving, frequent attack/move+heal intents, and during overlap 2nd creep moving to room + data.cpuCost += 0.2 + 0.15 + 0.2*(1-effectiveCreepUptime/CREEP_LIFE_TIME); + // TODO examine for accuracy Increased cost, frequent attack/move+heal intents } - const effectiveCreepUptime = (CREEP_LIFE_TIME - skPath.path.length); - creepEnergyCost += bodyCost(setup)/effectiveCreepUptime; - spawnTimeCost += setup.length*CREEP_SPAWN_TIME/effectiveCreepUptime; - // Increased cost, always moving, frequent attack/move+heal intents, and during overlap 2nd creep moving to room - cpuCost += 0.2 + 0.15 + 0.2*(1-effectiveCreepUptime/CREEP_LIFE_TIME); - // TODO examine for accuracy Increased cost, frequent attack/move+heal intents } // Compute transporter upkeep @@ -160,20 +188,18 @@ export class ExpansionEvaluator { const transporterCarryParts = _.filter(setup, (part: BodyPartConstant) => part == CARRY).length; const effectiveEnergyTransportedPerTick = transporterCarryParts * CARRY_CAPACITY / (2 * sourcePathLengths[source.pos.print]); // round trip - const transportersPerSource = energyPerSource/ENERGY_REGEN_TIME/effectiveEnergyTransportedPerTick; + const transportersPerSource = data.energyPerSource/ENERGY_REGEN_TIME/effectiveEnergyTransportedPerTick; - creepEnergyCost += bodyCost(setup)*transportersPerSource/CREEP_LIFE_TIME; - spawnTimeCost += setup.length*CREEP_SPAWN_TIME*transportersPerSource/CREEP_LIFE_TIME; - cpuCost += 0.2 * transportersPerSource; + data.creepEnergyCost += bodyCost(setup)*transportersPerSource/CREEP_LIFE_TIME; + data.spawnTimeCost += setup.length*CREEP_SPAWN_TIME*transportersPerSource/CREEP_LIFE_TIME; + data.cpuCost += 0.2 * transportersPerSource; } - const netIncome = (energyPerSource*sourcePositions.length/ENERGY_REGEN_TIME)-creepEnergyCost; + data.sources = sourcePositions.length; + data.netIncome = (data.energyPerSource * sourcePositions.length / ENERGY_REGEN_TIME) - data.creepEnergyCost; + data.avgEnergyPerCPU = (data.netIncome / data.cpuCost || 0); - let msg = `(Potential) Outpost ${room} type ${roomType} evaluated for colony at ${dropoffLocation.roomName} with per tick results \n`; - msg += `Income: ${energyPerSource*sourcePositions.length/ENERGY_REGEN_TIME} Net Income: ${netIncome} Net Energy per CPU: ${netIncome/cpuCost}\n`; - msg += `Creep Costs: Energy ${creepEnergyCost}, Spawn Time ${spawnTimeCost}, and CPU ${cpuCost} \n`; - log.alert(msg); - return netIncome/cpuCost; + return data; } // Compute the total score for a room From ab68173aa48f6dd6c80182c37daa5a807f0bb96a Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 23:24:14 +0200 Subject: [PATCH 30/41] Fix a bug that would have prevented non-move boots from being applied Cherry-picked from 07f221587e0356badddd47eb3cade33004aeba5e --- src/overlords/Overlord.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/overlords/Overlord.ts b/src/overlords/Overlord.ts index 3754bcf87..e41eee587 100644 --- a/src/overlords/Overlord.ts +++ b/src/overlords/Overlord.ts @@ -543,7 +543,7 @@ export abstract class Overlord { const [moveBoosts, nonMoveBoosts] = _.partition(neededBoostResources, resource => Abathur.isMoveBoost(resource)); - for (const boost of [...moveBoosts, nonMoveBoosts]) { // try to get move boosts first if they're available + for (const boost of [...moveBoosts, ...nonMoveBoosts]) { // try to get move boosts first if they're available const boostLab = _.find(evolutionChamber.boostingLabs, lab => lab.mineralType == boost); if (boostLab) { zerg.task = Tasks.getBoosted(boostLab, boost); From ceb4ca07e67550a96fa9c81790f4727b91bf7578 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 23:28:08 +0200 Subject: [PATCH 31/41] Fix a bug that would prevent players to be detected correctly Cherry-pick from 6ce4e72649c82cbf296beab0540d92792e9fb637 --- src/declarations/prototypes.d.ts | 2 +- src/prototypes/Room.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/declarations/prototypes.d.ts b/src/declarations/prototypes.d.ts index 6bf475b31..671d6cbb7 100644 --- a/src/declarations/prototypes.d.ts +++ b/src/declarations/prototypes.d.ts @@ -7,7 +7,7 @@ interface Creep { inRampart: boolean; approxMoveSpeed: number; bodypartCounts: { [bodypart in BodyPartConstant]: number }; - isHuman: true; + isPlayer: true; // private _boosts: ResourceConstant[]; diff --git a/src/prototypes/Room.ts b/src/prototypes/Room.ts index 5938ea2a8..378e99738 100644 --- a/src/prototypes/Room.ts +++ b/src/prototypes/Room.ts @@ -114,7 +114,7 @@ Object.defineProperty(Room.prototype, 'sourceKeepers', { Object.defineProperty(Room.prototype, 'playerHostiles', { get(this: Room) { if (!this._playerHostiles) { - this._playerHostiles = _.filter(this.hostiles, (creep: Creep) => creep.isHuman); + this._playerHostiles = _.filter(this.hostiles, (creep: Creep) => creep.isPlayer); } return this._playerHostiles; }, From 4c7f6b34d83514fc07bb5dd96d6225207ab4a7f5 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 22:00:10 +0200 Subject: [PATCH 32/41] Fix push priority calculation for Managers As those creeps have a push priority of 0, the check would fail and default them, defeating the push protection entirely. --- src/movement/Movement.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/movement/Movement.ts b/src/movement/Movement.ts index 4b8fbb2da..f3edd162b 100644 --- a/src/movement/Movement.ts +++ b/src/movement/Movement.ts @@ -463,8 +463,10 @@ export class Movement { } else { if (isPowerZerg(creep)) { return MovePriorities.powerCreep; + } else if (creep.memory.role in MovePriorities) { + return MovePriorities[creep.memory.role]; } else { - return MovePriorities[creep.memory.role] || MovePriorities.default; + return MovePriorities.default; } } } From 07fee1b386120bcebc60cd08281c006d0b71c479 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sat, 5 Aug 2023 23:19:57 +0200 Subject: [PATCH 33/41] Improve fortify response to nukes This reworks the nuke planner fortify logic to get to minimum safe value, then balance fortifications instead of full true up of barriers in order of priority which could be a massive jump if behind Squashed from commits 53df9373c1183d635062ab3a750f84bc1dfc5885, d4929730e221aa370234a2b8b529007928528291 --- src/Overseer.ts | 2 +- src/overlords/core/worker.ts | 50 +++++++++++++++++++++++++++++------- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/Overseer.ts b/src/Overseer.ts index 66334ccdd..f04680a80 100644 --- a/src/Overseer.ts +++ b/src/Overseer.ts @@ -329,7 +329,7 @@ export class Overseer implements IOverseer { // Place nuke response directive if there is a nuke present in colony room if (colony.room && colony.level >= DirectiveNukeResponse.requiredRCL) { for (const nuke of colony.room.find(FIND_NUKES)) { - DirectiveNukeResponse.createIfNotPresent(nuke.pos, 'pos'); + DirectiveNukeResponse.createIfNotPresent(colony.controller.pos, 'room'); } } } diff --git a/src/overlords/core/worker.ts b/src/overlords/core/worker.ts index d900eaa16..297c32875 100644 --- a/src/overlords/core/worker.ts +++ b/src/overlords/core/worker.ts @@ -13,6 +13,8 @@ import {Visualizer} from '../../visuals/Visualizer'; import {Zerg} from '../../zerg/Zerg'; import {Overlord} from '../Overlord'; +type hitsCallbackType = (structure: StructureWall | StructureRampart) => number; + /** * Spawns general-purpose workers, which maintain a colony, performing actions such as building, repairing, fortifying, * paving, and upgrading, when needed @@ -29,6 +31,7 @@ export class WorkerOverlord extends Overlord { constructionSites: ConstructionSite[]; nukeDefenseRamparts: StructureRampart[]; nukeDefenseHitsRemaining: { [id: string]: number }; + nukeDefenseHitsNeeded: { [id: string]: number }; useBoostedRepair?: boolean; static settings = { @@ -106,6 +109,7 @@ export class WorkerOverlord extends Overlord { // Nuke defense ramparts needing fortification this.nukeDefenseRamparts = []; this.nukeDefenseHitsRemaining = {}; + this.nukeDefenseHitsNeeded = {}; if (this.room.find(FIND_NUKES).length > 0) { for (const rampart of this.colony.room.ramparts) { const neededHits = this.neededRampartHits(rampart); @@ -133,8 +137,11 @@ export class WorkerOverlord extends Overlord { this.workers = this.zerg(Roles.worker); } - private neededRampartHits(rampart: StructureRampart): number { - let neededHits = WorkerOverlord.settings.barrierHits[this.colony.level]; + private neededNukeHits(rampart: StructureWall|StructureRampart): number { + if (this.nukeDefenseHitsNeeded[rampart.id] !== undefined) { + return this.nukeDefenseHitsNeeded[rampart.id] + } + let neededHits = 0; for (const nuke of rampart.pos.lookFor(LOOK_NUKES)) { neededHits += 10e6; } @@ -143,6 +150,13 @@ export class WorkerOverlord extends Overlord { neededHits += 5e6; } } + this.nukeDefenseHitsNeeded[rampart.id] = neededHits; + return neededHits; + } + + private neededRampartHits(rampart: StructureRampart): number { + let neededHits = WorkerOverlord.settings.barrierHits[this.colony.level]; + neededHits =+ this.neededNukeHits(rampart); return neededHits; } @@ -264,19 +278,26 @@ export class WorkerOverlord extends Overlord { } } - private fortifyActions(worker: Zerg, fortifyStructures = this.fortifyBarriers): boolean { + private findLowBarriers(fortifyStructures = this.fortifyBarriers, + hitsCallback: hitsCallbackType = (structure) => structure.hits, + numBarriersToConsider = 5 + ): (StructureWall | StructureRampart)[] { let lowBarriers: (StructureWall | StructureRampart)[]; - const highestBarrierHits = _.max(_.map(fortifyStructures, structure => structure.hits)); + const highestBarrierHits = _.max(_.map(fortifyStructures, structure => hitsCallback(structure))); if (highestBarrierHits > WorkerOverlord.settings.hitTolerance) { // At high barrier HP, fortify only structures that are within a threshold of the lowest - const lowestBarrierHits = _.min(_.map(fortifyStructures, structure => structure.hits)); - lowBarriers = _.filter(fortifyStructures, structure => structure.hits <= lowestBarrierHits + + const lowestBarrierHits = _.min(_.map(fortifyStructures, structure => hitsCallback(structure))); + lowBarriers = _.filter(fortifyStructures, structure => hitsCallback(structure) <= lowestBarrierHits + WorkerOverlord.settings.hitTolerance); } else { // Otherwise fortify the lowest N structures - const numBarriersToConsider = 5; // Choose the closest barrier of the N barriers with lowest hits lowBarriers = _.take(fortifyStructures, numBarriersToConsider); } + return lowBarriers + } + + private fortifyActions(worker: Zerg, fortifyStructures = this.fortifyBarriers): boolean { + const lowBarriers = this.findLowBarriers(fortifyStructures); const target = worker.pos.findClosestByMultiRoomRange(lowBarriers); if (target) { worker.task = Tasks.fortify(target); @@ -287,7 +308,17 @@ export class WorkerOverlord extends Overlord { } private nukeFortifyActions(worker: Zerg, fortifyStructures = this.nukeDefenseRamparts): boolean { - const target = minBy(fortifyStructures, rampart => { + var self = this; + const adaptedHits = _.reduce(fortifyStructures, function(obj,structure: StructureWall|StructureRampart) { + obj[structure.id] = structure.hits - self.neededNukeHits(structure); + return obj; + }, {} as {[key: string]: number}); + + const lowBarriers = this.findLowBarriers() + const minBarrier = lowBarriers[lowBarriers.length - 1].hits + const urgent = _.filter(fortifyStructures, structure => adaptedHits[structure.id] < minBarrier) + + const target = minBy(urgent, rampart => { const structuresUnderRampart = rampart.pos.lookFor(LOOK_STRUCTURES); return _.min(_.map(structuresUnderRampart, structure => { const priority = _.findIndex(FortifyPriorities, sType => sType == structure.structureType); @@ -298,11 +329,12 @@ export class WorkerOverlord extends Overlord { } })); }); + if (target) { worker.task = Tasks.fortify(target); return true; } else { - return false; + return this.fortifyActions(worker, fortifyStructures); } } From 364c2844089cbe213a34c49776c02ea691936c0e Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Tue, 12 Sep 2023 00:07:41 +0200 Subject: [PATCH 34/41] Update package.json This switches to Node 18 and more recent version of most dependencies --- .tool-versions | 2 +- package.json | 28 ++++++++++++++-------------- src/declarations/index.d.ts | 1 - 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/.tool-versions b/.tool-versions index a61cf126e..e9847d93b 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -nodejs 10.24.1 +nodejs 18.9.1 diff --git a/package.json b/package.json index a51e2a7b0..a03aa9b4b 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "Overmind", + "name": "overmind", "version": "0.6.0", "description": "Overmind Screeps AI", "author": "Ben Bartlett", @@ -24,25 +24,25 @@ "test": "npm run clean && npm run build" }, "engines": { - "node": "10.x" + "node": ">= 18.9.1" }, "devDependencies": { - "@types/node": "^10.17.18", + "@rollup/plugin-commonjs": "^25.0.3", + "@rollup/plugin-node-resolve": "^15.1.0", + "@types/columnify": "^1.5.1", "@types/lodash": "3.10.2", - "@types/screeps": "^3.1.0", - "@rollup/plugin-commonjs": "^11.0.2", - "@rollup/plugin-node-resolve": "^7.1.1", - "rollup": "2.6.0", - "rollup-plugin-progress": "1.1.1", - "rollup-plugin-screeps": "1.0.0", - "rollup-plugin-typescript2": "0.27.0", - "tslint": "^5.20.0", - "typedoc": "^0.14.2", - "typescript": "2.9.2" + "@types/screeps": "^3.3.3", + "rollup": "^3.27.1", + "rollup-plugin-progress": "^1.1.2", + "rollup-plugin-screeps": "^1.0.1", + "rollup-plugin-typescript2": "^0.35.0", + "tslint": "^6.1.3", + "typedoc": "^0.24.8", + "typescript": "^5.1.6" }, "dependencies": { "@tensorflow/tfjs": "^1.2.11", - "columnify": "1.5.4", + "columnify": "^1.6.0", "onnxjs": "^0.1.6", "source-map": "0.7.3" } diff --git a/src/declarations/index.d.ts b/src/declarations/index.d.ts index 3c6f4a7ce..c00638bc9 100644 --- a/src/declarations/index.d.ts +++ b/src/declarations/index.d.ts @@ -45,7 +45,6 @@ type Omit = Pick>; // declare module 'screeps-profiler'; // I stopped using the typings for this because it was fucking up the Game typings -declare module 'columnify'; // If TS2451 gets thrown, change "declare let Game: Game;" to "declare var Game: Game;" // in typed-screeps index.d.ts file. (See issue #61 until the package is updated) From 266efb0c025da557b7c23fe3e115936cc802ae0a Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Tue, 12 Sep 2023 00:07:53 +0200 Subject: [PATCH 35/41] Update rollup configuration --- rollup.config.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/rollup.config.js b/rollup.config.js index 5ebeaa6ed..295e1278d 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -5,14 +5,17 @@ import commonjs from '@rollup/plugin-commonjs'; import progress from "rollup-plugin-progress"; import typescript from "rollup-plugin-typescript2"; import screeps from "rollup-plugin-screeps"; +import { readFileSync } from 'fs'; let cfg; const dest = process.env.DEST; if (!dest) { console.log('\x1b[46m%s\x1b[0m \x1b[36m%s\x1b[0m', 'Compiling Overmind...', '(deploy destination: none)'); -} else if ((cfg = require("./screeps")[dest]) == null) { - throw new Error("Invalid upload destination"); } else { + cfg = JSON.parse(readFileSync("./screeps.json"))[dest]; + if (!cfg) { + throw new Error("Invalid upload destination"); + } console.log('\x1b[46m%s\x1b[0m \x1b[36m%s\x1b[0m', 'Compiling Overmind...', `(deploy destination: ${dest})`); console.log(`Pushing at time: ${new Date()})`); } @@ -28,13 +31,7 @@ export default { plugins: [ progress({clearLine: true}), resolve(), - commonjs({ - namedExports: { - 'src/Overmind_obfuscated': ['_Overmind'], - 'screeps-profiler': ['profiler'], - 'columnify': ['columnify'] - } - }), + commonjs(), typescript({tsconfig: "./tsconfig.json"}), screeps({config: cfg, dryRun: cfg == null}) ], @@ -70,4 +67,4 @@ export default { '//\n' }, -} \ No newline at end of file +} From 98e1e06250c401f9af4093132246adc0f888cba7 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 3 Aug 2023 19:45:48 +0200 Subject: [PATCH 36/41] Disable TS checking on utf15.ts --- src/algorithms/utf15.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/utf15.ts b/src/algorithms/utf15.ts index 7278c179d..1a161f9f0 100644 --- a/src/algorithms/utf15.ts +++ b/src/algorithms/utf15.ts @@ -1,7 +1,7 @@ +// @ts-nocheck // This module has been adapted from Mototroller's utf15 library: // https://github.com/screepers/utf15 - /* tslint:disable:no-bitwise prefer-for-of variable-name no-unused-expression */ import {profile} from '../profiler/decorator'; From c51ffeedb6e2551fb717c53fa98e7d48fce5fe3f Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Thu, 3 Aug 2023 20:13:09 +0200 Subject: [PATCH 37/41] Replace types with ones from @types/screeps --- src/caching/GlobalCache.ts | 24 ++++++++++++------------ src/declarations/index.d.ts | 10 +--------- src/declarations/prototypes.d.ts | 4 ++-- src/declarations/typeGuards.ts | 4 ++-- src/matrix/MatrixLib.ts | 16 ++++++++-------- src/movement/Movement.ts | 12 ++++++------ src/movement/Pathing.ts | 8 ++++---- src/movement/helpers.ts | 2 +- src/tasks/Task.ts | 12 ++++++------ src/tasks/instances/drop.ts | 2 +- src/zerg/AnyZerg.ts | 10 +++++----- src/zerg/NeuralZerg.ts | 2 +- src/zerg/Swarm.ts | 14 +++++++------- 13 files changed, 56 insertions(+), 64 deletions(-) diff --git a/src/caching/GlobalCache.ts b/src/caching/GlobalCache.ts index 7b37f006c..d83600e8a 100644 --- a/src/caching/GlobalCache.ts +++ b/src/caching/GlobalCache.ts @@ -98,7 +98,7 @@ export class $ { // $ = cash = cache... get it? :D } static set(thing: T, key: K, - callback: () => (T[K] & (undefined | HasID | HasID[])), + callback: () => (T[K] & (undefined | _HasId | _HasId[])), timeout = CACHE_TIMEOUT): void { const cacheKey = thing.ref + '$' + key; if (!_cache.things[cacheKey] || Game.time > _cache.expiration[cacheKey]) { @@ -109,39 +109,39 @@ export class $ { // $ = cash = cache... get it? :D // Refresh structure list by ID if not already done on current tick if ((_cache.accessed[cacheKey] || 0) < Game.time) { if (_.isArray(_cache.things[cacheKey])) { - _cache.things[cacheKey] = _.compact(_.map(_cache.things[cacheKey] as HasID[], - s => Game.getObjectById(s.id))) as HasID[]; + _cache.things[cacheKey] = _.compact(_.map(_cache.things[cacheKey] as _HasId[], + s => Game.getObjectById(s.id))) as _HasId[]; } else { - _cache.things[cacheKey] = Game.getObjectById((_cache.things[cacheKey]).id) as HasID; + _cache.things[cacheKey] = Game.getObjectById((<_HasId>_cache.things[cacheKey]).id) as _HasId; } _cache.accessed[cacheKey] = Game.time; } } - thing[key] = _cache.things[cacheKey] as T[K] & (undefined | HasID | HasID[]); + thing[key] = _cache.things[cacheKey] as T[K] & (undefined | _HasId | _HasId[]); } - static refresh, K extends string>(thing: T, ...keys: K[]): void { + static refresh, K extends string>(thing: T, ...keys: K[]): void { _.forEach(keys, function(key) { if (thing[key]) { if (_.isArray(thing[key])) { - thing[key] = _.compact(_.map(thing[key] as HasID[], s => Game.getObjectById(s.id))) as T[K]; + thing[key] = _.compact(_.map(thing[key] as _HasId[], s => Game.getObjectById(s.id))) as T[K]; } else { - thing[key] = Game.getObjectById((thing[key]).id) as T[K]; + thing[key] = Game.getObjectById((<_HasId>thing[key]).id) as T[K]; } } }); } - static refreshObject, + static refreshObject, K extends string>(thing: T, ...keys: K[]): void { _.forEach(keys, function(key) { if (_.isObject(thing[key])) { for (const prop in thing[key]) { if (_.isArray(thing[key][prop])) { - thing[key][prop] = _.compact(_.map(thing[key][prop] as HasID[], - s => Game.getObjectById(s.id))) as HasID[]; + thing[key][prop] = _.compact(_.map(thing[key][prop] as _HasId[], + s => Game.getObjectById(s.id))) as _HasId[]; } else { - thing[key][prop] = Game.getObjectById((thing[key][prop]).id) as undefined | HasID; + thing[key][prop] = Game.getObjectById((<_HasId>thing[key][prop]).id) as undefined | _HasId; } } } diff --git a/src/declarations/index.d.ts b/src/declarations/index.d.ts index c00638bc9..f7db6537c 100644 --- a/src/declarations/index.d.ts +++ b/src/declarations/index.d.ts @@ -62,7 +62,7 @@ interface IGlobalCache { lists: { [key: string]: any[] }; costMatrices: { [key: string]: CostMatrix }; roomPositions: { [key: string]: RoomPosition | undefined }; - things: { [key: string]: undefined | HasID | HasID[] }; + things: { [key: string]: undefined | _HasId | _HasId[] }; // objects: { [key: string]: Object }; } @@ -290,18 +290,10 @@ interface ProtoPos { roomName: string; } -interface HasPos { - pos: RoomPosition; -} - interface HasRef { ref: string; } -interface HasID { - id: Id; -} - type AnyStoreStructure = StructureContainer | StructureExtension diff --git a/src/declarations/prototypes.d.ts b/src/declarations/prototypes.d.ts index 671d6cbb7..3cb8effb0 100644 --- a/src/declarations/prototypes.d.ts +++ b/src/declarations/prototypes.d.ts @@ -80,7 +80,7 @@ interface Room { threatLevel: number; instantaneousThreatLevel: 0 | 0.5 | 1; - fleeDefaults: HasPos[]; + fleeDefaults: _HasRoomPosition[]; structures: Structure[]; hostileStructures: Structure[]; @@ -147,7 +147,7 @@ interface Room { _dangerousHostiles: Creep[]; _playerHostiles: Creep[]; _dangerousPlayerHostiles: Creep[]; - _fleeDefaults: HasPos[]; + _fleeDefaults: _HasRoomPosition[]; _allStructures: Structure[]; _hostileStructures: Structure[]; _flags: Flag[]; diff --git a/src/declarations/typeGuards.ts b/src/declarations/typeGuards.ts index dac03e94b..1de41509e 100644 --- a/src/declarations/typeGuards.ts +++ b/src/declarations/typeGuards.ts @@ -49,8 +49,8 @@ export function isResource(obj: RoomObject): obj is Resource { return (obj).amount != undefined; } -export function hasPos(obj: HasPos | RoomPosition): obj is HasPos { - return (obj).pos != undefined; +export function hasPos(obj: _HasRoomPosition | RoomPosition): obj is _HasRoomPosition { + return (<_HasRoomPosition>obj).pos != undefined; } export function isCreep(obj: RoomObject): obj is Creep { diff --git a/src/matrix/MatrixLib.ts b/src/matrix/MatrixLib.ts index c6445a36e..c383b1ee4 100644 --- a/src/matrix/MatrixLib.ts +++ b/src/matrix/MatrixLib.ts @@ -401,7 +401,7 @@ export class MatrixLib { /** * Blocks all specified positions, setting their cost to 0xff */ - static block(matrix: CostMatrix, positions: (RoomPosition | HasPos)[]): CostMatrix { + static block(matrix: CostMatrix, positions: (RoomPosition | _HasRoomPosition)[]): CostMatrix { let pos: RoomPosition; for (let i = 0; i < positions.length; i++) { pos = normalizePos(positions[i]); @@ -413,7 +413,7 @@ export class MatrixLib { /** * Sets the cost of all positions to a value if walls are not present and if the value is above the current value */ - static softBlock(matrix: CostMatrix, positions: (RoomPosition | HasPos)[], + static softBlock(matrix: CostMatrix, positions: (RoomPosition | _HasRoomPosition)[], roomName: string, cost: number): CostMatrix { let pos: RoomPosition; const terrain = Game.map.getRoomTerrain(roomName); @@ -473,7 +473,7 @@ export class MatrixLib { * 0 2 2 2 2 2 0 * 0 0 0 0 0 0 0 */ - static addPyramidPotential(matrix: CostMatrix, pos: RoomPosition | HasPos, range: number, maxCost: number, + static addPyramidPotential(matrix: CostMatrix, pos: RoomPosition | _HasRoomPosition, range: number, maxCost: number, includeTerrain = true, // don't use includeTerrain with explicitTerrainCosts! terrainCosts: TerrainCosts = {plainCost: 1, swampCost: 5}): CostMatrix { @@ -520,7 +520,7 @@ export class MatrixLib { * Adds a square potential with a specified center and range. If includeTerrainCosts=true (by default) then if the * cost for a square is zero, the terrain cost of the tile is added using default costs of {plain: 1, swamp: 5}. */ - static addSquarePotential(matrix: CostMatrix, pos: RoomPosition | HasPos, range: number, addCost: number, + static addSquarePotential(matrix: CostMatrix, pos: RoomPosition | _HasRoomPosition, range: number, addCost: number, includeTerrain = true, // don't use includeTerrain with explicitTerrainCosts! terrainCosts: TerrainCosts = {plainCost: 1, swampCost: 5}): CostMatrix { @@ -588,7 +588,7 @@ export class MatrixLib { * -> Do not run additional passes of applyMovingMaxPool after doing this! * -> This method assumes that you have already added explicit terrian costs. */ - static blockAfterMaxPooling(matrix: CostMatrix, positions: (RoomPosition | HasPos)[], + static blockAfterMaxPooling(matrix: CostMatrix, positions: (RoomPosition | _HasRoomPosition)[], width: number, height: number): CostMatrix { let pos: RoomPosition; let x, y, dx, dy: number; @@ -619,7 +619,7 @@ export class MatrixLib { * 0 9 0 0 0 9 5 0 9 9 5 1 | 0 9 0 0 9 9 1 1 9 9 5 1 * 0 0 0 1 0 0 0 1 0 0 1 1 | 0 0 0 1 0 0 1 1 0 0 1 1 */ - static setToMaxCostAfterMaxPooling(matrix: CostMatrix, positions: (RoomPosition | HasPos)[], + static setToMaxCostAfterMaxPooling(matrix: CostMatrix, positions: (RoomPosition | _HasRoomPosition)[], width: number, height: number, cost: number): CostMatrix { let pos: RoomPosition; let x, y, dx, dy: number; @@ -655,7 +655,7 @@ export class MatrixLib { * 0 9 0 0 0 9 5 0 9 9 5 1 | 0 9 0 0 9 9 1 1 9 9 6 1 * 0 0 0 1 0 0 0 1 0 0 1 1 | 0 0 0 1 0 0 1 1 0 0 1 1 */ - static addCostAfterMaxPooling(matrix: CostMatrix, positions: (RoomPosition | HasPos)[], + static addCostAfterMaxPooling(matrix: CostMatrix, positions: (RoomPosition | _HasRoomPosition)[], width: number, height: number, cost: number): CostMatrix { const addMatrix = new PathFinder.CostMatrix(); MatrixLib.setToMaxCostAfterMaxPooling(addMatrix, positions, width, height, cost); @@ -668,7 +668,7 @@ export class MatrixLib { * to the existing cost of the tile. If the cost for a square is zero, the terrain cost of the tile is added * using implicit costs of {plain: 1, swamp: 5} */ - static setInRange(matrix: CostMatrix, pos: RoomPosition | HasPos, range: number, cost: number, + static setInRange(matrix: CostMatrix, pos: RoomPosition | _HasRoomPosition, range: number, cost: number, addDefaultTerrainCosts = false): CostMatrix { pos = normalizePos(pos); diff --git a/src/movement/Movement.ts b/src/movement/Movement.ts index f3edd162b..aaf3b29ce 100644 --- a/src/movement/Movement.ts +++ b/src/movement/Movement.ts @@ -127,7 +127,7 @@ export class Movement { /** * Move a creep to a destination */ - static goTo(creep: AnyZerg, destination: HasPos | RoomPosition, opts: MoveOptions = {}): number { + static goTo(creep: AnyZerg, destination: _HasRoomPosition | RoomPosition, opts: MoveOptions = {}): number { if (creep.blockMovement && !opts.force) { return ERR_BUSY; @@ -755,7 +755,7 @@ export class Movement { /** * Moves a pair of creeps; the follower will always attempt to be in the last position of the leader */ - static pairwiseMove(leader: AnyZerg, follower: AnyZerg, target: HasPos | RoomPosition, + static pairwiseMove(leader: AnyZerg, follower: AnyZerg, target: _HasRoomPosition | RoomPosition, opts = {} as MoveOptions, allowedRange = 1): number | undefined { let outcome; if (leader.room != follower.room) { @@ -795,7 +795,7 @@ export class Movement { /** * Moves a swarm to a destination, accounting for group pathfinding */ - static swarmMove(swarm: Swarm, destination: HasPos | RoomPosition, opts: SwarmMoveOptions = {}): number { + static swarmMove(swarm: Swarm, destination: _HasRoomPosition | RoomPosition, opts: SwarmMoveOptions = {}): number { if (swarm.fatigue > 0) { Movement.circle(swarm.anchor, 'aqua', .3); @@ -1198,7 +1198,7 @@ export class Movement { /** * Moving routine for guards or sourceReapers in a room with NPC invaders */ - static invasionMove(creep: Zerg, destination: RoomPosition | HasPos, opts: MoveOptions = {}): number { + static invasionMove(creep: Zerg, destination: RoomPosition | _HasRoomPosition, opts: MoveOptions = {}): number { _.defaults(opts, getDefaultMoveOptions()); const dest = normalizePos(destination); if (creep.pos.getRangeTo(dest) > 8) { @@ -1217,7 +1217,7 @@ export class Movement { /** * Kite around enemies in a single room, repathing every tick. More expensive than flee(). */ - static kite(creep: AnyZerg, avoidGoals: (RoomPosition | HasPos)[], options: MoveOptions = {}): number | undefined { + static kite(creep: AnyZerg, avoidGoals: (RoomPosition | _HasRoomPosition)[], options: MoveOptions = {}): number | undefined { _.defaults(options, { fleeRange : 5, terrainCosts: isPowerZerg(creep) ? {plainCost: 1, swampCost: 1} : getTerrainCosts((creep.creep)), @@ -1231,7 +1231,7 @@ export class Movement { /** * Flee from avoid goals in the room while not re-pathing every tick like kite() does. */ - static flee(creep: AnyZerg, avoidGoals: (RoomPosition | HasPos)[], + static flee(creep: AnyZerg, avoidGoals: (RoomPosition | _HasRoomPosition)[], dropEnergy = false, opts: MoveOptions = {}): number | undefined { if (avoidGoals.length == 0) { diff --git a/src/movement/Pathing.ts b/src/movement/Pathing.ts index 2ad7fe0ec..af0cad98d 100644 --- a/src/movement/Pathing.ts +++ b/src/movement/Pathing.ts @@ -488,7 +488,7 @@ export class Pathing { /** * Get a kiting path within a room */ - static findKitingPath(creepPos: RoomPosition, fleeFrom: (RoomPosition | HasPos)[], + static findKitingPath(creepPos: RoomPosition, fleeFrom: (RoomPosition | _HasRoomPosition)[], opts: PathOptions = {}): PathFinderPath { _.defaults(opts, { fleeRange : 5, @@ -511,7 +511,7 @@ export class Pathing { /** * Get a flee path possibly leaving the room; generally called further in advance of kitingPath */ - static findFleePath(creepPos: RoomPosition, fleeFrom: (RoomPosition | HasPos)[], + static findFleePath(creepPos: RoomPosition, fleeFrom: (RoomPosition | _HasRoomPosition)[], opts: PathOptions = {}): PathFinderPath { _.defaults(opts, { terrainCosts: {plainCost: 1, swampCost: 5}, @@ -1139,7 +1139,7 @@ export class Pathing { * Whether another object in the same room can be reached from the current position. * This method is very expensive and kind of stupid, so use it sparingly! */ - static isReachable(startPos: RoomPosition, endPos: RoomPosition, obstacles: (RoomPosition | HasPos)[], + static isReachable(startPos: RoomPosition, endPos: RoomPosition, obstacles: (RoomPosition | _HasRoomPosition)[], options: PathOptions = {}): boolean { _.defaults(options, { blockCreeps: false, @@ -1182,7 +1182,7 @@ export class Pathing { /** * Like isReachable(), but returns the first position which should be cleared to find a path to destination */ - static findBlockingPos(startPos: RoomPosition, endPos: RoomPosition, obstacles: (RoomPosition | HasPos)[], + static findBlockingPos(startPos: RoomPosition, endPos: RoomPosition, obstacles: (RoomPosition | _HasRoomPosition)[], options: PathOptions = {}): RoomPosition | undefined { _.defaults(options, { blockCreeps: false, diff --git a/src/movement/helpers.ts b/src/movement/helpers.ts index 85fa6b36d..b5a184baf 100644 --- a/src/movement/helpers.ts +++ b/src/movement/helpers.ts @@ -1,7 +1,7 @@ /** * Returns destination.pos if destination has a position, or destination if destination is a RoomPosition */ -export function normalizePos(destination: HasPos | RoomPosition): RoomPosition { +export function normalizePos(destination: _HasRoomPosition | RoomPosition): RoomPosition { return (destination).pos || destination; } diff --git a/src/tasks/Task.ts b/src/tasks/Task.ts index fe2564b94..57aa77c87 100644 --- a/src/tasks/Task.ts +++ b/src/tasks/Task.ts @@ -22,18 +22,18 @@ interface AbstractTaskTarget { _pos: ProtoPos; // Target position's coordinates in case vision is lost } -type ConcreteTaskTarget = HasRef | HasPos | RoomPosition; +type ConcreteTaskTarget = HasRef | _HasRoomPosition | RoomPosition; function isAbstractTarget(target: any): target is AbstractTaskTarget { - return target && target._pos !== undefined; + return target && (target)._pos !== undefined; } -function isRoomRefTarget(target: any): target is HasRef & HasPos { - return target && target.ref !== undefined; +function isRoomRefTarget(target: any): target is HasRef & _HasRoomPosition { + return target && (target).ref !== undefined; } function isRoomObjectTarget(target: any): target is RoomObject { - return target && target.pos !== undefined; + return target && (target).pos !== undefined; } /** @@ -171,7 +171,7 @@ export abstract class Task { // refresh if you have visibility of the target if (!this._targetPos) { if (this.target) { - this._target._pos = (this.target as HasPos).pos; + this._target._pos = (this.target as _HasRoomPosition).pos; } this._targetPos = derefRoomPosition(this._target._pos); } diff --git a/src/tasks/instances/drop.ts b/src/tasks/instances/drop.ts index b615552a9..54ab720fc 100644 --- a/src/tasks/instances/drop.ts +++ b/src/tasks/instances/drop.ts @@ -1,7 +1,7 @@ import {profile} from '../../profiler/decorator'; import {Task} from '../Task'; -export type dropTargetType = HasRef & HasPos | RoomPosition; +export type dropTargetType = HasRef & _HasRoomPosition | RoomPosition; export const dropTaskName = 'drop'; @profile diff --git a/src/zerg/AnyZerg.ts b/src/zerg/AnyZerg.ts index f8bd6b254..3d35aa6c7 100644 --- a/src/zerg/AnyZerg.ts +++ b/src/zerg/AnyZerg.ts @@ -332,7 +332,7 @@ export abstract class AnyZerg { // Movement and location ------------------------------------------------------------------------------------------- - goTo(destination: RoomPosition | HasPos, options: MoveOptions = {}) { + goTo(destination: RoomPosition | _HasRoomPosition, options: MoveOptions = {}) { return Movement.goTo(this, destination, options); } @@ -340,7 +340,7 @@ export abstract class AnyZerg { return Movement.goToRoom(this, roomName, options); } - inSameRoomAs(target: HasPos): boolean { + inSameRoomAs(target: _HasRoomPosition): boolean { return this.pos.roomName == target.pos.roomName; } @@ -360,7 +360,7 @@ export abstract class AnyZerg { /** * Kite around hostiles in the room */ - kite(avoidGoals: (RoomPosition | HasPos)[] = this.room.hostiles, options: MoveOptions = {}): number | undefined { + kite(avoidGoals: (RoomPosition | _HasRoomPosition)[] = this.room.hostiles, options: MoveOptions = {}): number | undefined { _.defaults(options, { fleeRange: 5 }); @@ -368,7 +368,7 @@ export abstract class AnyZerg { } private defaultFleeGoals() { - let fleeGoals: (RoomPosition | HasPos)[] = []; + let fleeGoals: (RoomPosition | _HasRoomPosition)[] = []; fleeGoals = fleeGoals.concat(this.room.hostiles) .concat(_.filter(this.room.keeperLairs, lair => (lair.ticksToSpawn || Infinity) < 10)); return fleeGoals; @@ -377,7 +377,7 @@ export abstract class AnyZerg { /** * Flee from hostiles in the room, while not repathing every tick // TODO: take a look at this */ - flee(avoidGoals: (RoomPosition | HasPos)[] = this.room.fleeDefaults, + flee(avoidGoals: (RoomPosition | _HasRoomPosition)[] = this.room.fleeDefaults, fleeOptions: FleeOptions = {}, moveOptions: MoveOptions = {}): boolean { if (avoidGoals.length == 0 || this.room.dangerousHostiles.find( diff --git a/src/zerg/NeuralZerg.ts b/src/zerg/NeuralZerg.ts index 13fbaea98..350ee4b74 100644 --- a/src/zerg/NeuralZerg.ts +++ b/src/zerg/NeuralZerg.ts @@ -41,7 +41,7 @@ export class NeuralZerg extends CombatZerg { return Movement.combatMove(this, [], avoid); } - maneuver(approachTargs: HasPos[], avoidTargs: HasPos[]) { + maneuver(approachTargs: _HasRoomPosition[], avoidTargs: _HasRoomPosition[]) { const approach = _.map(approachTargs, targ => ({pos: targ.pos, range: APPROACH_RANGE})); const avoid = _.map(avoidTargs, targ => ({pos: targ.pos, range: AVOID_RANGE})); return Movement.combatMove(this, approach, avoid); diff --git a/src/zerg/Swarm.ts b/src/zerg/Swarm.ts index 0ebe4b2f7..1d6ac1826 100644 --- a/src/zerg/Swarm.ts +++ b/src/zerg/Swarm.ts @@ -337,7 +337,7 @@ export class Swarm implements ProtoSwarm { // Range finding methods =========================================================================================== - minRangeTo(obj: RoomPosition | HasPos): number { + minRangeTo(obj: RoomPosition | _HasRoomPosition): number { if (hasPos(obj)) { return _.min(_.map(this.creeps, creep => creep.pos.roomName === obj.pos.roomName ? creep.pos.getRangeToXY(obj.pos.x, obj.pos.y) : Infinity)); @@ -347,7 +347,7 @@ export class Swarm implements ProtoSwarm { } } - maxRangeTo(obj: RoomPosition | HasPos): number { + maxRangeTo(obj: RoomPosition | _HasRoomPosition): number { if (hasPos(obj)) { return _.max(_.map(this.creeps, creep => creep.pos.roomName === obj.pos.roomName ? creep.pos.getRangeToXY(obj.pos.x, obj.pos.y) : Infinity)); @@ -357,7 +357,7 @@ export class Swarm implements ProtoSwarm { } } - findInMinRange(targets: HasPos[], range: number): HasPos[] { + findInMinRange(targets: _HasRoomPosition[], range: number): _HasRoomPosition[] { const initialRange = range + Math.max(this.width, this.height) - 1; const targetsInRange = _.filter(targets, t => this.anchor.inRangeToXY(t.pos.x, t.pos.y, initialRange)); return _.filter(targetsInRange, t => this.minRangeTo(t) <= range); @@ -366,7 +366,7 @@ export class Swarm implements ProtoSwarm { /** * Compute the "average" direction to a target */ - getDirectionTo(obj: RoomPosition | HasPos): DirectionConstant { + getDirectionTo(obj: RoomPosition | _HasRoomPosition): DirectionConstant { const pos = normalizePos(obj); const directions = _.map(this.creeps, creep => creep.pos.getDirectionTo(obj)); // TODO @@ -519,7 +519,7 @@ export class Swarm implements ProtoSwarm { return allMoved ? OK : ERR_NOT_ALL_OK; } - goTo(destination: RoomPosition | HasPos, options: SwarmMoveOptions = {}): number { + goTo(destination: RoomPosition | _HasRoomPosition, options: SwarmMoveOptions = {}): number { // if (DEBUG) { // options.displayCostMatrix = true; // } @@ -588,7 +588,7 @@ export class Swarm implements ProtoSwarm { } private getBestOrientation(room: Room, includeStructures = true, includeCreeps = false): TOP | RIGHT | BOTTOM | LEFT { - const targets: HasPos[] = []; + const targets: _HasRoomPosition[] = []; if (includeStructures) { const structureTargets = this.findInMinRange(room.hostileStructures, 1); for (const structure of structureTargets) { @@ -823,7 +823,7 @@ export class Swarm implements ProtoSwarm { /** * Groups enemies into proto-swarms based on proximity to each other */ - static findEnemySwarms(room: Room, anchor?: HasPos, maxClumpSize = 3): ProtoSwarm[] { + static findEnemySwarms(room: Room, anchor?: _HasRoomPosition, maxClumpSize = 3): ProtoSwarm[] { const enemySwarms: ProtoSwarm[] = []; const origin = anchor || _.first(room.spawns) || room.controller || {pos: new RoomPosition(25, 25, room.name)}; let attackers = _.sortBy(room.dangerousHostiles, creep => origin.pos.getRangeTo(creep)); From 08ba6cadbd3773ea0333a5d93e1dcea69aea99da Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Fri, 4 Aug 2023 16:45:23 +0200 Subject: [PATCH 38/41] Fix enough TS issues to have it build --- .eslintrc.cjs | 192 +++++++++++++++++++++++++++++++ package.json | 10 +- src/Colony.ts | 21 +++- src/assimilation/initializer.ts | 1 + src/caching/GlobalCache.ts | 13 ++- src/console/Console.ts | 82 ++++++++++--- src/console/globals.ts | 8 +- src/console/nukeManifest.ts | 13 +-- src/declarations/index.d.ts | 62 +++++----- src/declarations/memory.d.ts | 17 ++- src/directives/Directive.ts | 2 + src/main.ts | 7 +- src/matrix/MatrixLib.ts | 2 +- src/memory/Memory.ts | 14 ++- src/roomPlanner/RoomPlanner.ts | 6 +- src/stats/stats.ts | 4 +- src/utilities/Cartographer.ts | 2 +- src/utilities/packrat.ts | 16 +++ src/versionMigration/migrator.ts | 35 +++--- src/visuals/Visualizer.ts | 2 +- src/zerg/AnyZerg.ts | 22 ++-- src/zerg/PowerZerg.ts | 1 + tslint.json | 91 --------------- 23 files changed, 423 insertions(+), 200 deletions(-) create mode 100644 .eslintrc.cjs delete mode 100644 tslint.json diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 000000000..12be953bb --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,192 @@ +/* +👋 Hi! This file was autogenerated by tslint-to-eslint-config. +https://github.com/typescript-eslint/tslint-to-eslint-config + +It represents the closest reasonable ESLint configuration to this +project's original TSLint configuration. + +We recommend eventually switching this configuration to extend from +the recommended rulesets in typescript-eslint. +https://github.com/typescript-eslint/tslint-to-eslint-config/blob/master/docs/FAQs.md + +Happy linting! 💖 +*/ +module.exports = { + "env": { + "es6": true + }, + "extends": [ + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "prettier" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "tsconfig.json", + "sourceType": "module" + }, + "plugins": [ + "eslint-plugin-jsdoc", + "eslint-plugin-prefer-arrow", + "@typescript-eslint" + ], + "root": true, + "rules": { + "@typescript-eslint/adjacent-overload-signatures": "error", + "@typescript-eslint/array-type": "off", + "@typescript-eslint/ban-types": "off", + "@typescript-eslint/consistent-type-assertions": "off", + "@typescript-eslint/consistent-type-definitions": "off", + "@typescript-eslint/dot-notation": "error", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-member-accessibility": [ + "error", + { + "accessibility": "no-public" + } + ], + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/indent": [ + "off", + "tab" + ], + "@typescript-eslint/member-ordering": "off", + "@typescript-eslint/naming-convention": [ + "off", + { + "selector": "variable", + "format": [ + "camelCase", + "UPPER_CASE", + "PascalCase" + ], + "leadingUnderscore": "allow", + "trailingUnderscore": "forbid" + } + ], + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-empty-interface": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-misused-new": "error", + "@typescript-eslint/no-namespace": "error", + "@typescript-eslint/no-parameter-properties": "off", + "@typescript-eslint/no-shadow": [ + "off", + { + "hoist": "all" + } + ], + "@typescript-eslint/no-unused-expressions": "error", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-var-requires": "error", + "@typescript-eslint/prefer-for-of": "error", + "@typescript-eslint/prefer-function-type": "error", + "@typescript-eslint/prefer-namespace-keyword": "error", + "@typescript-eslint/triple-slash-reference": [ + "error", + { + "path": "always", + "types": "prefer-import", + "lib": "always" + } + ], + "@typescript-eslint/typedef": "off", + "@typescript-eslint/unified-signatures": "error", + "@typescript-eslint/no-namespace": "off", + "@typescript-eslint/no-base-to-string": "off", + "@typescript-eslint/restrict-template-expressions": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "arrow-parens": [ + "off", + "always" + ], + "brace-style": [ + "error", + "1tbs" + ], + "comma-dangle": "off", + "complexity": "off", + "constructor-super": "error", + "curly": [ + "error", + "multi-line" + ], + "dot-notation": "off", + "eqeqeq": [ + "off", + "always" + ], + "guard-for-in": "off", + "id-denylist": [ + "error", + "any", + "Number", + "number", + "String", + "string", + "Boolean", + "boolean", + "Undefined", + "undefined" + ], + "id-match": "error", + "indent": "off", + "jsdoc/check-alignment": "error", + "jsdoc/check-indentation": "error", + "max-classes-per-file": "off", + "max-len": [ + "error", + { + "code": 120 + } + ], + "new-parens": "error", + "no-bitwise": "off", + "no-caller": "error", + "no-cond-assign": "error", + "no-console": "off", + "no-debugger": "error", + "no-empty": "off", + "no-empty-function": "off", + "no-eval": "error", + "no-fallthrough": "off", + "no-invalid-this": "off", + "no-multiple-empty-lines": "off", + "no-new-wrappers": "error", + "no-shadow": "off", + "no-throw-literal": "error", + "no-trailing-spaces": "off", + "no-undef-init": "error", + "no-underscore-dangle": "off", + "no-unsafe-finally": "error", + "no-unused-expressions": "off", + "no-unused-labels": "error", + "no-use-before-define": "off", + "no-var": "error", + "object-shorthand": "off", + "one-var": [ + "off", + "never" + ], + "prefer-arrow/prefer-arrow-functions": "off", + "prefer-const": [ + "error", + { + "destructuring": "all" + } + ], + "quotes": "off", + "radix": "error", + "spaced-comment": [ + "error", + "always", + { + "markers": [ + "/" + ] + } + ], + "use-isnan": "error", + "valid-typeof": "off" + } +}; diff --git a/package.json b/package.json index a03aa9b4b..5d7282d77 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ }, "scripts": { "build": "tsc -p .", - "lint": "tslint \"src/**/*.ts\"", + "lint": "eslint \"src/**/*.ts\"", "clean": "rm -rf tsc-out && rm -rf dist", "obfuscate": "tsc && javascript-obfuscator tsc-out/Overmind.js --output src/Overmind_obfuscated.js --compact false --self-defending true --string-array true --string-array-threshold 1 --string-array-encoding true && javascript-obfuscator tsc-out/assimilation/Assimilator.js --output src/assimilation/Assimilator_obfuscated.js --compact false --self-defending true --string-array true --string-array-threshold 1 --string-array-encoding true", "compile": "rollup -c", @@ -23,6 +23,7 @@ "push-screepsplus": "rollup -c --environment DEST:screepsplus", "test": "npm run clean && npm run build" }, + "type": "module", "engines": { "node": ">= 18.9.1" }, @@ -32,11 +33,16 @@ "@types/columnify": "^1.5.1", "@types/lodash": "3.10.2", "@types/screeps": "^3.3.3", + "@typescript-eslint/eslint-plugin": "^6.3.0", + "@typescript-eslint/parser": "^6.3.0", + "eslint": "^8.46.0", + "eslint-config-prettier": "^8.10.0", + "eslint-plugin-jsdoc": "^46.4.5", + "eslint-plugin-prefer-arrow": "^1.2.3", "rollup": "^3.27.1", "rollup-plugin-progress": "^1.1.2", "rollup-plugin-screeps": "^1.0.1", "rollup-plugin-typescript2": "^0.35.0", - "tslint": "^6.1.3", "typedoc": "^0.24.8", "typescript": "^5.1.6" }, diff --git a/src/Colony.ts b/src/Colony.ts index 285e31b50..95ff48f91 100644 --- a/src/Colony.ts +++ b/src/Colony.ts @@ -62,7 +62,7 @@ export interface BunkerData { export interface ColonyMemory { defcon: { - level: number, + level: DEFCON, tick: number, }; expansionData: ColonyExpansionData; @@ -70,6 +70,22 @@ export interface ColonyMemory { outposts: { [roomName: string]: OutpostData }; suspend?: boolean; debug?: boolean; + persistent?: boolean; + evolutionChamber?: { + activeReaction: never; + reactionQueue: never; + status: never; + statusTick: never; + }; + roomPlanner?: { + lastGenerated: number; + }; + roadPlanner?: { + roadCoordsPacked: { [roomName: string]: string }; + }; + barrierPlanner?: { + barrierCoordsPacked: string; + } } // Outpost that is currently not being maintained @@ -233,7 +249,9 @@ export class Colony { } }); // Register colony globally to allow 'W1N1' and 'w1n1' to refer to Overmind.colonies.W1N1 + // @ts-expect-error global getter for Colonies global[this.name] = this; + // @ts-expect-error global getter for Colonies global[this.name.toLowerCase()] = this; // Build the colony this.build(roomName, outposts); @@ -635,6 +653,7 @@ export class Colony { const assetCreeps = [...this.getCreepsByRole(Roles.queen), ...this.getCreepsByRole(Roles.manager)]; const assetStores = _.map([...assetStructures, ...assetCreeps], thing => thing!.store); + // @ts-expect-error Store stuff const allAssets = mergeSum([...assetStores, ALL_ZERO_ASSETS]) as Assets; if (verbose) log.debug(`${this.room.print} assets: ` + JSON.stringify(allAssets)); diff --git a/src/assimilation/initializer.ts b/src/assimilation/initializer.ts index 0e93d9daa..439d40227 100644 --- a/src/assimilation/initializer.ts +++ b/src/assimilation/initializer.ts @@ -1,3 +1,4 @@ import _Assimilator from './Assimilator_obfuscated'; +// @ts-expect-error obfuscated global.Assimilator = new _Assimilator(); diff --git a/src/caching/GlobalCache.ts b/src/caching/GlobalCache.ts index d83600e8a..554ea03ef 100644 --- a/src/caching/GlobalCache.ts +++ b/src/caching/GlobalCache.ts @@ -31,6 +31,7 @@ export class $ { // $ = cash = cache... get it? :D return _cache.structures[cacheKey] as T[]; } + // eslint-disable-next-line static number(saver: { ref: string }, key: string, callback: () => number, timeout = SHORT_CACHE_TIMEOUT): number { const cacheKey = saver.ref + '#' + key; if (_cache.numbers[cacheKey] == undefined || Game.time > _cache.expiration[cacheKey]) { @@ -66,7 +67,7 @@ export class $ { // $ = cash = cache... get it? :D _cache.lists[cacheKey] = callback(); _cache.expiration[cacheKey] = getCacheExpiration(timeout, Math.ceil(timeout / 10)); } - return _cache.lists[cacheKey]; + return _cache.lists[cacheKey] as T[]; } /** @@ -100,7 +101,7 @@ export class $ { // $ = cash = cache... get it? :D static set(thing: T, key: K, callback: () => (T[K] & (undefined | _HasId | _HasId[])), timeout = CACHE_TIMEOUT): void { - const cacheKey = thing.ref + '$' + key; + const cacheKey = thing.ref + '$' + key; if (!_cache.things[cacheKey] || Game.time > _cache.expiration[cacheKey]) { // Recache if new entry or entry is expired _cache.things[cacheKey] = callback(); @@ -138,10 +139,12 @@ export class $ { // $ = cash = cache... get it? :D if (_.isObject(thing[key])) { for (const prop in thing[key]) { if (_.isArray(thing[key][prop])) { - thing[key][prop] = _.compact(_.map(thing[key][prop] as _HasId[], - s => Game.getObjectById(s.id))) as _HasId[]; + // @ts-expect-error + thing[key][prop] = <_HasId[]>_.compact(_.map(thing[key][prop] as _HasId[], + s => Game.getObjectById(s.id))); } else { - thing[key][prop] = Game.getObjectById((<_HasId>thing[key][prop]).id) as undefined | _HasId; + // @ts-expect-error + thing[key][prop] = <_HasId>Game.getObjectById((<_HasId>thing[key][prop]).id); } } } diff --git a/src/console/Console.ts b/src/console/Console.ts index 250ebd463..8b68a2c88 100644 --- a/src/console/Console.ts +++ b/src/console/Console.ts @@ -13,6 +13,51 @@ import {log} from './log'; type RecursiveObject = { [key: string]: number | RecursiveObject }; +declare global { + var help: string; + var info: () => string; + var notifications: () => string; + var debug: (obj: any) => string; + var stopDebug: (obj: any) => string; + var setMode: (mode: operationMode) => string; + var setSignature: (signature: string | undefined) => string | undefined; + var timeit: (cb: () => any, repeat?: number) => string; + var profileOverlord: (overlord: string | Overlord, ticks?: number | undefined) => string; + var finishProfilingOverlord: (overlord: string | Overlord) => string; + var setLogLevel: (value: number) => void; + var suspendColony: (roomName: string) => string; + var unsuspendColony: (roomName: string) => string; + var listSuspendedColonies: () => string; + var openRoomPlanner: (roomName: string) => string; + var closeRoomPlanner: (roomName: string) => string; + var cancelRoomPlanner: (roomName: string) => string; + var listActiveRoomPlanners: () => string; + var destroyErrantStructures: (roomName: string) => string; + var destroyAllHostileStructures: (roomName: string) => string; + var destroyAllBarriers: (roomName: string) => string; + var listConstructionSites: () => string; + var removeUnbuiltConstructionSites: () => string; + var listDirectives: () => string; + var listPersistentDirectives: () => string; + var removeAllLogisticsDirectives: () => string; + var removeFlagsByColor: (color: ColorConstant, secondaryColor: ColorConstant) => string; + var removeErrantFlags: () => string; + var deepCleanMemory: () => string; + var startRemoteDebugSession: () => string; + var endRemoteDebugSession: () => string; + var profileMemory: () => string; + var cancelMarketOrders: () => string; + var setRoomUpgradeRate: (roomName: string, rate: number) => string; + var getEmpireMineralDistribution: () => string; + var listPortals: () => string; + var evaluateOutpostEfficiencies: () => string; + var evaluatePotentialOutpostEfficiencies: () => string; +} + +interface MemoryDebug { + debug?: boolean; +} + /** * OvermindConsole registers a number of global methods for direct use in the Screeps console */ @@ -187,12 +232,12 @@ export class OvermindConsole { // Debugging methods =============================================================================================== - static debug(thing: { name?: string, ref?: string, memory: any }): string { + static debug(thing: { name?: string, ref?: string, memory: MemoryDebug }): string { thing.memory.debug = true; return `Enabled debugging for ${thing.name || thing.ref || '(no name or ref)'}.`; } - static stopDebug(thing: { name?: string, ref?: string, memory: any }): string { + static stopDebug(thing: { name?: string, ref?: string, memory: MemoryDebug }): string { delete thing.memory.debug; return `Disabled debugging for ${thing.name || thing.ref || '(no name or ref)'}.`; } @@ -210,8 +255,8 @@ export class OvermindConsole { static print(...args: any[]): string { let message = ''; for (const arg of args) { - let cache: any = []; - const msg = JSON.stringify(arg, function(key, value) { + let cache: any[] = []; + const msg = JSON.stringify(arg, function(key, value: any): any { if (typeof value === 'object' && value !== null) { if (cache.indexOf(value) !== -1) { // Duplicate reference found @@ -228,6 +273,7 @@ export class OvermindConsole { } return value; }, '\t'); + // @ts-expect-error Clear out the cache cache = null; message += '\n' + msg; } @@ -235,12 +281,12 @@ export class OvermindConsole { } static timeit(callback: () => any, repeat = 1): string { - let start, used, i: number; - start = Game.cpu.getUsed(); + const start = Game.cpu.getUsed(); + let i: number; for (i = 0; i < repeat; i++) { callback(); } - used = Game.cpu.getUsed() - start; + const used = Game.cpu.getUsed() - start; return `CPU used: ${used}. Repetitions: ${repeat} (${used / repeat} each).`; } @@ -256,7 +302,7 @@ export class OvermindConsole { } } - static finishProfilingOverlord(overlord: Overlord | string, ticks?: number): string { + static finishProfilingOverlord(overlord: Overlord | string): string { const overlordInstance = typeof overlord == 'string' ? Overmind.overlords[overlord] : overlord as Overlord | undefined; if (!overlordInstance) { @@ -358,7 +404,7 @@ export class OvermindConsole { (colony: Colony) => colony.roomPlanner.active); const names: string[] = _.map(coloniesWithActiveRoomPlanners, colony => colony.room.print); if (names.length > 0) { - console.log('Colonies with active room planners: ' + names); + console.log('Colonies with active room planners: ' + names.toString()); return ''; } else { return `No colonies with active room planners`; @@ -442,7 +488,7 @@ export class OvermindConsole { // Structure management ============================================================================================ static destroyErrantStructures(roomName: string): string { - const colony = Overmind.colonies[roomName] as Colony; + const colony = Overmind.colonies[roomName]; if (!colony) return `${roomName} is not a valid colony!`; const room = colony.room; const allStructures = room.find(FIND_STRUCTURES); @@ -493,7 +539,7 @@ export class OvermindConsole { return msg; } - // Colony Management ================================================================================================= + // Colony Management =============================================================================================== static setRoomUpgradeRate(roomName: string, rate: number): string { const colony: Colony = Overmind.colonies[roomName]; @@ -515,10 +561,9 @@ export class OvermindConsole { const colonies = getAllColonies(); const allPortals = colonies.map(colony => RoomIntel.findPortalsInRange(colony.name, rangeFromColonies)); let ret = `Empire Portal Census \n`; - for (const colonyId in allPortals) { - const portals = allPortals[colonyId]; + for (const [colonyId, portals] of Object.entries(allPortals)) { if (_.keys(portals).length > 0) { - ret += `Colony ${colonies[colonyId].print}: \n`; + ret += `Colony ${Overmind.colonies[colonyId].print}: \n`; } for (const portalRoomName of _.keys(portals)) { const samplePortal = _.first(portals[portalRoomName]); // don't need to list all 8 in a room @@ -588,7 +633,8 @@ export class OvermindConsole { for (const colName in Memory.colonies) { for (const key in Memory.colonies[colName]) { if (!protectedColonyKeys.includes(key)) { - delete (Memory.colonies[colName])[key]; + // @ts-expect-error direct property access + delete Memory.colonies[colName][key]; } } } @@ -602,8 +648,8 @@ export class OvermindConsole { delete Memory.screepsProfiler; // Remove overlords memory from flags for (const i in Memory.flags) { - if ((Memory.flags[i]).overlords) { - delete (Memory.flags[i]).overlords; + if (Memory.flags[i].overlords) { + delete Memory.flags[i].overlords; } } // Clean creep memory @@ -638,7 +684,7 @@ export class OvermindConsole { return JSON.stringify(sizes, undefined, '\t'); } - static cancelMarketOrders(filter?: (order: Order) => any): string { + static cancelMarketOrders(filter?: (order: Order) => boolean): string { const ordersToCancel = !!filter ? _.filter(Game.market.orders, order => filter(order)) : Game.market.orders; _.forEach(_.values(ordersToCancel), (order: Order) => Game.market.cancelOrder(order.id)); return `Canceled ${_.values(ordersToCancel).length} orders.`; diff --git a/src/console/globals.ts b/src/console/globals.ts index 07f944422..83cb22f2c 100644 --- a/src/console/globals.ts +++ b/src/console/globals.ts @@ -1,14 +1,10 @@ -declare const __VERSION__: string; global.__VERSION__ = '0.5.2'; -declare function deref(ref: string): RoomObject | null; - global.deref = function(ref: string): RoomObject | null { // dereference any object from identifier - return Game.getObjectById(ref) as any as RoomObject || Game.flags[ref] || Game.creeps[ref] || Game.spawns[ref] || null; + return Game.getObjectById(ref) as any as RoomObject + || Game.flags[ref] || Game.creeps[ref] || Game.spawns[ref] || null; }; -declare function derefRoomPosition(protoPos: ProtoPos): RoomPosition; - global.derefRoomPosition = function(protoPos: ProtoPos): RoomPosition { return new RoomPosition(protoPos.x, protoPos.y, protoPos.roomName); }; diff --git a/src/console/nukeManifest.ts b/src/console/nukeManifest.ts index 4f4d8cd73..715d63a0e 100644 --- a/src/console/nukeManifest.ts +++ b/src/console/nukeManifest.ts @@ -53,11 +53,9 @@ const launchPos = [ ]; export function verifyLaunchManifest() { - for (const i in launchFrom) { - const from = launchFrom[i]; + for (const [i, from] of launchFrom.entries()) { const to = launchTo[i]; - const [x, y] = launchPos[i]; - const nuker: StructureNuker = Overmind.colonies[from].commandCenter.nuker; + const nuker = Overmind.colonies[from].commandCenter?.nuker; if (Game.map.getRoomLinearDistance(from, to) > NUKE_RANGE) { log.info(`${from} to ${to} is out of range!`); @@ -71,13 +69,12 @@ export function verifyLaunchManifest() { } export function doomsdayLaunch() { - for (const i in launchFrom) { - const from = launchFrom[i]; + for (const [i, from] of launchFrom.entries()) { const to = launchTo[i]; const [x, y] = launchPos[i]; - const nuker: StructureNuker = Overmind.colonies[from].commandCenter.nuker; + const nuker = Overmind.colonies[from].commandCenter?.nuker; - if (nuker.cooldown == 0) { + if (nuker && nuker.cooldown == 0) { const pos = new RoomPosition(x, y, to); const ret = nuker.launchNuke(pos); log.alert(`[NUCLEAR LAUNCH] Launching nuke from ${from} to ${pos.print}! Result: ${ret}`); diff --git a/src/declarations/index.d.ts b/src/declarations/index.d.ts index f7db6537c..0d6b57e15 100644 --- a/src/declarations/index.d.ts +++ b/src/declarations/index.d.ts @@ -1,41 +1,51 @@ declare const require: (module: string) => any; -declare var global: any; -declare const MARKET_FEE: 300; // missing in the typed-screeps declarations -global.MARKET_FEE = MARKET_FEE; +declare const MARKET_FEE = 300; // missing in the typed-screeps declarations -declare const NO_ACTION: 1; -declare type NO_ACTION = NO_ACTION; -global.NO_ACTION = NO_ACTION; +declare type NO_ACTION = 1; +declare var NO_ACTION: NO_ACTION = 1; type TickPhase = 'assimilating' | 'build' | 'refresh' | 'init' | 'run' | 'postRun'; declare var PHASE: TickPhase; declare var LATEST_BUILD_TICK: number; declare var LATEST_GLOBAL_RESET_TICK: number; declare var LATEST_GLOBAL_RESET_DATE: Date; +declare var GLOBAL_AGE: number; -declare namespace NodeJS { - interface Global { +declare var __VERSION__: string; - age?: number; +declare function print(...args: any[]): string; +declare function deref(ref: string): RoomObject | null; +declare function derefRoomPosition(protoPos: ProtoPos): RoomPosition; +declare function gc(quick?: boolean): void; - _cache: IGlobalCache; +declare var _cache: IGlobalCache; - __VERSION__: string; +declare var PERMACACHE: { [key: string]: any }; - Overmind: IOvermind; +declare var __DEFAULT_OVERMIND_SIGNATURE__: string; - Assimilator: IAssimilator; +declare var remoteDebugger: import('debug/remoteDebugger').RemoteDebugger; - print(...args: any[]): string; +declare var Overmind: IOvermind; - deref(ref: string): RoomObject | null; +declare var Memory: Memory; +declare var Assimilator: IAssimilator; - derefRoomPosition(protoPos: ProtoPos): RoomPosition; +declare var Cartographer: import('utilities/Cartographer').Cartographer; +declare var Pathing: import('movement/Pathing').Pathing; +declare var RoomIntel: typeof import('intel/RoomIntel').RoomIntel; +declare var CombatIntel: typeof import('intel/CombatIntel').CombatIntel; +declare var GoalFinder: import('targeting/GoalFinder').GoalFinder; +declare var Abathur: import('resources/Abathur').Abathur; - gc(quick?: boolean): void; - } -} +declare var MatrixCache: import('matrix/MatrixLib').MatrixCache; +declare var MatrixLib: import('matrix/MatrixLib').MatrixLib; + +declare var PackratTests: import('utilities/packrat').PackratTests; + +declare var CombatCreepSetup: typeof import('creepSetups/CombatCreepSetup').CombatCreepSetup; +declare var DefaultCombatCreepSetups: {[type: string]: any }; // import('creepSetups/CombatCreepSetup').CombatCreepSetup } type Full = { [P in keyof T]-?: T[P]; @@ -113,8 +123,8 @@ interface IAssimilator { interface IOvermind { shouldBuild: boolean; expiration: number; - cache: ICache; // is actually GameCache - overseer: IOverseer; // is actually Overseer + cache: import('caching/GameCache').GameCache; + overseer: import('Overseer').Overseer; directives: { [flagName: string]: import('directives/Directive').Directive }; zerg: { [creepName: string]: import('zerg/Zerg').Zerg }; powerZerg: { [creepName: string]: import('zerg/PowerZerg').PowerZerg }; @@ -125,7 +135,7 @@ interface IOvermind { memory: IOvermindMemory; terminalNetwork: ITerminalNetwork; // is actually TerminalNetwork tradeNetwork: ITradeNetwork; // is actually TradeNetwork - expansionPlanner: IExpansionPlanner; + expansionPlanner: import('strategy/ExpansionPlanner').ExpansionPlanner; exceptions: Error[]; build(): void; @@ -242,14 +252,6 @@ interface ITradeNetwork { run(): void; } -declare var Overmind: IOvermind; - -declare var _cache: IGlobalCache; - -declare var PERMACACHE: { [key: string]: any }; - -declare function print(...args: any[]): void; - interface Coord { x: number; y: number; diff --git a/src/declarations/memory.d.ts b/src/declarations/memory.d.ts index e695b3118..5f5d1049c 100644 --- a/src/declarations/memory.d.ts +++ b/src/declarations/memory.d.ts @@ -16,13 +16,13 @@ interface RawMemory { interface Memory { tick: number; build: number; - assimilator: any; + assimilator: { users?: any }; Overmind: {}; profiler: any; overseer: any; segmenter: any; roomIntel: any; - colonies: { [name: string]: any }; + colonies: { [name: string]: import("Colony").ColonyMemory }; creeps: { [name: string]: CreepMemory; }; powerCreeps: {[name: string]: PowerCreepMemory}; flags: { [name: string]: FlagMemory; }; @@ -30,7 +30,17 @@ interface Memory { spawns: { [name: string]: SpawnMemory; }; pathing: PathingMemory; constructionSites: { [id: string]: number }; - stats: any; + stats: { + persistent:{ + lastGlobalReset?: number; + lastMemoryReset?: number; + globalAge?: number; + avgCPU?: number; + empireAge?: number; + build?: number; + }; + "cpu.heapStatistics"?: HeapStatistics; + }; // suspend?: number; resetBucket?: boolean; @@ -177,6 +187,7 @@ interface FlagMemory { [MEM.EXPIRATION]: number; incomplete?: boolean; }; + overlords?: any; debug?: boolean; amount?: number; persistent?: boolean; diff --git a/src/directives/Directive.ts b/src/directives/Directive.ts index 80f3301a2..06bd445f9 100644 --- a/src/directives/Directive.ts +++ b/src/directives/Directive.ts @@ -102,6 +102,7 @@ export abstract class Directive { } // Register directive on Overmind + // @ts-expect-error global shenanigans global[this.name] = this; Overmind.overseer.registerDirective(this); Overmind.directives[this.name] = this; @@ -312,6 +313,7 @@ export abstract class Directive { remove(force = false): OK | undefined { if (!this.memory.persistent || force) { delete Overmind.directives[this.name]; + // @ts-expect-error global shenanigans delete global[this]; Overmind.overseer.removeDirective(this); if (this.colony) { diff --git a/src/main.ts b/src/main.ts index 158135107..6a9280d78 100644 --- a/src/main.ts +++ b/src/main.ts @@ -56,8 +56,10 @@ function main(): void { // Instantiation operations: build or refresh the game state ------------------------------------------------------- if (!Overmind || Overmind.shouldBuild || Game.time >= Overmind.expiration) { PHASE = 'build'; + // @ts-expect-error global shenanigans delete global.Overmind; // Explicitly delete the old Overmind object - Mem.garbageCollect(true); // Run quick garbage collection + Mem.garbageCollect(true); // Run quick garbage collection + // @ts-expect-error obfuscated global.Overmind = new _Overmind(); // Instantiate the Overmind object Overmind.build(); // Build phase: instantiate all game components LATEST_BUILD_TICK = Game.time; // Record this tick as having a build reset @@ -86,7 +88,9 @@ function main(): void { function main_RL(): void { Mem.clean(); + // @ts-expect-error global shenanigans delete global.Overmind; + // @ts-expect-error obfuscated global.Overmind = new _Overmind(); ActionParser.run(); @@ -107,6 +111,7 @@ function onGlobalReset(): void { Assimilator.updateValidChecksumLedger(); } // Make a new Overmind object + // @ts-expect-error obfuscated global.Overmind = new _Overmind(); // Make a remote debugger global.remoteDebugger = new RemoteDebugger(); diff --git a/src/matrix/MatrixLib.ts b/src/matrix/MatrixLib.ts index c383b1ee4..c12124d39 100644 --- a/src/matrix/MatrixLib.ts +++ b/src/matrix/MatrixLib.ts @@ -52,7 +52,7 @@ export interface VolatileMatrixOptions { PERMACACHE.terrainMatrices = PERMACACHE.terrainMatrices || {}; -const MatrixCache: { +export const MatrixCache: { [hash: string]: { matrix: CostMatrix; generated: number; diff --git a/src/memory/Memory.ts b/src/memory/Memory.ts index 240070227..fd7cb5c5c 100644 --- a/src/memory/Memory.ts +++ b/src/memory/Memory.ts @@ -32,7 +32,7 @@ export function getAutonomyLevel(): number { } } -let lastMemory: any; +let lastMemory: Memory; let lastTime: number = 0; const MAX_BUCKET = 10000; @@ -93,14 +93,14 @@ export class Mem { */ static load() { if (lastTime && lastMemory && Game.time == lastTime + 1) { + // @ts-expect-error global shenanigans delete global.Memory; global.Memory = lastMemory; RawMemory._parsed = lastMemory; } else { - // noinspection BadExpressionStatementJS - /* tslint:disable:no-unused-expression */ + // eslint-disable-next-line Memory.rooms; // forces parsing - /* tslint:enable:no-unused-expression */ + // eslint-disable-next-line lastMemory = RawMemory._parsed; Memory.stats.persistent.lastMemoryReset = Game.time; } @@ -183,7 +183,7 @@ export class Mem { spawns : {}, pathing : {distances: {}}, constructionSites : {}, - stats : {}, + stats : {persistent:{}}, playerCreepTracker: {}, settings : { signature : DEFAULT_OVERMIND_SIGNATURE, @@ -249,6 +249,7 @@ export class Mem { Memory.build--; // don't count this reset as a build Game.cpu.halt(); } else if (Game.cpu.bucket < BUCKET_CLEAR_CACHE) { + // @ts-expect-error global shenanigans delete global._cache; this.initGlobalMemory(); } @@ -260,6 +261,7 @@ export class Mem { for (const name in Memory.creeps) { if (!Game.creeps[name]) { delete Memory.creeps[name]; + // @ts-expect-error global shenanigans delete global[name]; } } @@ -270,6 +272,7 @@ export class Mem { for (const name in Memory.flags) { if (!Game.flags[name]) { delete Memory.flags[name]; + // @ts-expect-error global shenanigans delete global[name]; } } @@ -283,6 +286,7 @@ export class Mem { // Delete only if "persistent" is not set - use case: praise rooms if (!Memory.colonies[name].persistent) { delete Memory.colonies[name]; + // @ts-expect-error global shenanigans delete global[name]; } } diff --git a/src/roomPlanner/RoomPlanner.ts b/src/roomPlanner/RoomPlanner.ts index f5f0e649a..e440827fe 100644 --- a/src/roomPlanner/RoomPlanner.ts +++ b/src/roomPlanner/RoomPlanner.ts @@ -593,7 +593,7 @@ export class RoomPlanner { // Recall the appropriate map this.recallMap(); - if (!this.map || this.map == {}) { // in case a map hasn't been generated yet + if (!this.map || _.isEmpty(this.map)) { // in case a map hasn't been generated yet log.info(this.colony.name + ' does not have a room plan yet! Unable to demolish errant structures.'); } @@ -653,7 +653,7 @@ export class RoomPlanner { log.info(`${this.colony.name}: waiting until storage is built to remove terminal`); return; } else if (this.colony.terminal && - _.sum(this.colony.terminal.store) - this.colony.terminal.energy > 1000) { + this.colony.terminal.store.getUsedCapacity() - this.colony.terminal.energy > 1000) { log.info(`${this.colony.name}: waiting on resources to evacuate before removing terminal`); return; } else if (this.colony.storage && @@ -718,7 +718,7 @@ export class RoomPlanner { let count = RoomPlanner.settings.maxSitesPerColony - this.colony.constructionSites.length; // Recall the appropriate map this.recallMap(); - if (!this.map || this.map == {}) { // in case a map hasn't been generated yet + if (!this.map || _.isEmpty(this.map)) { // in case a map hasn't been generated yet log.info(this.colony.name + ' does not have a room plan yet! Unable to build missing structures.'); } // Build missing structures from room plan diff --git a/src/stats/stats.ts b/src/stats/stats.ts index 7695896a7..0c9e7a834 100644 --- a/src/stats/stats.ts +++ b/src/stats/stats.ts @@ -17,6 +17,7 @@ export class Stats { ]; for (const key in Memory.stats) { if (!protectedKeys.includes(key)) { + // @ts-expect-error global shenaningans delete Memory.stats[key]; } } @@ -49,7 +50,8 @@ export class Stats { static run() { if (Game.time % LOG_STATS_INTERVAL == 0) { // Record IVM heap statistics - Memory.stats['cpu.heapStatistics'] = (Game.cpu).getHeapStatistics(); + if (Game.cpu.getHeapStatistics) + Memory.stats['cpu.heapStatistics'] = Game.cpu.getHeapStatistics(); // Log GCL this.log('gcl.progress', Game.gcl.progress); this.log('gcl.progressTotal', Game.gcl.progressTotal); diff --git a/src/utilities/Cartographer.ts b/src/utilities/Cartographer.ts index 352e1dcb1..4d017872c 100644 --- a/src/utilities/Cartographer.ts +++ b/src/utilities/Cartographer.ts @@ -58,7 +58,7 @@ export class Cartographer { } else { visited[roomName] = Math.min(depth, visited[roomName]); } - const neighbors = _.values(Game.map.describeExits(roomName)) as string[]; + const neighbors = _.values(Game.map.describeExits(roomName)); if (depth < maxDepth) { for (const neighbor of neighbors) { // Visit the neighbor if not already done or if this would be a more direct route diff --git a/src/utilities/packrat.ts b/src/utilities/packrat.ts index da6a5a7c0..9619a5129 100644 --- a/src/utilities/packrat.ts +++ b/src/utilities/packrat.ts @@ -335,6 +335,22 @@ export function unpackPosList(chars: string): RoomPosition[] { return posList; } +declare global { + var packId: any; + var unpackId: any; + var packIdList: any; + var unpackIdList: any; + var packCoord: any; + var unpackCoord: any; + var unpackCoordAsPos: any; + var packCoordList: any; + var unpackCoordList: any; + var unpackCoordListAsPosList: any; + var packPos: any; + var unpackPos: any; + var packPosList: any; + var unpackPosList: any; +} // Useful to register these functions on global diff --git a/src/versionMigration/migrator.ts b/src/versionMigration/migrator.ts index 081916c12..0bc084cb4 100644 --- a/src/versionMigration/migrator.ts +++ b/src/versionMigration/migrator.ts @@ -71,7 +71,7 @@ export class VersionMigration { static get memory(): VersionMigratorMemory { return Mem.wrap(Memory.Overmind, 'versionMigrator', () => ({ versions: {} - })); + })) as VersionMigratorMemory; } /* @@ -314,6 +314,7 @@ export class VersionMigration { for (const name in Memory.colonies) { for (const key in Memory.colonies[name]) { if (key.includes('miningSite@')) { + // @ts-expect-error migrated delete Memory.colonies[name][key]; } } @@ -356,10 +357,10 @@ export class VersionMigration { // Remove all orders for (const colonyName in Memory.colonies) { if (Memory.colonies[colonyName].evolutionChamber) { - delete Memory.colonies[colonyName].evolutionChamber.activeReaction; - delete Memory.colonies[colonyName].evolutionChamber.reactionQueue; - delete Memory.colonies[colonyName].evolutionChamber.status; - delete Memory.colonies[colonyName].evolutionChamber.statusTick; + delete Memory.colonies[colonyName].evolutionChamber?.activeReaction; + delete Memory.colonies[colonyName].evolutionChamber?.reactionQueue; + delete Memory.colonies[colonyName].evolutionChamber?.status; + delete Memory.colonies[colonyName].evolutionChamber?.statusTick; } } this.memory.versions['053to06X_part3'] = true; @@ -391,7 +392,7 @@ export class VersionMigration { for (const name in Memory.colonies) { if (Memory.colonies[name] && Memory.colonies[name].roomPlanner) { const rpmem = Memory.colonies[name].roomPlanner; - if (rpmem.lastGenerated && rpmem.lastGenerated < oldestTick) { + if (rpmem && rpmem.lastGenerated && rpmem.lastGenerated < oldestTick) { oldestTick = rpmem.lastGenerated; } } @@ -413,8 +414,10 @@ export class VersionMigration { delete Memory.zoneRooms; Memory.roomIntel = {}; // reset this - delete Memory.stats.persistent.terminalNetwork.transfers; - delete Memory.stats.persistent.terminalNetwork.costs; + // @ts-expect-error migrated + delete Memory.stats.persistent.terminalNetwork?.transfers; + // @ts-expect-error migrated + delete Memory.stats.persistent.terminalNetwork?.costs; const mem = Memory as any; @@ -438,8 +441,9 @@ export class VersionMigration { for (const name in Memory.colonies) { const colmem = Memory.colonies[name]; + // @ts-expect-error migrated delete colmem.abathur; // outdated - + // @ts-expect-error migrated delete colmem.expansionData; // bugged log.alert(`Migrating room planner memories...`); @@ -449,6 +453,7 @@ export class VersionMigration { if (colmem.roomPlanner) { for (const key in colmem.roomPlanner) { if (!validRoomPlannerMemKeys.includes(key)) { + // @ts-expect-error migrated delete colmem.roomPlanner[key]; } } @@ -457,14 +462,16 @@ export class VersionMigration { // Migrate road planner to new format log.alert(`Migrating road planner memories...`); if (colmem.roadPlanner) { - if (colmem.roadPlanner.roadLookup) { - const roadLookup = colmem.roadPlanner.roadLookup; + // @ts-expect-error migration + const roadLookup = colmem.roadPlanner.roadLookup; + if (roadLookup) { const roadCoordsPacked: { [roomName: string]: string } = {}; for (const roomName in roadLookup) { const roadCoords = _.map(_.keys(roadLookup[roomName]), coordName => derefCoords(coordName)); roadCoordsPacked[roomName] = packCoordList(roadCoords); } colmem.roadPlanner.roadCoordsPacked = roadCoordsPacked; + // @ts-expect-error migration delete colmem.roadPlanner.roadLookup; } } @@ -472,10 +479,12 @@ export class VersionMigration { // Migrate barrier planner to new format log.alert(`Migrating barrier planner memories...`); if (colmem.barrierPlanner) { - if (colmem.barrierPlanner.barrierLookup) { - const barrierLookup = colmem.barrierPlanner.barrierLookup; + // @ts-expect-error migration + const barrierLookup = colmem.barrierPlanner.barrierLookup; + if (barrierLookup) { const barrierCoords = _.map(_.keys(barrierLookup), coordName => derefCoords(coordName)); colmem.barrierPlanner.barrierCoordsPacked = packCoordList(barrierCoords); + // @ts-expect-error migration delete colmem.barrierPlanner.barrierLookup; } } diff --git a/src/visuals/Visualizer.ts b/src/visuals/Visualizer.ts index e1a45bd0c..23391bfd5 100644 --- a/src/visuals/Visualizer.ts +++ b/src/visuals/Visualizer.ts @@ -315,7 +315,7 @@ export class Visualizer { static drawGraphs(): void { this.text(`CPU`, {x: 1, y: 7}); - this.barGraph(Memory.stats.persistent.avgCPU / Game.cpu.limit, {x: 2.75, y: 7}); + this.barGraph((Memory.stats.persistent.avgCPU ?? 0) / Game.cpu.limit, {x: 2.75, y: 7}); this.text(`BKT`, {x: 1, y: 8}); this.barGraph(Game.cpu.bucket / 10000, {x: 2.75, y: 8}); this.text(`GCL`, {x: 1, y: 9}); diff --git a/src/zerg/AnyZerg.ts b/src/zerg/AnyZerg.ts index 3d35aa6c7..2ed86b94a 100644 --- a/src/zerg/AnyZerg.ts +++ b/src/zerg/AnyZerg.ts @@ -137,6 +137,7 @@ export abstract class AnyZerg { this.blockMovement = false; // Register global references // Overmind.zerg[this.name] = this; + // @ts-expect-error Global getter for Zergs global[this.name] = this; // Handle attack notification when at lifetime - 1 if (!notifyWhenAttacked && (this.ticksToLive || 0) >= this.lifetime - (NEW_OVERMIND_INTERVAL + 1)) { @@ -171,7 +172,7 @@ export abstract class AnyZerg { // this._task = null; } else { log.debug(`Deleting ${this.print} from global`); - // delete Overmind.zerg[this.name]; + // @ts-expect-error Global getter for Zergs delete global[this.name]; } } @@ -240,7 +241,8 @@ export abstract class AnyZerg { return this.creep.suicide(); } - transfer(target: AnyCreep | AnyZerg | Structure, resourceType: ResourceConstant = RESOURCE_ENERGY, amount?: number) { + transfer(target: AnyCreep | AnyZerg | Structure, + resourceType: ResourceConstant = RESOURCE_ENERGY, amount?: number) { let result: ScreepsReturnCode; if (isAnyZerg(target)) { result = this.creep.transfer(target.creep, resourceType, amount); @@ -251,7 +253,7 @@ export abstract class AnyZerg { return result; } - transferAll(target: AnyCreep | AnyZerg | Structure, amount?: number) { + transferAll(target: AnyCreep | AnyZerg | Structure) { for (const [resourceType, amount] of this.creep.store.contents) { if (amount > 0) { return this.transfer(target, resourceType); @@ -309,7 +311,7 @@ export abstract class AnyZerg { */ get colony(): Colony | null { if (this.memory[MEM.COLONY] != null) { - return Overmind.colonies[this.memory[MEM.COLONY] as string]; + return Overmind.colonies[this.memory[MEM.COLONY]]; } else { return null; } @@ -353,14 +355,15 @@ export abstract class AnyZerg { } get isMoving(): boolean { - const moveData = this.memory._go as MoveData | undefined; + const moveData = this.memory._go; return (!!moveData && !!moveData.path && moveData.path.length > 1) || this.actionLog[MOVE]; } /** * Kite around hostiles in the room */ - kite(avoidGoals: (RoomPosition | _HasRoomPosition)[] = this.room.hostiles, options: MoveOptions = {}): number | undefined { + kite(avoidGoals: (RoomPosition | _HasRoomPosition)[] = this.room.hostiles, + options: MoveOptions = {}): number | undefined { _.defaults(options, { fleeRange: 5 }); @@ -449,9 +452,8 @@ export abstract class AnyZerg { // Like 99.999% of the time this will be the case if (this.colony && Game.map.getRoomLinearDistance(this.room.name, this.colony.name) <= maxLinearRange) { fallback = this.colony.name; - } - // But this could happen if the creep was working remotely through a portal - else { + } else { + // But this could happen if the creep was working remotely through a portal const nearbyColonies = _.filter(getAllColonies(), colony => Game.map.getRoomLinearDistance(this.room.name, colony.name) <= maxLinearRange); const closestColony = minBy(nearbyColonies, colony => { @@ -516,7 +518,7 @@ export abstract class AnyZerg { /** * Moves off of an exit tile */ - moveOffExit(towardPos?: RoomPosition, avoidSwamp = true): ScreepsReturnCode { + moveOffExit(towardPos?: RoomPosition, avoidSwamp = true): ScreepsReturnCode | NO_ACTION { return Movement.moveOffExit(this, towardPos, avoidSwamp); } diff --git a/src/zerg/PowerZerg.ts b/src/zerg/PowerZerg.ts index 19d8436d5..caa6afd71 100644 --- a/src/zerg/PowerZerg.ts +++ b/src/zerg/PowerZerg.ts @@ -81,6 +81,7 @@ export abstract class PowerZerg extends AnyZerg { } else { log.debug(`Deleting ${this.print} from global`); delete Overmind.powerZerg[this.name]; + // @ts-expect-error global getter for PowerZergs delete global[this.name]; } } diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 0e2eb347b..000000000 --- a/tslint.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "extends": [ - "tslint:recommended" - ], - "linterOptions": { - "exclude": [ - "src/deprecated/*.ts", - "node_modules/**/*" - ] - }, - "rules": { - "align": false, - "array-type": false, - "arrow-parens": false, - "ban-types": false, - "curly": [ - true, - "ignore-same-line" - ], - "forin": false, - "indent": [ - true, - "tabs", - 4 - ], - "interface-name": false, - "interface-over-type-literal": false, - "jsdoc-format": [ - true, - "check-multiline-start" - ], - "object-literal-sort-keys": false, - "one-line": [ - true, - "check-catch", - "check-finally", - // "check-else", // putting else on a different line is sometimes useful - "check-open-brace", - "check-whitespace" - ], - "one-variable-per-declaration": false, - "only-arrow-functions": false, - "max-classes-per-file": false, - "max-line-length": [ - true, - 120 - ], - "member-access": [ - true, - "no-public" - ], - "member-ordering": [ - false - ], - "no-angle-bracket-type-assertion": false, - "no-consecutive-blank-lines": false, - "no-console": [ - false - ], - "no-empty": false, - "no-empty-interface": false, - "no-namespace": [ - true, - "allow-declarations" - ], - "no-shadowed-variable": false, - "no-trailing-whitespace": false, - "object-literal-shorthand": false, - "prefer-const": [ - true, - { - "destructuring": "all" - } - ], - "quotemark": [ - true, - "single" - // I recognize the irony here - ], - "trailing-comma": false, - "triple-equals": false, - "variable-name": [ - true, - "ban-keywords", - "check-format", - "allow-pascal-case", - "allow-leading-underscore" - ], - "whitespace": false - } -} From 222c613b4a94d5f74dd0e9348c9b13fe7613dac4 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Fri, 4 Aug 2023 21:01:07 +0200 Subject: [PATCH 39/41] Update everything to the new Store interface --- src/declarations/prototypes.d.ts | 39 +---- src/deprecated/TerminalNetwork.ts | 14 +- src/directives/colony/poisonRoom.ts | 2 +- src/directives/situational/stronghold.ts | 4 +- src/hiveClusters/commandCenter.ts | 4 +- src/hiveClusters/hatchery.ts | 2 +- src/hiveClusters/sporeCrawler.ts | 4 +- src/hiveClusters/upgradeSite.ts | 2 +- src/logistics/Energetics.ts | 4 +- src/logistics/LogisticsNetwork.ts | 32 ++-- src/logistics/RoadLogistics.ts | 4 +- src/logistics/TerminalNetwork_v2.ts | 4 +- src/overlords/colonization/pioneer.ts | 2 +- src/overlords/colonization/roomPoisoner.ts | 2 +- src/overlords/core/manager.ts | 10 +- src/overlords/core/queen.ts | 8 +- src/overlords/core/queen_bunker.ts | 10 +- src/overlords/core/transporter.ts | 4 +- src/overlords/core/upgrader.ts | 2 +- src/overlords/core/worker.ts | 2 +- src/overlords/mining/miner.ts | 40 ++--- src/overlords/powerMining/PowerHauler.ts | 16 +- src/overlords/situational/bootstrap.ts | 2 +- src/overlords/situational/hauler.ts | 22 +-- src/overlords/situational/remoteUpgrader.ts | 20 +-- src/overlords/~template/templateOverlord.ts | 4 +- src/prototypes/Structures.ts | 180 +++++--------------- src/tasks/instances/build.ts | 2 +- src/tasks/instances/drop.ts | 2 +- src/tasks/instances/fortify.ts | 2 +- src/tasks/instances/generateSafeMode.ts | 2 +- src/tasks/instances/harvest.ts | 2 +- src/tasks/instances/pickup.ts | 2 +- src/tasks/instances/recharge.ts | 2 +- src/tasks/instances/repair.ts | 2 +- src/tasks/instances/transfer.ts | 2 +- src/tasks/instances/transferAll.ts | 6 +- src/tasks/instances/upgrade.ts | 2 +- src/tasks/instances/withdraw.ts | 2 +- src/tasks/instances/withdrawAll.ts | 4 +- src/zerg/AnyZerg.ts | 14 +- src/zerg/PowerZerg.ts | 2 - src/zerg/Zerg.ts | 4 +- 43 files changed, 180 insertions(+), 311 deletions(-) diff --git a/src/declarations/prototypes.d.ts b/src/declarations/prototypes.d.ts index 3cb8effb0..857ea96f0 100644 --- a/src/declarations/prototypes.d.ts +++ b/src/declarations/prototypes.d.ts @@ -247,12 +247,17 @@ interface Structure { isWalkable: boolean; } -interface StructureContainer { +interface _StoreLike { energy: number; isFull: boolean; isEmpty: boolean; } +interface StructureContainer extends _StoreLike {} +interface StructureExtension extends _StoreLike {} +interface StructureLink extends _StoreLike {} +interface StructureStorage extends _StoreLike {} + interface StructureController { reservedByMe: boolean; signedByMe: boolean; @@ -261,46 +266,20 @@ interface StructureController { needsReserving(reserveBuffer: number): boolean; } -interface StructureExtension { - isFull: boolean; - isEmpty: boolean; -} - -interface StructureLink { - isFull: boolean; - isEmpty: boolean; - storeCapacity: number; -} - -interface StructureStorage { - energy: number; - isFull: boolean; - isEmpty: boolean; -} - interface StoreBase { contents: [ResourceConstant, number][]; } -interface StructureSpawn { - isFull: boolean; - isEmpty: boolean; - +interface StructureSpawn extends _StoreLike { cost(bodyArray: string[]): number; } -interface StructureTerminal { - energy: any; - isFull: boolean; - isEmpty: boolean; +interface StructureTerminal extends _StoreLike { isReady: boolean; hasReceived: boolean; } -interface StructureTower { - isFull: boolean; - isEmpty: boolean; - +interface StructureTower extends _StoreLike { // run(): void; // // attackNearestEnemy(): number; diff --git a/src/deprecated/TerminalNetwork.ts b/src/deprecated/TerminalNetwork.ts index a60f360b1..8c4a1b7d7 100644 --- a/src/deprecated/TerminalNetwork.ts +++ b/src/deprecated/TerminalNetwork.ts @@ -117,7 +117,7 @@ export class TerminalNetwork /*implements ITerminalNetwork*/ { this.exceptionTerminals = {}; // populated in init() this.assets = {}; // populated in init() this.notifications = []; - this.averageFullness = _.sum(this.terminals, t => _.sum(t.store) / t.storeCapacity) / this.terminals.length; + this.averageFullness = _.sum(this.terminals, t => t.store.getUsedCapacity() / t.store.getCapacity()) / this.terminals.length; } refresh(): void { @@ -131,7 +131,7 @@ export class TerminalNetwork /*implements ITerminalNetwork*/ { this.exceptionTerminals = {}; // populated in init() this.assets = {}; // populated in init() this.notifications = []; - this.averageFullness = _.sum(this.terminals, t => _.sum(t.store) / t.storeCapacity) / this.terminals.length; + this.averageFullness = _.sum(this.terminals, t => t.store.getUsedCapacity() / t.store.getCapacity()) / this.terminals.length; } /* Summarizes the total of all resources currently in a colony store structure */ @@ -174,10 +174,10 @@ export class TerminalNetwork /*implements ITerminalNetwork*/ { private remainingRoomCapacity(room: Room): number { let remainingCapacity = 0; if (room.storage) { - remainingCapacity += room.storage.storeCapacity - _.sum(room.storage.store); + remainingCapacity += room.storage.store.getFreeCapacity(); } if (room.terminal) { - remainingCapacity += room.terminal.storeCapacity - _.sum(room.terminal.store); + remainingCapacity += room.terminal.store.getFreeCapacity(); } return remainingCapacity; } @@ -362,7 +362,7 @@ export class TerminalNetwork /*implements ITerminalNetwork*/ { sendAmount = Math.floor(Math.max(sendAmount, 0)); const sendCost = Game.market.calcTransactionCost(sendAmount, sender.room.name, receiver.room.name); sendAmount = Math.min(sendAmount, (sender.store[resourceType] || 0) - sendCost - 10, - (receiver.storeCapacity - _.sum(receiver.store))); + (receiver.store.getFreeCapacity())); if (sendAmount < TERMINAL_MIN_SEND) { if (verbose) log.debug(` Size too small`); @@ -437,7 +437,7 @@ export class TerminalNetwork /*implements ITerminalNetwork*/ { // Terminal output state - push resources away from this colony if (state.type == 'out' || state.type == 'in/out') { if (terminal.cooldown == 0 && amount > targetAmount + tolerance) { - const receiver = minBy(this.terminals, t => _.sum(t.store)); + const receiver = minBy(this.terminals, t => t.store.getUsedCapacity()); if (receiver) { let sendAmount: number; if (resource == RESOURCE_ENERGY) { @@ -446,7 +446,7 @@ export class TerminalNetwork /*implements ITerminalNetwork*/ { } else { sendAmount = minMax(amount - targetAmount, TERMINAL_MIN_SEND, maxSendSize); } - if (receiver.storeCapacity - _.sum(receiver.store) > sendAmount) { + if (receiver.store.getFreeCapacity() >= sendAmount) { this.transfer(terminal, receiver, resource, sendAmount, 'exception state out'); return; } diff --git a/src/directives/colony/poisonRoom.ts b/src/directives/colony/poisonRoom.ts index 316cbe4da..c7a2323d2 100644 --- a/src/directives/colony/poisonRoom.ts +++ b/src/directives/colony/poisonRoom.ts @@ -138,7 +138,7 @@ export class DirectivePoisonRoom extends Directive { } // Don't lock off the last position unless there's a creep with energy to build the site const enoughEnergyToBuildFinalWall = _.any(this.overlords.roomPoisoner.roomPoisoners, - creep => creep.carry.energy >= BUILD_POWER); + creep => creep.store.energy >= BUILD_POWER); if (this.blockPositions.length == 1 && !enoughEnergyToBuildFinalWall) { return; } diff --git a/src/directives/situational/stronghold.ts b/src/directives/situational/stronghold.ts index 050cdfd50..8da402cf1 100644 --- a/src/directives/situational/stronghold.ts +++ b/src/directives/situational/stronghold.ts @@ -88,10 +88,10 @@ export class DirectiveStronghold extends Directive { const ruins = this.room.ruins; if (containers) { returns = returns.concat(containers.filter(container => - container.pos.getRangeTo(this.pos) < 5 && _.sum(container.store) > 0)); + container.pos.getRangeTo(this.pos) < 5 && container.store.getUsedCapacity() > 0)); } if (ruins) { - returns = returns.concat(ruins.filter(ruin => ruin.pos.getRangeTo(this.pos) <= 3 && _.sum(ruin.store) > 0)); + returns = returns.concat(ruins.filter(ruin => ruin.pos.getRangeTo(this.pos) <= 3 && ruin.store.getUsedCapacity() > 0)); } return returns; } diff --git a/src/hiveClusters/commandCenter.ts b/src/hiveClusters/commandCenter.ts index 950345f78..2e5eb0c5b 100644 --- a/src/hiveClusters/commandCenter.ts +++ b/src/hiveClusters/commandCenter.ts @@ -238,13 +238,13 @@ export class CommandCenter extends HiveCluster { y = titleCoords.y + 0.25; if (this.storage) { Visualizer.text('Storage', {x: boxX, y: y, roomName: this.room.name}); - Visualizer.barGraph(_.sum(this.storage.store) / this.storage.storeCapacity, + Visualizer.barGraph(this.storage.store.getUsedCapacity() / this.storage.store.getCapacity(), {x: boxX + 4, y: y, roomName: this.room.name}, 5); y += 1; } if (this.terminal) { Visualizer.text('Terminal', {x: boxX, y: y, roomName: this.room.name}); - Visualizer.barGraph(_.sum(this.terminal.store) / this.terminal.storeCapacity, + Visualizer.barGraph(this.terminal.store.getUsedCapacity() / this.terminal.store.getCapacity(), {x: boxX + 4, y: y, roomName: this.room.name}, 5); y += 1; } diff --git a/src/hiveClusters/hatchery.ts b/src/hiveClusters/hatchery.ts index 0fbd7a069..95c273cfe 100644 --- a/src/hiveClusters/hatchery.ts +++ b/src/hiveClusters/hatchery.ts @@ -220,7 +220,7 @@ export class Hatchery extends HiveCluster { } if (this.battery) { const threshold = this.colony.stage == ColonyStage.Larva ? 0.75 : 0.5; - if (this.battery.energy < threshold * this.battery.storeCapacity) { + if (this.battery.store.getUsedCapacity() < threshold * this.battery.store.getCapacity()) { this.colony.logisticsNetwork.requestInput(this.battery, {multiplier: 1.5}); } // get rid of any minerals in the container if present diff --git a/src/hiveClusters/sporeCrawler.ts b/src/hiveClusters/sporeCrawler.ts index 20c629f8e..f6fba05d0 100644 --- a/src/hiveClusters/sporeCrawler.ts +++ b/src/hiveClusters/sporeCrawler.ts @@ -40,8 +40,8 @@ export class SporeCrawler extends HiveCluster { private registerEnergyRequests() { // Request energy from transporters if below request threshold for (const tower of this.towers) { - if (tower.energy < SporeCrawler.settings.requestThreshold) { - const multiplier = tower.energy < SporeCrawler.settings.criticalEnergyThreshold ? 2 : 1; + if (tower.store[RESOURCE_ENERGY] < SporeCrawler.settings.requestThreshold) { + const multiplier = tower.store[RESOURCE_ENERGY] < SporeCrawler.settings.criticalEnergyThreshold ? 2 : 1; const dAmountdt = this.room.hostiles.length > 0 ? 10 : 0; this.colony.logisticsNetwork.requestInput(tower, {multiplier: multiplier, dAmountdt: dAmountdt}); } diff --git a/src/hiveClusters/upgradeSite.ts b/src/hiveClusters/upgradeSite.ts index d390c9ab8..c7e70c891 100644 --- a/src/hiveClusters/upgradeSite.ts +++ b/src/hiveClusters/upgradeSite.ts @@ -124,7 +124,7 @@ export class UpgradeSite extends HiveCluster { } const inThreshold = this.colony.stage > ColonyStage.Larva ? 0.5 : 0.75; if (this.battery) { - if (this.battery.energy < inThreshold * this.battery.storeCapacity) { + if (this.battery.energy < inThreshold * this.battery.store.getCapacity()) { const energyPerTick = UPGRADE_CONTROLLER_POWER * this.upgradePowerNeeded; this.colony.logisticsNetwork.requestInput(this.battery, {dAmountdt: energyPerTick}); } diff --git a/src/logistics/Energetics.ts b/src/logistics/Energetics.ts index fb1b46cae..1fe192f24 100644 --- a/src/logistics/Energetics.ts +++ b/src/logistics/Energetics.ts @@ -32,8 +32,8 @@ export class Energetics { static lowPowerMode(colony: Colony): boolean { if (colony.stage == ColonyStage.Adult) { - if (_.sum(colony.storage!.store) > this.settings.storage.total.cap && - colony.terminal && _.sum(colony.terminal.store) > this.settings.terminal.total.cap) { + if (colony.storage!.store.getUsedCapacity() > this.settings.storage.total.cap && + colony.terminal && colony.terminal.store.getUsedCapacity() > this.settings.terminal.total.cap) { return true; } } diff --git a/src/logistics/LogisticsNetwork.ts b/src/logistics/LogisticsNetwork.ts index 739cd3c05..faa92e047 100644 --- a/src/logistics/LogisticsNetwork.ts +++ b/src/logistics/LogisticsNetwork.ts @@ -169,7 +169,7 @@ export class LogisticsNetwork { dAmountdt : 0, }); if (opts.resourceType == 'all' && !isResource(target)) { - if (_.sum(target.store) == target.store.energy) { + if (target.store.getUsedCapacity() == target.store.energy) { opts.resourceType = RESOURCE_ENERGY; // convert "all" requests to energy if that's all they have } } @@ -294,8 +294,8 @@ export class LogisticsNetwork { if (requestID) { const request = this.requests[requestID]; if (request) { - const carry = transporter.carry as { [resourceType: string]: number }; - const remainingCapacity = transporter.carryCapacity - _.sum(carry); + const carry = transporter.store; + const remainingCapacity = carry.getFreeCapacity() const resourceAmount = -1 * this.predictedRequestAmount(transporter, request, nextAvailability); // ^ need to multiply amount by -1 since transporter is doing complement of what request needs if (request.resourceType == 'all') { @@ -304,9 +304,9 @@ export class LogisticsNetwork { return {energy: 0} as StoreDefinition; } for (const [resourceType, storeAmt] of request.target.store.contents) { - const resourceFraction = storeAmt / _.sum(request.target.store); + const resourceFraction = storeAmt / (request.target.store.getUsedCapacity(resourceType) || storeAmt); if (carry[resourceType]) { - carry[resourceType]! += resourceAmount * resourceFraction; + carry[resourceType] += resourceAmount * resourceFraction; carry[resourceType] = minMax(carry[resourceType]!, 0, remainingCapacity); } else { carry[resourceType] = minMax(resourceAmount, 0, remainingCapacity); @@ -324,7 +324,7 @@ export class LogisticsNetwork { } } } - return transporter.carry; + return transporter.store; } /** @@ -371,7 +371,7 @@ export class LogisticsNetwork { predictedAmount = minMax(predictedAmount, 0, request.target.store.getCapacity(request.resourceType)); } const resourceInflux = _.sum(_.map(otherTargetingTransporters, - other => (other.carry[request.resourceType] || 0))); + other => (other.store[request.resourceType] || 0))); predictedAmount = Math.max(predictedAmount - resourceInflux, 0); return predictedAmount; } else { // output state, resources withdrawn from target @@ -386,7 +386,7 @@ export class LogisticsNetwork { predictedAmount = minMax(predictedAmount, -1 * request.target.store.getCapacity(request.resourceType), 0); } const resourceOutflux = _.sum(_.map(otherTargetingTransporters, - other => other.carryCapacity - _.sum(other.carry))); + other => other.store.getCapacity() - other.store.getUsedCapacity())); predictedAmount = Math.min(predictedAmount + resourceOutflux, 0); return predictedAmount; } @@ -411,7 +411,7 @@ export class LogisticsNetwork { carry = this.predictedTransporterCarry(transporter); } else { // If you are targeting the requestor, use current carry for computations - carry = transporter.carry; + carry = transporter.store; } if (amount > 0) { // requestInput instance, needs refilling if (request.resourceType == 'all') { @@ -428,12 +428,12 @@ export class LogisticsNetwork { dt : dt_direct, targetRef: request.target.ref }); - if ((carry[request.resourceType] || 0) > amount || _.sum(carry) == transporter.carryCapacity) { + if ((carry[request.resourceType] || 0) > amount || _.sum(carry) == transporter.store.getCapacity()) { return choices; // Return early if you already have enough resources to go direct or are already full } // Change in resources if transporter picks up resources from a buffer first for (const buffer of this.buffers) { - const dQ_buffer = Math.min(amount, transporter.carryCapacity, buffer.store[request.resourceType] || 0); + const dQ_buffer = Math.min(amount, transporter.store.getCapacity(), buffer.store[request.resourceType] || 0); const dt_buffer = newPos.getMultiRoomRangeTo(buffer.pos) * LogisticsNetwork.settings.rangeToPathHeuristic + (Pathing.distance(buffer.pos, request.target.pos) || Infinity) + ticksUntilFree; choices.push({ @@ -444,7 +444,7 @@ export class LogisticsNetwork { } } else if (amount < 0) { // requestOutput instance, needs pickup // Change in resources if transporter goes straight to the output - const remainingCarryCapacity = transporter.carryCapacity - _.sum(carry); + const remainingCarryCapacity = transporter.store.getCapacity() - _.sum(carry); const dQ_direct = Math.min(Math.abs(amount), remainingCarryCapacity); const dt_direct = newPos.getMultiRoomRangeTo(request.target.pos) * LogisticsNetwork.settings.rangeToPathHeuristic + ticksUntilFree; @@ -453,13 +453,13 @@ export class LogisticsNetwork { dt : dt_direct, targetRef: request.target.ref }); - if (remainingCarryCapacity >= Math.abs(amount) || remainingCarryCapacity == transporter.carryCapacity) { + if (remainingCarryCapacity >= Math.abs(amount) || remainingCarryCapacity == transporter.store.getCapacity()) { return choices; // Return early you have sufficient free space or are empty } // Change in resources if transporter drops off resources at a buffer first for (const buffer of this.buffers) { - const dQ_buffer = Math.min(Math.abs(amount), transporter.carryCapacity, - buffer.storeCapacity - _.sum(buffer.store)); + const dQ_buffer = Math.min(Math.abs(amount), transporter.store.getCapacity(), + buffer.store.getFreeCapacity()); const dt_buffer = newPos.getMultiRoomRangeTo(buffer.pos) * LogisticsNetwork.settings.rangeToPathHeuristic + (Pathing.distance(buffer.pos, request.target.pos) || Infinity) + ticksUntilFree; choices.push({ @@ -578,7 +578,7 @@ export class LogisticsNetwork { } else { if (request.resourceType == 'all') { if (!isResource(request.target)) { - amount = _.sum(request.target.store); + amount = request.target.store.getUsedCapacity() || 0; } else { amount = -0.001; } diff --git a/src/logistics/RoadLogistics.ts b/src/logistics/RoadLogistics.ts index b08f41252..af9980f03 100644 --- a/src/logistics/RoadLogistics.ts +++ b/src/logistics/RoadLogistics.ts @@ -47,7 +47,7 @@ export class RoadLogistics { return this.repairableRoads(room).length > 0; } else { // If worker is not already assigned, repair if critical roads or repaving energy >= carry capacity - return this.criticalRoads(room).length > 0 || this.energyToRepave(room.name) >= worker.carryCapacity; + return this.criticalRoads(room).length > 0 || this.energyToRepave(room.name) >= worker.store.getCapacity(); } } else { return false; @@ -164,7 +164,7 @@ export class RoadLogistics { } buildPavingManifest(worker: Zerg, room: Room): Task | null { - let energy = worker.carry.energy; + let energy = worker.store.energy; const targetRefs: { [ref: string]: boolean } = {}; const tasks: Task[] = []; let target: StructureRoad | undefined; diff --git a/src/logistics/TerminalNetwork_v2.ts b/src/logistics/TerminalNetwork_v2.ts index f04e92eed..537cafe3c 100644 --- a/src/logistics/TerminalNetwork_v2.ts +++ b/src/logistics/TerminalNetwork_v2.ts @@ -422,8 +422,8 @@ export class TerminalNetworkV2 implements ITerminalNetwork { private getRemainingSpace(colony: Colony, includeFactoryCapacity = false): number { let totalAssets = _.sum(colony.assets); // Overfilled storage gets counted as just 100% full - if (colony.storage && _.sum(colony.storage.store) > STORAGE_CAPACITY) { - totalAssets -= (_.sum(colony.storage.store) - STORAGE_CAPACITY); + if (colony.storage && colony.storage.store.getUsedCapacity() > STORAGE_CAPACITY) { + totalAssets -= (colony.storage.store.getUsedCapacity() - STORAGE_CAPACITY); } const roomCapacity = (colony.terminal ? TERMINAL_CAPACITY : 0) + diff --git a/src/overlords/colonization/pioneer.ts b/src/overlords/colonization/pioneer.ts index d08bd3641..3b77378c5 100644 --- a/src/overlords/colonization/pioneer.ts +++ b/src/overlords/colonization/pioneer.ts @@ -57,7 +57,7 @@ export class PioneerOverlord extends Overlord { } } // Build and recharge - if (pioneer.carry.energy == 0) { + if (pioneer.store.energy == 0) { pioneer.task = Tasks.recharge(); } else if (this.room && this.room.controller && (this.room.controller.ticksToDowngrade < (0.1 * CONTROLLER_DOWNGRADE[this.room.controller.level]) diff --git a/src/overlords/colonization/roomPoisoner.ts b/src/overlords/colonization/roomPoisoner.ts index ddee7c6a0..69fb24e22 100644 --- a/src/overlords/colonization/roomPoisoner.ts +++ b/src/overlords/colonization/roomPoisoner.ts @@ -45,7 +45,7 @@ export class RoomPoisonerOverlord extends Overlord { private handleRoomPoisoner(posioner: Zerg): void { // Recharge if needed - if (posioner.carry.energy < BUILD_POWER) { + if (posioner.store.energy < BUILD_POWER) { posioner.task = Tasks.recharge(); return; } diff --git a/src/overlords/core/manager.ts b/src/overlords/core/manager.ts index d38345a96..69e7804ea 100644 --- a/src/overlords/core/manager.ts +++ b/src/overlords/core/manager.ts @@ -136,7 +136,7 @@ export class CommandCenterOverlord extends Overlord { if (manager.store.getUsedCapacity() == 0) { return false; } else { - manager.debug(`Unloading carry: ${JSON.stringify(manager.carry)}`); + manager.debug(`Unloading carry: ${JSON.stringify(manager.store)}`); manager.task = Tasks.transferAll(this.commandCenter.storage); // placeholder solution return true; } @@ -150,7 +150,7 @@ export class CommandCenterOverlord extends Overlord { manager.debug('supplyActions'); const request = this.commandCenter.transportRequests.getPrioritizedClosestRequest(manager.pos, 'supply'); if (request) { - const amount = Math.min(request.amount, manager.carryCapacity); + const amount = Math.min(request.amount, manager.store.getCapacity()); const resource = request.resourceType; // If we have enough to fulfill the request, we're done if (manager.store[request.resourceType] >= amount) { @@ -254,7 +254,7 @@ export class CommandCenterOverlord extends Overlord { } const transferAmount = Math.min(terminal.store[resource] - target, storage.store.getFreeCapacity(resource), - manager.carryCapacity); + manager.store.getCapacity()); manager.task = Tasks.chain([Tasks.withdraw(terminal, resource, transferAmount), Tasks.transfer(storage, resource, transferAmount)]); // manager.debug(`Assigned task ${print(manager.task)}`) @@ -269,7 +269,7 @@ export class CommandCenterOverlord extends Overlord { } const transferAmount = Math.min(target - terminal.store[resource], storage.store[resource], - manager.carryCapacity); + manager.store.getCapacity()); manager.task = Tasks.chain([Tasks.withdraw(storage, resource, transferAmount), Tasks.transfer(terminal, resource, transferAmount)]); // manager.debug(`Assigned task ${print(manager.task)}`) @@ -543,7 +543,7 @@ export class CommandCenterOverlord extends Overlord { manager.debug('idleActions'); if (this.mode == 'bunker' && this.managerRepairTarget && manager.getActiveBodyparts(WORK) > 0) { // Repair ramparts when idle - if (manager.carry.energy > 0) { + if (manager.store.energy > 0) { manager.repair(this.managerRepairTarget); } else { const storage = this.commandCenter.storage; diff --git a/src/overlords/core/queen.ts b/src/overlords/core/queen.ts index b5147ebcf..dae1265de 100644 --- a/src/overlords/core/queen.ts +++ b/src/overlords/core/queen.ts @@ -67,13 +67,13 @@ export class QueenOverlord extends Overlord { // Can energy be moved from the link to the battery? if (this.hatchery.battery && !this.hatchery.battery.isFull && !this.hatchery.link.isEmpty) { // Move energy to battery as needed - if (queen.carry.energy < queen.carryCapacity) { + if (queen.store.energy < queen.store.getCapacity()) { queen.task = Tasks.withdraw(this.hatchery.link); } else { queen.task = Tasks.transfer(this.hatchery.battery); } } else { - if (queen.carry.energy < queen.carryCapacity) { // make sure you're recharged + if (queen.store.energy < queen.store.getCapacity()) { // make sure you're recharged if (!this.hatchery.link.isEmpty) { queen.task = Tasks.withdraw(this.hatchery.link); } else if (this.hatchery.battery && !this.hatchery.battery.isEmpty) { @@ -82,14 +82,14 @@ export class QueenOverlord extends Overlord { } } } else { - if (this.hatchery.battery && queen.carry.energy < queen.carryCapacity) { + if (this.hatchery.battery && queen.store.energy < queen.store.getCapacity()) { queen.task = Tasks.withdraw(this.hatchery.battery); } } } private handleQueen(queen: Zerg): void { - if (queen.carry.energy > 0) { + if (queen.store.energy > 0) { this.supplyActions(queen); } else { this.rechargeActions(queen); diff --git a/src/overlords/core/queen_bunker.ts b/src/overlords/core/queen_bunker.ts index b44746abc..8f0dfaeb0 100644 --- a/src/overlords/core/queen_bunker.ts +++ b/src/overlords/core/queen_bunker.ts @@ -128,7 +128,7 @@ export class BunkerQueenOverlord extends Overlord { let tasks: Task[] = []; // Step 1: empty all contents (this shouldn't be necessary since queen is normally empty at this point) let queenPos = queen.pos; - if (_.sum(queen.carry) > 0) { + if (queen.store.getUsedCapacity() > 0) { const transferTarget = this.colony.terminal || this.colony.storage || this.batteries[0]; if (transferTarget) { tasks.push(Tasks.transferAll(transferTarget)); @@ -153,7 +153,7 @@ export class BunkerQueenOverlord extends Overlord { const supplyTasks: Task[] = []; for (const request of supplyRequests) { // stop when carry will be full - const remainingAmount = queen.carryCapacity - _.sum(queenCarry); + const remainingAmount = queen.store.getCapacity() - _.sum(queenCarry); if (remainingAmount == 0) break; // figure out how much you can withdraw let amount = Math.min(request.amount, remainingAmount); @@ -222,7 +222,7 @@ export class BunkerQueenOverlord extends Overlord { const tasks: Task[] = []; const transferTarget = this.colony.terminal || this.colony.storage || this.batteries[0]; // Step 1: empty all contents (this shouldn't be necessary since queen is normally empty at this point) - if (_.sum(queen.carry) > 0) { + if (queen.store.getUsedCapacity() > 0) { if (transferTarget) { tasks.push(Tasks.transferAll(transferTarget)); } else { @@ -244,7 +244,7 @@ export class BunkerQueenOverlord extends Overlord { } for (const request of withdrawRequests) { // stop when carry will be full - const remainingAmount = queen.carryCapacity - _.sum(queenCarry); + const remainingAmount = queen.store.getCapacity() - _.sum(queenCarry); if (remainingAmount == 0) break; // figure out how much you can withdraw const amount = Math.min(request.amount, remainingAmount); @@ -320,7 +320,7 @@ export class BunkerQueenOverlord extends Overlord { // Do we need safemodes? else if (this.colony.level > 5 && this.colony.controller.safeModeAvailable < 3 && this.colony.terminal && this.colony.terminal.store[RESOURCE_GHODIUM] >= 1000 && - queen.carryCapacity >= 1000) { + queen.store.getCapacity() >= 1000) { // Only use 1 queen to avoid adding 2 safemodes if (queen.name == _.first(_.sortBy(this.queens, q => q.name)).name) { queen.task = Tasks.chain([ diff --git a/src/overlords/core/transporter.ts b/src/overlords/core/transporter.ts index 64536e2db..f87c4df29 100644 --- a/src/overlords/core/transporter.ts +++ b/src/overlords/core/transporter.ts @@ -99,7 +99,7 @@ export class TransportOverlord extends Overlord { // If we need to go to a buffer first to get more stuff const buffer = deref(bestChoice.targetRef) as BufferTarget; const withdrawAmount = Math.min(buffer.store[request.resourceType] || 0, - transporter.carryCapacity - _.sum(transporter.carry), amount); + transporter.store.getFreeCapacity(request.resourceType), amount); task = task.fork(Tasks.withdraw(buffer, request.resourceType, withdrawAmount)); if (transporter.hasMineralsInCarry && request.resourceType == RESOURCE_ENERGY) { task = task.fork(Tasks.transferAll(buffer)); @@ -135,7 +135,7 @@ export class TransportOverlord extends Overlord { this.colony.logisticsNetwork.invalidateCache(transporter, request); } else { // If nothing to do, put everything in a store structure - if (_.sum(transporter.carry) > 0) { + if (transporter.store.getUsedCapacity() > 0) { if (transporter.hasMineralsInCarry) { const target = this.colony.terminal || this.colony.storage; if (target) { diff --git a/src/overlords/core/upgrader.ts b/src/overlords/core/upgrader.ts index 5891c3d0c..6bc052fe8 100644 --- a/src/overlords/core/upgrader.ts +++ b/src/overlords/core/upgrader.ts @@ -51,7 +51,7 @@ export class UpgradingOverlord extends Overlord { } private handleUpgrader(upgrader: Zerg): void { - if (upgrader.carry.energy > 0) { + if (upgrader.store.energy > 0) { // Repair link if (this.upgradeSite.link && this.upgradeSite.link.hits < this.upgradeSite.link.hitsMax) { upgrader.task = Tasks.repair(this.upgradeSite.link); diff --git a/src/overlords/core/worker.ts b/src/overlords/core/worker.ts index 297c32875..e6d60f477 100644 --- a/src/overlords/core/worker.ts +++ b/src/overlords/core/worker.ts @@ -349,7 +349,7 @@ export class WorkerOverlord extends Overlord { } private handleWorker(worker: Zerg) { - if (worker.carry.energy > 0) { + if (worker.store.energy > 0) { // TODO Add high priority to block controller with ramparts/walls in case of downgrade attack // FIXME workers get stalled at controller in case of downgrade attack // Upgrade controller if close to downgrade or if getting controller attacked/was downgraded diff --git a/src/overlords/mining/miner.ts b/src/overlords/mining/miner.ts index 8b3fcb118..c2831fd09 100644 --- a/src/overlords/mining/miner.ts +++ b/src/overlords/mining/miner.ts @@ -308,7 +308,7 @@ export class MiningOverlord extends Overlord { if (this.container) { const transportCapacity = 200 * this.colony.level; const threshold = this.colony.stage > ColonyStage.Larva ? 0.8 : 0.5; - if (_.sum(this.container.store) > threshold * transportCapacity) { + if (this.container.store.getUsedCapacity() > threshold * transportCapacity) { this.colony.logisticsNetwork.requestOutput(this.container, { resourceType: 'all', dAmountdt : this.energyPerTick @@ -318,7 +318,7 @@ export class MiningOverlord extends Overlord { if (this.link) { // If the link will be full with next deposit from the miner const minerCapacity = 150; - if (this.link.energy + minerCapacity > this.link.energyCapacity) { + if (this.link.store.getUsedCapacity(RESOURCE_ENERGY) + minerCapacity > this.link.store.getCapacity(RESOURCE_ENERGY)) { this.colony.linkNetwork.requestTransmit(this.link); } } @@ -342,10 +342,10 @@ export class MiningOverlord extends Overlord { // Container mining if (this.container) { if (this.container.hits < this.container.hitsMax - && miner.carry.energy >= Math.min(miner.carryCapacity, REPAIR_POWER * miner.getActiveBodyparts(WORK))) { + && miner.store.energy >= Math.min(miner.store.getCapacity(), REPAIR_POWER * miner.getActiveBodyparts(WORK))) { return miner.goRepair(this.container); } else { - if (_.sum(miner.carry) < miner.carryCapacity) { + if (miner.store.getUsedCapacity(RESOURCE_ENERGY) < miner.store.getCapacity()) { return miner.goHarvest(this.source!); } else { return miner.goTransfer(this.container); @@ -355,7 +355,7 @@ export class MiningOverlord extends Overlord { // Build output site if (this.constructionSite) { - if (miner.carry.energy >= Math.min(miner.carryCapacity, BUILD_POWER * miner.getActiveBodyparts(WORK))) { + if (miner.store.energy >= Math.min(miner.store.getCapacity(), BUILD_POWER * miner.getActiveBodyparts(WORK))) { return miner.goBuild(this.constructionSite); } else { return miner.goHarvest(this.source!); @@ -365,7 +365,7 @@ export class MiningOverlord extends Overlord { // Drop mining if (this.allowDropMining) { miner.goHarvest(this.source!); - if (miner.carry.energy > 0.8 * miner.carryCapacity) { // try to drop on top of largest drop if full + if (miner.store.energy > 0.8 * miner.store.getCapacity()) { // try to drop on top of largest drop if full const biggestDrop = maxBy(miner.pos.findInRange(miner.room.droppedEnergy, 1), drop => drop.amount); if (biggestDrop) { miner.goDrop(biggestDrop.pos, RESOURCE_ENERGY); @@ -410,7 +410,7 @@ export class MiningOverlord extends Overlord { if (res == ERR_NOT_IN_RANGE) { // approach mining site if (this.goToMiningSite(miner)) return; } - if (miner.carry.energy > 0.9 * miner.carryCapacity) { + if (miner.store.energy > 0.9 * miner.store.getCapacity()) { miner.transfer(this.link, RESOURCE_ENERGY); } // If for whatever reason there's no reciever link, you can get stuck in a bootstrapping loop, so @@ -444,7 +444,7 @@ export class MiningOverlord extends Overlord { // Container mining if (this.container) { if (this.container.hits < this.container.hitsMax - && miner.carry.energy >= Math.min(miner.carryCapacity, REPAIR_POWER * miner.getActiveBodyparts(WORK))) { + && miner.store.energy >= Math.min(miner.store.getCapacity(), REPAIR_POWER * miner.getActiveBodyparts(WORK))) { return miner.repair(this.container); } else { return this.harvestOrSleep(miner, source); @@ -453,7 +453,7 @@ export class MiningOverlord extends Overlord { // Build output site if (this.constructionSite) { // standard miners won't have both a container and a construction site - if (miner.carry.energy >= Math.min(miner.carryCapacity, BUILD_POWER * miner.getActiveBodyparts(WORK))) { + if (miner.store.energy >= Math.min(miner.store.getCapacity(), BUILD_POWER * miner.getActiveBodyparts(WORK))) { return miner.build(this.constructionSite); } else { return this.harvestOrSleep(miner, source); @@ -463,13 +463,13 @@ export class MiningOverlord extends Overlord { // Drop mining if (this.allowDropMining) { this.harvestOrSleep(miner, source); - if (miner.carry.energy > 0.8 * miner.carryCapacity) { // move over the drop when you're close to full + if (miner.store.energy > 0.8 * miner.store.getCapacity()) { // move over the drop when you're close to full const biggestDrop = maxBy(miner.pos.findInRange(miner.room.droppedEnergy, 1), drop => drop.amount); if (biggestDrop) { miner.goTo(biggestDrop); } } - if (miner.carry.energy == miner.carryCapacity) { // drop when you are full + if (miner.store.energy == miner.store.getCapacity()) { // drop when you are full miner.drop(RESOURCE_ENERGY); } return; @@ -492,7 +492,7 @@ export class MiningOverlord extends Overlord { // Container mining if (this.container) { if (this.container.hits < this.container.hitsMax - && miner.carry.energy >= Math.min(miner.carryCapacity, REPAIR_POWER * miner.getActiveBodyparts(WORK))) { + && miner.store.energy >= Math.min(miner.store.getCapacity(), REPAIR_POWER * miner.getActiveBodyparts(WORK))) { return miner.repair(this.container); } else { return this.harvestOrSleep(miner, source); @@ -501,7 +501,7 @@ export class MiningOverlord extends Overlord { // Build output site if (this.constructionSite) { // standard miners won't have both a container and a construction site - if (miner.carry.energy >= Math.min(miner.carryCapacity, BUILD_POWER * miner.getActiveBodyparts(WORK))) { + if (miner.store.energy >= Math.min(miner.store.getCapacity(), BUILD_POWER * miner.getActiveBodyparts(WORK))) { return miner.build(this.constructionSite); } else { return this.harvestOrSleep(miner, source); @@ -511,13 +511,13 @@ export class MiningOverlord extends Overlord { // Drop mining if (this.allowDropMining) { this.harvestOrSleep(miner, source); - if (miner.carry.energy > 0.8 * miner.carryCapacity) { // move over the drop when you're close to full + if (miner.store.energy > 0.8 * miner.store.getCapacity()) { // move over the drop when you're close to full const biggestDrop = maxBy(miner.pos.findInRange(miner.room.droppedEnergy, 1), drop => drop.amount); if (biggestDrop) { miner.goTo(biggestDrop); } } - if (miner.carry.energy == miner.carryCapacity) { // drop when you are full + if (miner.store.energy == miner.store.getCapacity()) { // drop when you are full miner.drop(RESOURCE_ENERGY); } return; @@ -539,7 +539,7 @@ export class MiningOverlord extends Overlord { } else { miner.harvest(this.secondSource!); } - if (miner.carry.energy > 0.9 * miner.carryCapacity) { + if (miner.store.energy > 0.9 * miner.store.getCapacity()) { miner.transfer(this.link, RESOURCE_ENERGY); } return; @@ -550,7 +550,7 @@ export class MiningOverlord extends Overlord { // Container mining if (this.container) { if (this.container.hits < this.container.hitsMax - && miner.carry.energy >= Math.min(miner.carryCapacity, REPAIR_POWER * miner.getActiveBodyparts(WORK))) { + && miner.store.energy >= Math.min(miner.store.getCapacity(), REPAIR_POWER * miner.getActiveBodyparts(WORK))) { return miner.repair(this.container); } else if (this.source && this.source.energy > 0) { return miner.harvest(this.source!); @@ -561,7 +561,7 @@ export class MiningOverlord extends Overlord { // Build output site if (this.constructionSite) { - if (miner.carry.energy >= Math.min(miner.carryCapacity, BUILD_POWER * miner.getActiveBodyparts(WORK))) { + if (miner.store.energy >= Math.min(miner.store.getCapacity(), BUILD_POWER * miner.getActiveBodyparts(WORK))) { return miner.build(this.constructionSite); } else { return miner.harvest(this.source!); @@ -571,13 +571,13 @@ export class MiningOverlord extends Overlord { // Drop mining if (this.allowDropMining) { miner.harvest(this.source!); - if (miner.carry.energy > 0.8 * miner.carryCapacity) { // move over the drop when you're close to full + if (miner.store.energy > 0.8 * miner.store.getCapacity()) { // move over the drop when you're close to full const biggestDrop = maxBy(miner.pos.findInRange(miner.room.droppedEnergy, 1), drop => drop.amount); if (biggestDrop) { miner.goTo(biggestDrop); } } - if (miner.carry.energy == miner.carryCapacity) { // drop when you are full + if (miner.store.energy == miner.store.getCapacity()) { // drop when you are full miner.drop(RESOURCE_ENERGY); } return; diff --git a/src/overlords/powerMining/PowerHauler.ts b/src/overlords/powerMining/PowerHauler.ts index f9800e5c4..bea5921f6 100644 --- a/src/overlords/powerMining/PowerHauler.ts +++ b/src/overlords/powerMining/PowerHauler.ts @@ -45,7 +45,7 @@ export class PowerHaulingOverlord extends Overlord { } private handleHauler(hauler: Zerg) { - if (_.sum(hauler.carry) == 0) { + if (hauler.store.getUsedCapacity() === 0) { if (this.directive.memory.state >= 4) { // FIXME: Maybe ditch this and put it as a separate on-finishing method to reassign hauler.say('💀 RIP 💀', true); @@ -96,22 +96,22 @@ export class PowerHaulingOverlord extends Overlord { } else { // Travel to colony room and deposit resources if (hauler.inSameRoomAs(this.colony)) { - for (const [resourceType, amount] of hauler.carry.contents) { + for (const [resourceType, amount] of hauler.store.contents) { if (amount == 0) continue; if (resourceType == RESOURCE_ENERGY) { // prefer to put energy in storage - if (this.colony.storage && _.sum(this.colony.storage.store) < STORAGE_CAPACITY) { + if (this.colony.storage && this.colony.storage.store.getUsedCapacity() < STORAGE_CAPACITY) { hauler.task = Tasks.transfer(this.colony.storage, resourceType); return; - } else if (this.colony.terminal && _.sum(this.colony.terminal.store) < TERMINAL_CAPACITY) { + } else if (this.colony.terminal && this.colony.terminal.store.getUsedCapacity() < TERMINAL_CAPACITY) { hauler.task = Tasks.transfer(this.colony.terminal, resourceType); return; } } else { // prefer to put minerals in terminal - this.directive.memory.totalCollected += hauler.carry.power || 0; - if (this.colony.terminal && _.sum(this.colony.terminal.store) < TERMINAL_CAPACITY) { + this.directive.memory.totalCollected += hauler.store.power || 0; + if (this.colony.terminal && this.colony.terminal.store.getUsedCapacity() < TERMINAL_CAPACITY) { hauler.task = Tasks.transfer(this.colony.terminal, resourceType); return; - } else if (this.colony.storage && _.sum(this.colony.storage.store) < STORAGE_CAPACITY) { + } else if (this.colony.storage && this.colony.storage.store.getUsedCapacity() < STORAGE_CAPACITY) { hauler.task = Tasks.transfer(this.colony.storage, resourceType); return; } @@ -126,7 +126,7 @@ export class PowerHaulingOverlord extends Overlord { } checkIfStillCarryingPower() { - return _.find(this.haulers, hauler => hauler.carry.power != undefined && hauler.carry.power > 0); + return _.find(this.haulers, hauler => hauler.store.power != undefined && hauler.store.power > 0); } run() { diff --git a/src/overlords/situational/bootstrap.ts b/src/overlords/situational/bootstrap.ts index d51d759e0..72f2d56fa 100644 --- a/src/overlords/situational/bootstrap.ts +++ b/src/overlords/situational/bootstrap.ts @@ -134,7 +134,7 @@ export class BootstrappingOverlord extends Overlord { } private handleFiller(filler: Zerg) { - if (filler.carry.energy > 0) { + if (filler.store.energy > 0) { this.supplyActions(filler); } else { this.rechargeActions(filler); diff --git a/src/overlords/situational/hauler.ts b/src/overlords/situational/hauler.ts index 289488f04..d00ca5f66 100644 --- a/src/overlords/situational/hauler.ts +++ b/src/overlords/situational/hauler.ts @@ -28,7 +28,7 @@ export class HaulingOverlord extends Overlord { } init() { - if (!this.colony.storage || _.sum(this.colony.storage.store) > Energetics.settings.storage.total.cap) { + if (!this.colony.storage || this.colony.storage.store.getUsedCapacity() > Energetics.settings.storage.total.cap) { return; } // Spawn a number of haulers sufficient to move all resources within a lifetime, up to a max @@ -36,8 +36,8 @@ export class HaulingOverlord extends Overlord { // Calculate total needed amount of hauling power as (resource amount * trip distance) const tripDistance = 2 * (Pathing.distance((this.colony.storage || this.colony).pos, this.directive.pos) || 0); const haulingPowerNeeded = Math.min(this.directive.totalResources, - this.colony.storage.storeCapacity - - _.sum(this.colony.storage.store)) * tripDistance; + this.colony.storage.store.getCapacity() + - this.colony.storage.store.getUsedCapacity()) * tripDistance; // Calculate amount of hauling each hauler provides in a lifetime const haulerCarryParts = Setups.transporters.early.getBodyPotential(CARRY, this.colony); const haulingPowerPerLifetime = CREEP_LIFE_TIME * haulerCarryParts * CARRY_CAPACITY; @@ -52,7 +52,7 @@ export class HaulingOverlord extends Overlord { } private handleHauler(hauler: Zerg) { - if (_.sum(hauler.carry) == 0) { + if (hauler.store.getUsedCapacity() == 0) { // Travel to directive and collect resources if (hauler.inSameRoomAs(this.directive)) { // Pick up drops first @@ -76,7 +76,7 @@ export class HaulingOverlord extends Overlord { hauler.task = Tasks.withdraw(this.directive.storeStructure, resourceType); } totalDrawn += store[resourceType]; - if (totalDrawn >= hauler.carryCapacity) { + if (totalDrawn >= hauler.store.getCapacity()) { return; } } @@ -97,22 +97,22 @@ export class HaulingOverlord extends Overlord { // Travel to colony room and deposit resources if (hauler.inSameRoomAs(this.colony)) { // Put energy in storage and minerals in terminal if there is one - for (const [resourceType, amount] of hauler.carry.contents) { + for (const [resourceType, amount] of hauler.store.contents) { if (amount == 0) continue; if (resourceType == RESOURCE_ENERGY) { // prefer to put energy in storage - if (this.colony.storage && _.sum(this.colony.storage.store) < STORAGE_CAPACITY) { + if (this.colony.storage && this.colony.storage.store.getUsedCapacity() < STORAGE_CAPACITY) { hauler.task = Tasks.transfer(this.colony.storage, resourceType); return; - } else if (this.colony.terminal && _.sum(this.colony.terminal.store) < TERMINAL_CAPACITY) { + } else if (this.colony.terminal && this.colony.terminal.store.getUsedCapacity() < TERMINAL_CAPACITY) { hauler.task = Tasks.transfer(this.colony.terminal, resourceType); return; } } else { // prefer to put minerals in terminal if (this.colony.terminal && this.colony.terminal.my - && _.sum(this.colony.terminal.store) < TERMINAL_CAPACITY) { + && this.colony.terminal.store.getUsedCapacity() < TERMINAL_CAPACITY) { hauler.task = Tasks.transfer(this.colony.terminal, resourceType); return; - } else if (this.colony.storage && _.sum(this.colony.storage.store) < STORAGE_CAPACITY) { + } else if (this.colony.storage && this.colony.storage.store.getUsedCapacity() < STORAGE_CAPACITY) { hauler.task = Tasks.transfer(this.colony.storage, resourceType); return; } @@ -134,7 +134,7 @@ export class HaulingOverlord extends Overlord { hauler.run(); } // TODO: fix the way this is done - if (this.directive.memory.totalResources == 0 && this.haulers.filter(hauler => _.sum(hauler.carry) > 0).length == 0) { + if (this.directive.memory.totalResources == 0 && this.haulers.filter(hauler => hauler.store.getUsedCapacity() > 0).length == 0) { this.directive.remove(); } } diff --git a/src/overlords/situational/remoteUpgrader.ts b/src/overlords/situational/remoteUpgrader.ts index cb1d8c57d..232ca7c42 100644 --- a/src/overlords/situational/remoteUpgrader.ts +++ b/src/overlords/situational/remoteUpgrader.ts @@ -120,7 +120,7 @@ export class RemoteUpgradingOverlord extends Overlord { return; } // You're in the room, upgrade if you have energy - if (upgrader.carry.energy > 0) { + if (upgrader.store.energy > 0) { upgrader.task = Tasks.upgrade(this.upgradeSite.controller); return; } @@ -135,8 +135,8 @@ export class RemoteUpgradingOverlord extends Overlord { } // Recharge from transporter? const nearbyCarriers = _.filter(this.carriers, carrier => upgrader.pos.getRangeTo(carrier) <= 5); - const nearbyCarriersWaitingToUnload = _.filter(nearbyCarriers, carrier => carrier.carry.energy > 0); - const lowestEnergyCarrier = minBy(nearbyCarriersWaitingToUnload, carrier => carrier.carry.energy); + const nearbyCarriersWaitingToUnload = _.filter(nearbyCarriers, carrier => carrier.store.energy > 0); + const lowestEnergyCarrier = minBy(nearbyCarriersWaitingToUnload, carrier => carrier.store.energy); if (lowestEnergyCarrier) { upgrader.goTo(lowestEnergyCarrier); return; @@ -153,10 +153,10 @@ export class RemoteUpgradingOverlord extends Overlord { } // Get energy from the parent colony if you need it - if (carrier.carry.energy == 0) { + if (carrier.store.energy == 0) { // If you are in the child room and there are valuable resources in a storage/terminal that isn't mine, // then take those back before you go home - if (carrier.room == this.childColony.room && carrier.carry.getFreeCapacity() > 0) { + if (carrier.room == this.childColony.room && carrier.store.getFreeCapacity() > 0) { const storeStructuresNotMy = _.filter(_.compact([this.childColony.room.storage, this.childColony.room.terminal]), @@ -166,7 +166,7 @@ export class RemoteUpgradingOverlord extends Overlord { structure => structure.store.getUsedCapacity(resource) > 0); if (withdrawTarget) { const amount = Math.min(withdrawTarget.store.getUsedCapacity(resource), - carrier.carry.getFreeCapacity()); + carrier.store.getFreeCapacity()); carrier.task = Tasks.withdraw(withdrawTarget, resource, amount); return; } @@ -179,12 +179,12 @@ export class RemoteUpgradingOverlord extends Overlord { } const target = _.find(_.compact([this.parentColony.storage, this.parentColony.terminal]), - s => s!.store[RESOURCE_ENERGY] >= carrier.carryCapacity); + s => s!.store[RESOURCE_ENERGY] >= carrier.store.getCapacity()); if (!target) { log.warning(`${this.print}: no energy withdraw target for ${carrier.print}!`); return; } - if (carrier.carry.getUsedCapacity() > carrier.carry.getUsedCapacity(RESOURCE_ENERGY)) { + if (carrier.store.getUsedCapacity() > carrier.store.getUsedCapacity(RESOURCE_ENERGY)) { carrier.task = Tasks.transferAll(target); } else { carrier.task = Tasks.withdraw(target); @@ -202,9 +202,9 @@ export class RemoteUpgradingOverlord extends Overlord { // otherwise put in storage if you can const depositPos = this.upgradeSite.batteryPos || this.upgradeSite.pos; const carriersWaitingToUnload = _.filter(this.carriers, carrier => - carrier.carry.energy > 0 && carrier.pos.inRangeToPos(depositPos, 5)); + carrier.store.energy > 0 && carrier.pos.inRangeToPos(depositPos, 5)); const firstCarrierInQueue = minBy(carriersWaitingToUnload, carrier => - carrier.carry.energy + (carrier.ticksToLive || Infinity) / 10000); + carrier.store.energy + (carrier.ticksToLive || Infinity) / 10000); // Put in storage if you can if (this.childColony.storage && firstCarrierInQueue && firstCarrierInQueue != carrier) { diff --git a/src/overlords/~template/templateOverlord.ts b/src/overlords/~template/templateOverlord.ts index 1194674ed..555fe781c 100644 --- a/src/overlords/~template/templateOverlord.ts +++ b/src/overlords/~template/templateOverlord.ts @@ -143,7 +143,7 @@ export class TemplateOverlord extends Overlord { return; } // You're in the room, upgrade if you have energy - if (upgrader.carry.energy > 0) { + if (upgrader.store.energy > 0) { upgrader.task = Tasks.upgrade(this.colony.controller); return; } @@ -190,7 +190,7 @@ export class TemplateOverlord extends Overlord { private handleWorker(worker: Zerg): void { // Get energy if needed - if (worker.carry.energy == 0) { + if (worker.store.energy == 0) { worker.task = Tasks.recharge(); return; } diff --git a/src/prototypes/Structures.ts b/src/prototypes/Structures.ts index 3cb5c5b4c..c954a4699 100644 --- a/src/prototypes/Structures.ts +++ b/src/prototypes/Structures.ts @@ -45,46 +45,64 @@ OwnedStructure.prototype._isActive = OwnedStructure.prototype.isActive; // return this._isActiveValue; // }; -// Container prototypes ================================================================================================ +// Storage prototypes ================================================================================================ + +const StorageLikeStructures = [ + StructureContainer, + StructureExtension, + StructureLink, + StructureStorage, + StructureTerminal, + StructureSpawn, + Tombstone, + Ruin, +]; + +for (const structure of StorageLikeStructures) { + if (!structure.prototype.hasOwnProperty('energy')) { + Object.defineProperty(structure.prototype, 'energy', { + get(this: typeof structure.prototype) { + return this.store.getUsedCapacity(RESOURCE_ENERGY); + }, + configurable: true, + }); + } -Object.defineProperty(StructureContainer.prototype, 'energy', { - get() { - return this.store[RESOURCE_ENERGY]; - }, - configurable: true, -}); + Object.defineProperty(structure.prototype, 'isFull', { // if this container-like object is full + get(this: typeof structure.prototype) { + return this.store.getFreeCapacity() === 0; + }, + configurable: true, + }); + + Object.defineProperty(structure.prototype, 'isEmpty', { // if this container-like object is empty + get(this: StructureContainer) { + return this.store.getUsedCapacity() === 0; + }, + configurable: true, + }); +} -Object.defineProperty(StructureContainer.prototype, 'isFull', { // if this container-like object is full - get() { - return _.sum(this.store) >= this.storeCapacity; - }, - configurable: true, -}); -Object.defineProperty(StructureContainer.prototype, 'isEmpty', { // if this container-like object is empty - get() { - return _.sum(this.store) == 0; - }, - configurable: true, -}); +// Link prototypes ===================================================================================================== // Controller prototypes =============================================================================================== Object.defineProperty(StructureController.prototype, 'reservedByMe', { - get : function() { + get(this: StructureController) { return this.reservation && this.reservation.username == MY_USERNAME; }, configurable: true, }); Object.defineProperty(StructureController.prototype, 'signedByMe', { - get : function() { + get(this: StructureController) { return this.sign && this.sign.username == MY_USERNAME && Game.time - this.sign.time < 250000; }, configurable: true, }); Object.defineProperty(StructureController.prototype, 'signedByScreeps', { - get : function() { + get(this: StructureController) { return this.sign && this.sign.username == 'Screeps'; }, configurable: true, @@ -97,64 +115,14 @@ StructureController.prototype.needsReserving = function(this: StructureControlle // Extension prototypes ================================================================================================ -Object.defineProperty(StructureExtension.prototype, 'isFull', { // if this container-like object is full - get() { - return this.energy >= this.energyCapacity; - }, - configurable: true, -}); - -Object.defineProperty(StructureExtension.prototype, 'isEmpty', { // if this container-like object is empty - get() { - return this.energy == 0; - }, - configurable: true, -}); - // Link prototypes ===================================================================================================== -Object.defineProperty(StructureLink.prototype, 'isFull', { // if this container-like object is full - get() { - return this.energy >= this.energyCapacity; - }, - configurable: true, -}); - -Object.defineProperty(StructureLink.prototype, 'isEmpty', { // if this container-like object is empty - get() { - return this.energy == 0; - }, - configurable: true, -}); - -Object.defineProperty(StructureLink.prototype, 'storeCapacity', { // forwards-backwards compatibility - get() { - return this.energyCapacity; - }, - configurable: true, -}); - - // Nuker prototypes ==================================================================================================== // PowerSpawn prototypes =============================================================================================== // Spawn prototypes ==================================================================================================== -Object.defineProperty(StructureSpawn.prototype, 'isFull', { // if this container-like object is full - get() { - return this.energy >= this.energyCapacity; - }, - configurable: true, -}); - -Object.defineProperty(StructureSpawn.prototype, 'isEmpty', { // if this container-like object is empty - get() { - return this.energy == 0; - }, - configurable: true, -}); - // Storage prototypes ================================================================================================== declare const Store: any; // Store prototype isn't included in typed-screeps yet Object.defineProperty(Store.prototype, 'contents', { @@ -166,51 +134,8 @@ Object.defineProperty(Store.prototype, 'contents', { // Storage prototypes ================================================================================================== -Object.defineProperty(StructureStorage.prototype, 'energy', { - get() { - return this.store[RESOURCE_ENERGY]; - }, - configurable: true, -}); - -Object.defineProperty(StructureStorage.prototype, 'isFull', { // if this container-like object is full - get() { - return _.sum(this.store) >= this.storeCapacity; - }, - configurable: true, -}); - -Object.defineProperty(StructureStorage.prototype, 'isEmpty', { // if this container-like object is empty - get() { - return _.sum(this.store) == 0; - }, - configurable: true, -}); - - // Terminal prototypes ================================================================================================= -Object.defineProperty(StructureTerminal.prototype, 'energy', { - get() { - return this.store[RESOURCE_ENERGY]; - }, - configurable: true, -}); - -Object.defineProperty(StructureTerminal.prototype, 'isFull', { // if this container-like object is full - get() { - return _.sum(this.store) >= this.storeCapacity; - }, - configurable: true, -}); - -Object.defineProperty(StructureTerminal.prototype, 'isEmpty', { // if this container-like object is empty - get() { - return _.sum(this.store) == 0; - }, - configurable: true, -}); - Object.defineProperty(StructureTerminal.prototype, 'isReady', { // the terminal is ready to send or deal get() { return this.cooldown == 0 && !this._notReady; @@ -237,28 +162,3 @@ StructureTerminal.prototype.send = function(resourceType: ResourceConstant, amou } return response; }; - -// Tower prototypes - -Object.defineProperty(StructureTower.prototype, 'isFull', { // if this container-like object is full - get() { - return this.energy >= this.energyCapacity; - }, - configurable: true, -}); - -Object.defineProperty(StructureTower.prototype, 'isEmpty', { // if this container-like object is empty - get() { - return this.energy == 0; - }, - configurable: true, -}); - -// Tombstone prototypes ================================================================================================ -Object.defineProperty(Tombstone.prototype, 'energy', { - get() { - return this.store[RESOURCE_ENERGY]; - }, - configurable: true, -}); - diff --git a/src/tasks/instances/build.ts b/src/tasks/instances/build.ts index 01393bcd0..7abcc9f18 100644 --- a/src/tasks/instances/build.ts +++ b/src/tasks/instances/build.ts @@ -14,7 +14,7 @@ export class TaskBuild extends Task { } isValidTask() { - return this.creep.carry.energy > 0; + return this.creep.store.energy > 0; } isValidTarget() { diff --git a/src/tasks/instances/drop.ts b/src/tasks/instances/drop.ts index 54ab720fc..07e05508c 100644 --- a/src/tasks/instances/drop.ts +++ b/src/tasks/instances/drop.ts @@ -32,7 +32,7 @@ export class TaskDrop extends Task { isValidTask() { const amount = this.data.amount || 1; - const resourcesInCarry = this.creep.carry[this.data.resourceType] || 0; + const resourcesInCarry = this.creep.store[this.data.resourceType] || 0; return resourcesInCarry >= amount; } diff --git a/src/tasks/instances/fortify.ts b/src/tasks/instances/fortify.ts index 0bba5390b..ed6e81130 100644 --- a/src/tasks/instances/fortify.ts +++ b/src/tasks/instances/fortify.ts @@ -21,7 +21,7 @@ export class TaskFortify extends Task { } isValidTask() { - return (this.creep.carry.energy > 0); // Times out once creep is out of energy + return (this.creep.store.energy > 0); // Times out once creep is out of energy } isValidTarget() { diff --git a/src/tasks/instances/generateSafeMode.ts b/src/tasks/instances/generateSafeMode.ts index f28989ba8..fb53cd802 100644 --- a/src/tasks/instances/generateSafeMode.ts +++ b/src/tasks/instances/generateSafeMode.ts @@ -11,7 +11,7 @@ export class TaskGenerateSafeMode extends Task { } isValidTask() { - return (this.creep.carry[RESOURCE_GHODIUM] >= 1000); + return (this.creep.store[RESOURCE_GHODIUM] >= 1000); } isValidTarget() { diff --git a/src/tasks/instances/harvest.ts b/src/tasks/instances/harvest.ts index ad25a732e..cc84ad41e 100644 --- a/src/tasks/instances/harvest.ts +++ b/src/tasks/instances/harvest.ts @@ -12,7 +12,7 @@ export class TaskHarvest extends Task { } isValidTask() { - return _.sum(this.creep.carry) < this.creep.carryCapacity; + return this.creep.store.getUsedCapacity() < this.creep.store.getCapacity(); } isValidTarget() { diff --git a/src/tasks/instances/pickup.ts b/src/tasks/instances/pickup.ts index 0a4723531..34744849a 100644 --- a/src/tasks/instances/pickup.ts +++ b/src/tasks/instances/pickup.ts @@ -12,7 +12,7 @@ export class TaskPickup extends Task { } isValidTask() { - return _.sum(this.creep.carry) < this.creep.carryCapacity; + return this.creep.store.getUsedCapacity() < this.creep.store.getCapacity(); } isValidTarget() { diff --git a/src/tasks/instances/recharge.ts b/src/tasks/instances/recharge.ts index d44963826..f68da03c7 100644 --- a/src/tasks/instances/recharge.ts +++ b/src/tasks/instances/recharge.ts @@ -39,7 +39,7 @@ export class TaskRecharge extends Task { || zerg.task.name == pickupTaskName)); const resourceOutflux = _.sum(_.map(otherTargeters, other => other.carryCapacity - _.sum(other.carry))); - amount = minMax(amount - resourceOutflux, 0, creep.carryCapacity); + amount = minMax(amount - resourceOutflux, 0, creep.store.getCapacity()); const effectiveAmount = amount / (creep.pos.getMultiRoomRangeTo(obj.pos) + 1); if (effectiveAmount <= 0) { return false; diff --git a/src/tasks/instances/repair.ts b/src/tasks/instances/repair.ts index ea9ede838..d928556d8 100644 --- a/src/tasks/instances/repair.ts +++ b/src/tasks/instances/repair.ts @@ -14,7 +14,7 @@ export class TaskRepair extends Task { } isValidTask() { - return this.creep.carry.energy > 0; + return this.creep.store.energy > 0; } isValidTarget() { diff --git a/src/tasks/instances/transfer.ts b/src/tasks/instances/transfer.ts index 950657e06..cb2ddecaf 100644 --- a/src/tasks/instances/transfer.ts +++ b/src/tasks/instances/transfer.ts @@ -26,7 +26,7 @@ export class TaskTransfer extends Task { isValidTask() { const amount = this.data.amount || 1; - const resourcesInCarry = this.creep.carry[this.data.resourceType] || 0; + const resourcesInCarry = this.creep.store[this.data.resourceType] || 0; return resourcesInCarry >= amount; } diff --git a/src/tasks/instances/transferAll.ts b/src/tasks/instances/transferAll.ts index 9b63718db..3fdc72e69 100644 --- a/src/tasks/instances/transferAll.ts +++ b/src/tasks/instances/transferAll.ts @@ -18,7 +18,7 @@ export class TaskTransferAll extends Task { } isValidTask() { - for (const [resourceType, amount] of this.creep.carry.contents) { + for (const [resourceType, amount] of this.creep.store.contents) { if (this.data.skipEnergy && resourceType == RESOURCE_ENERGY) { continue; } @@ -30,11 +30,11 @@ export class TaskTransferAll extends Task { } isValidTarget() { - return _.sum(this.target.store) < this.target.storeCapacity; + return this.target.store.getUsedCapacity() < this.target.store.getCapacity(); } work() { - for (const [resourceType, amount] of this.creep.carry.contents) { + for (const [resourceType, amount] of this.creep.store.contents) { if (this.data.skipEnergy && resourceType == RESOURCE_ENERGY) { continue; } diff --git a/src/tasks/instances/upgrade.ts b/src/tasks/instances/upgrade.ts index ef5cb773f..0ca14a302 100644 --- a/src/tasks/instances/upgrade.ts +++ b/src/tasks/instances/upgrade.ts @@ -15,7 +15,7 @@ export class TaskUpgrade extends Task { } isValidTask() { - return (this.creep.carry.energy > 0); + return (this.creep.store.energy > 0); } isValidTarget() { diff --git a/src/tasks/instances/withdraw.ts b/src/tasks/instances/withdraw.ts index 8bc384489..d0e546fae 100644 --- a/src/tasks/instances/withdraw.ts +++ b/src/tasks/instances/withdraw.ts @@ -24,7 +24,7 @@ export class TaskWithdraw extends Task { isValidTask() { const amount = this.data.amount || 1; - return (_.sum(this.creep.carry) <= this.creep.carryCapacity - amount); + return (this.creep.store.getUsedCapacity() <= this.creep.store.getCapacity() - amount); } isValidTarget() { diff --git a/src/tasks/instances/withdrawAll.ts b/src/tasks/instances/withdrawAll.ts index f0459d5a4..997af58ef 100644 --- a/src/tasks/instances/withdrawAll.ts +++ b/src/tasks/instances/withdrawAll.ts @@ -14,11 +14,11 @@ export class TaskWithdrawAll extends Task { } isValidTask() { - return (_.sum(this.creep.carry) < this.creep.carryCapacity); + return (this.creep.store.getUsedCapacity() < this.creep.store.getCapacity()); } isValidTarget() { - return _.sum(this.target.store) > 0; + return (this.target.store.getUsedCapacity() || 0) > 0; } work() { diff --git a/src/zerg/AnyZerg.ts b/src/zerg/AnyZerg.ts index 2ed86b94a..981815d44 100644 --- a/src/zerg/AnyZerg.ts +++ b/src/zerg/AnyZerg.ts @@ -80,9 +80,7 @@ export abstract class AnyZerg { isAnyZerg: true; creep: AnyCreep; // The creep that this wrapper class will control // body: BodyPartDefinition[]; // These properties are all wrapped from this.creep.* to this.* - carry: StoreDefinition; // | store: StoreDefinition; // | - carryCapacity: number; // | effects: RoomObjectEffect[]; // fatigue: number; // | hits: number; // | @@ -108,9 +106,7 @@ export abstract class AnyZerg { // Copy over creep references this.creep = creep; // this.body = creep.body; - this.carry = creep.carry; this.store = creep.store; - this.carryCapacity = creep.carryCapacity; // this.fatigue = creep.fatigue; this.effects = creep.effects; this.hits = creep.hits; @@ -156,9 +152,7 @@ export abstract class AnyZerg { this.pos = creep.pos; this.nextPos = creep.pos; // this.body = creep.body; - this.carry = creep.carry; this.store = creep.store; - this.carryCapacity = creep.carryCapacity; // this.fatigue = creep.fatigue; this.hits = creep.hits; this.memory = creep.memory; @@ -286,7 +280,7 @@ export abstract class AnyZerg { // Carry methods get hasMineralsInCarry(): boolean { - for (const [resourceType, amount] of this.carry.contents) { + for (const [resourceType, amount] of this.store.contents) { if (resourceType != RESOURCE_ENERGY && amount > 0) { return true; } @@ -392,7 +386,7 @@ export abstract class AnyZerg { const fleeing = Movement.flee(this, avoidGoals, fleeOptions.dropEnergy, moveOptions) != undefined; if (fleeing) { // Drop energy if needed - if (fleeOptions.dropEnergy && this.carry.energy > 0) { + if (fleeOptions.dropEnergy && this.store.energy > 0) { const nearbyContainers = this.pos.findInRange(this.room.storageUnits, 1); if (nearbyContainers.length > 0) { this.transfer(_.first(nearbyContainers), RESOURCE_ENERGY); @@ -423,7 +417,7 @@ export abstract class AnyZerg { if (this.memory.avoidDanger) { if (this.memory.avoidDanger.timer > 0) { this.goToRoom(this.memory.avoidDanger.fallback); - if (opts.dropEnergy && this.carry.energy > 0) { + if (opts.dropEnergy && this.store.energy > 0) { this.drop(RESOURCE_ENERGY); // transfer energy to container check is only run on first danger tick } this.memory.avoidDanger.timer--; @@ -477,7 +471,7 @@ export abstract class AnyZerg { fallback: fallback, }; - if (opts.dropEnergy && this.carry.energy > 0) { + if (opts.dropEnergy && this.store.energy > 0) { const containersInRange = this.pos.findInRange(this.room.containers, 1); const adjacentContainer = _.first(containersInRange); if (adjacentContainer) { diff --git a/src/zerg/PowerZerg.ts b/src/zerg/PowerZerg.ts index caa6afd71..cb8c954cb 100644 --- a/src/zerg/PowerZerg.ts +++ b/src/zerg/PowerZerg.ts @@ -55,9 +55,7 @@ export abstract class PowerZerg extends AnyZerg { this.creep = powerCreep; this.pos = powerCreep.pos; this.nextPos = powerCreep.pos; - this.carry = powerCreep.carry; this.store = powerCreep.store; - this.carryCapacity = powerCreep.carryCapacity; this.hits = powerCreep.hits; this.memory = powerCreep.memory; this.room = powerCreep.room as Room; // not actually as Room diff --git a/src/zerg/Zerg.ts b/src/zerg/Zerg.ts index bbb63cf6c..7b15ac667 100644 --- a/src/zerg/Zerg.ts +++ b/src/zerg/Zerg.ts @@ -56,9 +56,7 @@ export class Zerg extends AnyZerg { isStandardZerg: true; creep: Creep; // The creep that this wrapper class will control body: BodyPartDefinition[]; // These properties are all wrapped from this.creep.* to this.* - carry: StoreDefinition; // | - store: StoreDefinition; // | - carryCapacity: number; // | + store: StoreDefinition; // | fatigue: number; // | hits: number; // | hitsMax: number; // | From 03d54eb80527246d4093eed785e545c5de383223 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Fri, 4 Aug 2023 04:55:05 +0200 Subject: [PATCH 40/41] Provide an interface over store contents --- src/Colony.ts | 15 +++------------ src/declarations/index.d.ts | 6 +++--- src/declarations/prototypes.d.ts | 8 ++++---- src/deprecated/TerminalNetwork.ts | 4 ++-- src/directives/resource/haul.ts | 22 +++++++++++----------- src/hiveClusters/evolutionChamber.ts | 2 +- src/logistics/LogisticsNetwork.ts | 12 ++++++------ src/logistics/TerminalNetwork_v2.ts | 10 +++++----- src/overlords/core/queen_bunker.ts | 4 ++-- src/overlords/situational/hauler.ts | 2 +- src/prototypes/Structures.ts | 5 +++-- src/resources/Abathur.ts | 10 +++++----- src/resources/map_resources.ts | 2 +- src/tasks/instances/recharge.ts | 3 +-- src/tasks/instances/transferAll.ts | 2 +- src/utilities/utils.ts | 13 +++++-------- 16 files changed, 54 insertions(+), 66 deletions(-) diff --git a/src/Colony.ts b/src/Colony.ts index 95ff48f91..afd1227f3 100644 --- a/src/Colony.ts +++ b/src/Colony.ts @@ -116,14 +116,6 @@ const getDefaultColonyMemory: () => ColonyMemory = () => ({ outposts : {}, }); -export interface Assets { - energy: number; - power: number; - ops: number; - - [resourceType: string]: number; -} - /** * Colonies are the highest-level object other than the global Overmind. A colony groups together all rooms, structures, * creeps, utilities, etc. which are run from a single owned room. @@ -143,7 +135,7 @@ export class Colony { // abandonedOutposts: AbandonedOutpost[]; // Outposts that are not currently maintained, not used for now rooms: Room[]; // All rooms including the primary room pos: RoomPosition; - assets: Assets; + assets: StoreContents; // Physical colony structures and roomObjects controller: StructureController; // These are all duplicated from room properties spawns: StructureSpawn[]; // | @@ -647,14 +639,13 @@ export class Colony { * Summarizes the total of all resources in colony store structures, labs, and some creeps. Will always return * 0 for an asset that it has none of (not undefined) */ - private computeAssets(verbose = false): Assets { + private computeAssets(verbose = false): StoreContents { // Include storage structures, lab contents, and manager carry const assetStructures = _.compact([this.storage, this.terminal, this.factory, ...this.labs]); const assetCreeps = [...this.getCreepsByRole(Roles.queen), ...this.getCreepsByRole(Roles.manager)]; const assetStores = _.map([...assetStructures, ...assetCreeps], thing => thing!.store); - // @ts-expect-error Store stuff - const allAssets = mergeSum([...assetStores, ALL_ZERO_ASSETS]) as Assets; + const allAssets = mergeSum(...assetStores, ALL_ZERO_ASSETS); if (verbose) log.debug(`${this.room.print} assets: ` + JSON.stringify(allAssets)); return allAssets; diff --git a/src/declarations/index.d.ts b/src/declarations/index.d.ts index 0d6b57e15..60ea047d3 100644 --- a/src/declarations/index.d.ts +++ b/src/declarations/index.d.ts @@ -324,7 +324,7 @@ type TransferrableStoreStructure = | StructureTerminal | StructureTower; -// interface StoreLike { -// [resourceType: string]: number -// } +type StoreContentsArray = [resourceType: ResourceConstant, amount: number][]; +type StoreContents = { [resourceType in ResourceConstant]: number }; +type DropContents = { [resourceType in ResourceConstant]: Resource[] | undefined }; diff --git a/src/declarations/prototypes.d.ts b/src/declarations/prototypes.d.ts index 857ea96f0..06dc8fd44 100644 --- a/src/declarations/prototypes.d.ts +++ b/src/declarations/prototypes.d.ts @@ -247,6 +247,10 @@ interface Structure { isWalkable: boolean; } +interface StoreBase { + contents: StoreContentsArray; +} + interface _StoreLike { energy: number; isFull: boolean; @@ -266,10 +270,6 @@ interface StructureController { needsReserving(reserveBuffer: number): boolean; } -interface StoreBase { - contents: [ResourceConstant, number][]; -} - interface StructureSpawn extends _StoreLike { cost(bodyArray: string[]): number; } diff --git a/src/deprecated/TerminalNetwork.ts b/src/deprecated/TerminalNetwork.ts index 8c4a1b7d7..54142a8c8 100644 --- a/src/deprecated/TerminalNetwork.ts +++ b/src/deprecated/TerminalNetwork.ts @@ -136,8 +136,8 @@ export class TerminalNetwork /*implements ITerminalNetwork*/ { /* Summarizes the total of all resources currently in a colony store structure */ private getAllAssets(): { [resourceType: string]: number } { - return mergeSum(_.map(this.terminals, terminal => - (colonyOf(terminal) != undefined ? colonyOf(terminal).assets : {}))); + const p = _.map(this.terminals, terminal => (!!colonyOf(terminal) ? colonyOf(terminal).assets : {})); + return mergeSum(...p); } private logTransfer(resourceType: ResourceConstant, amount: number, origin: string, destination: string) { diff --git a/src/directives/resource/haul.ts b/src/directives/resource/haul.ts index e6cde3c61..9d2cbbbcf 100644 --- a/src/directives/resource/haul.ts +++ b/src/directives/resource/haul.ts @@ -25,8 +25,8 @@ export class DirectiveHaul extends Directive { static color = COLOR_YELLOW; static secondaryColor = COLOR_BLUE; - private _store: StoreDefinition; - private _drops: { [resourceType: string]: Resource[] }; + private _store: StoreContents; + private _drops: DropContents; private _finishAtTime: number; memory: DirectiveHaulMemory; @@ -43,13 +43,13 @@ export class DirectiveHaul extends Directive { return Overmind.cache.targets[this.ref]; } - get drops(): { [resourceType: string]: Resource[] } { + get drops(): DropContents { if (!this.pos.isVisible) { - return {}; + return {}; } if (!this._drops) { const drops = (this.pos.lookFor(LOOK_RESOURCES) || []) as Resource[]; - this._drops = _.groupBy(drops, drop => drop.resourceType); + this._drops = _.groupBy(drops, drop => drop.resourceType); } return this._drops; } @@ -70,25 +70,25 @@ export class DirectiveHaul extends Directive { return undefined; } - get store(): { [resource: string]: number } { + get store(): StoreContents { if (!this._store) { // Merge the "storage" of drops with the store of structure - let store: { [resourceType: string]: number } = {}; + let store = {}; if (this.storeStructure) { store = this.storeStructure.store; } else { - store = {energy: 0}; + store = {energy: 0}; } // Merge with drops - for (const resourceType of _.keys(this.drops)) { - const totalResourceAmount = _.sum(this.drops[resourceType], drop => drop.amount); + for (const resourceType of (_.keys(this.drops) as ResourceConstant[])) { + const totalResourceAmount = _.sum(this.drops[resourceType] as Resource[], drop => drop.amount); if (store[resourceType]) { store[resourceType] += totalResourceAmount; } else { store[resourceType] = totalResourceAmount; } } - this._store = store as StoreDefinition; + this._store = store; } // log.alert(`Haul directive ${this.print} has store of ${JSON.stringify(this._store)}`); return this._store; diff --git a/src/hiveClusters/evolutionChamber.ts b/src/hiveClusters/evolutionChamber.ts index 92294430b..df8816eb7 100644 --- a/src/hiveClusters/evolutionChamber.ts +++ b/src/hiveClusters/evolutionChamber.ts @@ -485,7 +485,7 @@ export class EvolutionChamber extends HiveCluster { } const amountNeeded = this.neededBoosts[boost] + amountUnavailable; - if (amountNeeded > this.colony.assets[boost]) { + if (amountNeeded > this.colony.assets[boost]) { this.debug(`Requesting boost from terminal network: ${this.neededBoosts[boost]} ${boost}`); this.terminalNetwork.requestResource(this.colony, boost, amountNeeded); } else { diff --git a/src/logistics/LogisticsNetwork.ts b/src/logistics/LogisticsNetwork.ts index faa92e047..c3e2ec331 100644 --- a/src/logistics/LogisticsNetwork.ts +++ b/src/logistics/LogisticsNetwork.ts @@ -81,7 +81,7 @@ export class LogisticsNetwork { // private logisticPositions: { [roomName: string]: RoomPosition[] }; private cache: { nextAvailability: { [transporterName: string]: [number, RoomPosition] }, - predictedTransporterCarry: { [transporterName: string]: { [resourceType: string]: number } }, + predictedTransporterCarry: { [transporterName: string]: StoreContents }, resourceChangeRate: { [requestID: string]: { [transporterName: string]: number } }, }; static settings = { @@ -288,7 +288,7 @@ export class LogisticsNetwork { * Returns the predicted state of the transporter's carry after completing its current task */ private computePredictedTransporterCarry(transporter: Zerg, - nextAvailability?: [number, RoomPosition]): { [resourceType: string]: number } { + nextAvailability?: [number, RoomPosition]): StoreContents { if (transporter.task && transporter.task.target) { const requestID = this.targetToRequest[transporter.task.target.ref]; if (requestID) { @@ -301,7 +301,7 @@ export class LogisticsNetwork { if (request.resourceType == 'all') { if (isResource(request.target)) { log.error(ALL_RESOURCE_TYPE_ERROR); - return {energy: 0} as StoreDefinition; + return {energy: 0}; } for (const [resourceType, storeAmt] of request.target.store.contents) { const resourceFraction = storeAmt / (request.target.store.getUsedCapacity(resourceType) || storeAmt); @@ -320,7 +320,7 @@ export class LogisticsNetwork { carry[request.resourceType] = minMax(resourceAmount, 0, remainingCapacity); } } - return carry as StoreDefinition; + return carry; } } } @@ -330,7 +330,7 @@ export class LogisticsNetwork { /** * Returns the predicted state of the transporter's carry after completing its task */ - private predictedTransporterCarry(transporter: Zerg): { [resourceType: string]: number } { + private predictedTransporterCarry(transporter: Zerg): StoreContents { if (!this.cache.predictedTransporterCarry[transporter.name]) { this.cache.predictedTransporterCarry[transporter.name] = this.computePredictedTransporterCarry(transporter); } @@ -405,7 +405,7 @@ export class LogisticsNetwork { const [ticksUntilFree, newPos] = this.nextAvailability(transporter); const choices: { dQ: number, dt: number, targetRef: string }[] = []; const amount = this.predictedRequestAmount(transporter, request, [ticksUntilFree, newPos]); - let carry: { [resourceType: string]: number }; + let carry: StoreContents; if (!transporter.task || transporter.task.target != request.target) { // If you are not targeting the requestor, use predicted carry after completing current task carry = this.predictedTransporterCarry(transporter); diff --git a/src/logistics/TerminalNetwork_v2.ts b/src/logistics/TerminalNetwork_v2.ts index 537cafe3c..fe6fff76f 100644 --- a/src/logistics/TerminalNetwork_v2.ts +++ b/src/logistics/TerminalNetwork_v2.ts @@ -302,7 +302,7 @@ export class TerminalNetworkV2 implements ITerminalNetwork { private passiveRequestors: { [resourceType: string]: Colony[] }; private activeRequestors: { [resourceType: string]: Colony[] }; - private assets: { [resourceType: string]: number }; + private assets: StoreContents; private notifications: string[]; private memory: TerminalNetworkMemory; @@ -342,7 +342,7 @@ export class TerminalNetworkV2 implements ITerminalNetwork { this.passiveRequestors = {}; // _.clone(EMPTY_COLONY_TIER); this.activeRequestors = {}; // _.clone(EMPTY_COLONY_TIER); - this.assets = {}; // populated when getAssets() is called in init() + this.assets = {}; // populated when getAssets() is called in init() this.terminalOverload = {}; this.notifications = []; @@ -367,9 +367,9 @@ export class TerminalNetworkV2 implements ITerminalNetwork { } } - getAssets(): { [resourceType: string]: number } { + getAssets(): StoreContents { if (_.isEmpty(this.assets)) { - this.assets = mergeSum(_.map(this.colonies, colony => colony.assets)); + this.assets = mergeSum(..._.map(this.colonies, colony => colony.assets)); } return this.assets; } @@ -1205,7 +1205,7 @@ export class TerminalNetworkV2 implements ITerminalNetwork { `${colony.print} actively requesting ----------------------------------------------------\n` + `${bullet}${activeRequestors[colony.name] || '(None)'}\n`; } else { - const resource = resourceOrColony || undefined; + const resource = resourceOrColony || undefined; if (resource) { info += `Active providers for ${resource} -----------------------------------------------------\n` + `${bullet}${_.map(this.activeProviders[resource], col => diff --git a/src/overlords/core/queen_bunker.ts b/src/overlords/core/queen_bunker.ts index 8f0dfaeb0..ea4098047 100644 --- a/src/overlords/core/queen_bunker.ts +++ b/src/overlords/core/queen_bunker.ts @@ -139,8 +139,8 @@ export class BunkerQueenOverlord extends Overlord { } } // Step 2: figure out what you need to supply for and calculate the needed resources - const queenCarry = {} as { [resourceType: string]: number }; - const allStore = mergeSum(_.map(this.storeStructures, s => s.store)); + const queenCarry = {}; + const allStore = mergeSum(..._.map(this.storeStructures, s => s.store)); const supplyRequests: TransportRequest[] = []; for (const priority in this.colony.transportRequests.supply) { diff --git a/src/overlords/situational/hauler.ts b/src/overlords/situational/hauler.ts index d00ca5f66..8ec57be08 100644 --- a/src/overlords/situational/hauler.ts +++ b/src/overlords/situational/hauler.ts @@ -68,7 +68,7 @@ export class HaulingOverlord extends Overlord { if (this.directive.storeStructure) { const store = this.directive.store!; let totalDrawn = 0; // Fill to full - for (const resourceType in store) { + for (const resourceType of Object.keys(store)) { if (store[resourceType] > 0) { if (hauler.task) { hauler.task = Tasks.withdraw(this.directive.storeStructure, resourceType).fork(hauler.task); diff --git a/src/prototypes/Structures.ts b/src/prototypes/Structures.ts index c954a4699..ab12641ba 100644 --- a/src/prototypes/Structures.ts +++ b/src/prototypes/Structures.ts @@ -124,10 +124,11 @@ StructureController.prototype.needsReserving = function(this: StructureControlle // Spawn prototypes ==================================================================================================== // Storage prototypes ================================================================================================== + declare const Store: any; // Store prototype isn't included in typed-screeps yet Object.defineProperty(Store.prototype, 'contents', { - get() { - return Object.entries(this); + get(this: StoreDefinition) { + return Object.entries(this); }, configurable: true, }); diff --git a/src/resources/Abathur.ts b/src/resources/Abathur.ts index 1e058f32d..eeb074485 100644 --- a/src/resources/Abathur.ts +++ b/src/resources/Abathur.ts @@ -72,7 +72,7 @@ export const REACTION_PRIORITIES = [ BOOST_TIERS.upgrade.T3, ]; -export const priorityStockAmounts: { [key: string]: number } = { +export const priorityStockAmounts = { XGHO2: 1000, // (-70 % dmg taken) XLHO2: 1000, // (+300 % heal) XZHO2: 1000, // (+300 % fat decr - speed) @@ -94,7 +94,7 @@ export const priorityStockAmounts: { [key: string]: number } = { G : 2000, // For nukes and common compounds }; -export const wantedStockAmounts: { [key: string]: number } = { +export const wantedStockAmounts = { UH : 3000, // (+100 % attack) KO : 3000, // (+100 % ranged attack) XGHO2: 10000, // (-70 % dmg taken) @@ -351,7 +351,7 @@ export class Abathur { // Compute the reaction queue for the highest priority item that you should be and can be making const stocksToCheck = [priorityStockAmounts, wantedStockAmounts]; for (const stocks of stocksToCheck) { - for (const resourceType in stocks) { + for (const resourceType of Object.keys(stocks)) { const amountOwned = colony.assets[resourceType]; const amountNeeded = stocks[resourceType]; if (amountOwned < amountNeeded) { // if there is a shortage of this resource @@ -433,8 +433,8 @@ export class Abathur { const requiredBasicMinerals = Abathur.getRequiredBasicMinerals(reactionQueue); if (verbose) console.log(`Required basic minerals: ${JSON.stringify(requiredBasicMinerals)}`); if (verbose) console.log(`assets: ${JSON.stringify(colony.assets)}`); - const missingBasicMinerals: { [resourceType: string]: number } = {}; - for (const mineralType in requiredBasicMinerals) { + const missingBasicMinerals = {}; + for (const mineralType of Object.keys(requiredBasicMinerals)) { const amountMissing = requiredBasicMinerals[mineralType] - colony.assets[mineralType]; if (amountMissing > 0) { missingBasicMinerals[mineralType] = amountMissing; diff --git a/src/resources/map_resources.ts b/src/resources/map_resources.ts index c8d82a453..91e33589e 100644 --- a/src/resources/map_resources.ts +++ b/src/resources/map_resources.ts @@ -354,4 +354,4 @@ export const DEPOSITS_ALL: ResourceConstant[] = [ RESOURCE_MIST, ]; -export const ALL_ZERO_ASSETS: { [resource: string]: number } = _.zipObject(RESOURCES_ALL, _.map(RESOURCES_ALL, i => 0)); +export const ALL_ZERO_ASSETS: StoreContents = _.zipObject(RESOURCES_ALL, _.map(RESOURCES_ALL, i => 0)); diff --git a/src/tasks/instances/recharge.ts b/src/tasks/instances/recharge.ts index f68da03c7..4fecf3846 100644 --- a/src/tasks/instances/recharge.ts +++ b/src/tasks/instances/recharge.ts @@ -37,8 +37,7 @@ export class TaskRecharge extends Task { zerg => !!zerg && zerg.task && (zerg.task.name == withdrawTaskName || zerg.task.name == pickupTaskName)); - const resourceOutflux = _.sum(_.map(otherTargeters, - other => other.carryCapacity - _.sum(other.carry))); + const resourceOutflux = _.sum(_.map(otherTargeters, other => other.store.getFreeCapacity())); amount = minMax(amount - resourceOutflux, 0, creep.store.getCapacity()); const effectiveAmount = amount / (creep.pos.getMultiRoomRangeTo(obj.pos) + 1); if (effectiveAmount <= 0) { diff --git a/src/tasks/instances/transferAll.ts b/src/tasks/instances/transferAll.ts index 3fdc72e69..a564fed1b 100644 --- a/src/tasks/instances/transferAll.ts +++ b/src/tasks/instances/transferAll.ts @@ -18,7 +18,7 @@ export class TaskTransferAll extends Task { } isValidTask() { - for (const [resourceType, amount] of this.creep.store.contents) { + for (const [resourceType, amount] of Object.entries(this.creep.store)) { if (this.data.skipEnergy && resourceType == RESOURCE_ENERGY) { continue; } diff --git a/src/utilities/utils.ts b/src/utilities/utils.ts index 8560170d1..c28e0ac9a 100644 --- a/src/utilities/utils.ts +++ b/src/utilities/utils.ts @@ -166,14 +166,11 @@ export function toColumns(obj: { [key: string]: string }, opts = {} as ToColumnO /** * Merges a list of store-like objects, summing overlapping keys. Useful for calculating assets from multiple sources */ -export function mergeSum(objects: { [key: string]: number | undefined }[]): { [key: string]: number } { - const ret: { [key: string]: number } = {}; - for (const object of objects) { - for (const key in object) { - const amount = object[key] || 0; - if (!ret[key]) { - ret[key] = 0; - } +export function mergeSum(...stores: StoreContents[]): StoreContents { + const ret = {}; + for (const store of stores) { + for (const [key, amount] of <[ResourceConstant, number][]>Object.entries(store)) { + if (!ret[key]) ret[key] = 0; ret[key] += amount; } } From d3f620f2f28c6df0e5cfbf1b106f87a4b6d4b6d1 Mon Sep 17 00:00:00 2001 From: Etienne Samson Date: Sun, 6 Aug 2023 07:02:24 +0200 Subject: [PATCH 41/41] Fix error in AnyZerg.move() and freezing CombatZergs There was a logic error in the AnyZerg move() method, causing the issue in Movement.vacatePos(). The method vacatePos() sets creep.blockMovement to true, but is meant to override it with force: true. The check in AnyZerg said "!this.blockMovement && !force" therefore this method was not working, and the creep not moving. Swapped it to "!this.blockMovement || force". Also fixed an issue where Zergs of a role would stop working if one of their kind was spawning, there was a return instead of an continue, aborting any Zerg actions after it. Squashed from eb2b78c9013411fd1b309efc98f286291f3a8b42 --- src/movement/Movement.ts | 1 - src/overlords/CombatOverlord.ts | 2 +- src/zerg/AnyZerg.ts | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/movement/Movement.ts b/src/movement/Movement.ts index aaf3b29ce..c1c72a614 100644 --- a/src/movement/Movement.ts +++ b/src/movement/Movement.ts @@ -571,7 +571,6 @@ export class Movement { } - // TODO: this is bugged somewhere /** * Recursively moves creeps out of the way of a position to make room for something, such as a spawning creep. * If suicide is specified and there is no series of move commands that can move a block of creeps out of the way, diff --git a/src/overlords/CombatOverlord.ts b/src/overlords/CombatOverlord.ts index 6d839982c..eaa31ce25 100644 --- a/src/overlords/CombatOverlord.ts +++ b/src/overlords/CombatOverlord.ts @@ -43,7 +43,7 @@ export abstract class CombatOverlord extends Overlord { autoRun(roleCreeps: CombatZerg[], creepHandler: (creep: CombatZerg) => void) { for (const creep of roleCreeps) { if (creep.spawning) { - return; + continue; } if (creep.hasValidTask) { creep.run(); diff --git a/src/zerg/AnyZerg.ts b/src/zerg/AnyZerg.ts index 981815d44..9458045ba 100644 --- a/src/zerg/AnyZerg.ts +++ b/src/zerg/AnyZerg.ts @@ -204,7 +204,7 @@ export abstract class AnyZerg { } move(direction: DirectionConstant, force = false) { - if (!this.blockMovement && !force) { + if (!this.blockMovement || force) { const result = this.creep.move(direction); if (result == OK) { if (!this.actionLog.move) this.actionLog.move = true;