diff --git a/src/Overseer.ts b/src/Overseer.ts index 68664c3b3..9efc7efbf 100644 --- a/src/Overseer.ts +++ b/src/Overseer.ts @@ -314,7 +314,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 600df9ba4..46d921e70 100644 --- a/src/overlords/core/worker.ts +++ b/src/overlords/core/worker.ts @@ -13,6 +13,10 @@ import {Visualizer} from '../../visuals/Visualizer'; import {Zerg} from '../../zerg/Zerg'; import {Overlord} from '../Overlord'; + interface hitsCallback { + (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 +33,7 @@ export class WorkerOverlord extends Overlord { constructionSites: ConstructionSite[]; nukeDefenseRamparts: StructureRampart[]; nukeDefenseHitsRemaining: { [id: string]: number }; + nukeDefenseHitsNeeded: { [id: string]: number }; useBoostedRepair?: boolean; static settings = { @@ -106,6 +111,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 +139,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 +152,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; } @@ -263,20 +279,29 @@ export class WorkerOverlord extends Overlord { return false; } } - - private fortifyActions(worker: Zerg, fortifyStructures = this.fortifyBarriers): boolean { + + private lowBarriers(fortifyStructures = this.fortifyBarriers, + hitsCallback: hitsCallback + = function(structure: StructureWall|StructureRampart): number {return structure.hits;} + ): (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.lowBarriers(fortifyStructures); const target = worker.pos.findClosestByMultiRoomRange(lowBarriers); if (target) { worker.task = Tasks.fortify(target); @@ -287,7 +312,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.lowBarriers() + 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 +333,12 @@ export class WorkerOverlord extends Overlord { } })); }); + if (target) { worker.task = Tasks.fortify(target); return true; } else { - return false; + return this.fortifyActions(worker, fortifyStructures); } }