From 1f34e3293e45e23a9d89ac30645a37da4fa490a2 Mon Sep 17 00:00:00 2001 From: Matthew Roy Date: Wed, 22 May 2019 10:28:59 -0700 Subject: [PATCH 01/10] Adding partial power directive, needs the powers first --- src/directives/initializer.ts | 8 + src/directives/powerCreeps/baseOperator.ts | 244 ++++++++++++++++++ .../powerCreeps/powers/generateOps.ts | 13 + .../powerCreeps/powers/genericPower.ts | 17 ++ 4 files changed, 282 insertions(+) create mode 100644 src/directives/powerCreeps/baseOperator.ts create mode 100644 src/directives/powerCreeps/powers/generateOps.ts create mode 100644 src/directives/powerCreeps/powers/genericPower.ts diff --git a/src/directives/initializer.ts b/src/directives/initializer.ts index 081a081bd..a63af3941 100644 --- a/src/directives/initializer.ts +++ b/src/directives/initializer.ts @@ -25,6 +25,7 @@ import {DirectiveTargetSiege} from './targeting/siegeTarget'; import {DirectiveTerminalEmergencyState} from './terminalState/terminalState_emergency'; import {DirectiveTerminalEvacuateState} from './terminalState/terminalState_evacuate'; import {DirectiveTerminalRebuildState} from './terminalState/terminalState_rebuild'; +import {DirectiveBaseOperator} from "./powerCreeps/baseOperator"; /** * This is the initializer for directives, which maps flags by their color code to the corresponding directive @@ -128,6 +129,13 @@ export function DirectiveWrapper(flag: Flag): Directive | undefined { return new DirectiveRPBunker(flag); } break; + // Power directives ==================================================================================== + case COLOR_CYAN: + switch (flag.secondaryColor) { + case COLOR_PURPLE: + return new DirectiveBaseOperator(flag); + } + break; } } diff --git a/src/directives/powerCreeps/baseOperator.ts b/src/directives/powerCreeps/baseOperator.ts new file mode 100644 index 000000000..63fb97bf4 --- /dev/null +++ b/src/directives/powerCreeps/baseOperator.ts @@ -0,0 +1,244 @@ +import {CombatPlanner, SiegeAnalysis} from "../../strategy/CombatPlanner"; +import {profile} from "../../profiler/decorator"; +import {Directive} from "../Directive"; +import {log} from "../../console/log"; +import {Visualizer} from "../../visuals/Visualizer"; + + +interface DirectiveBaseOperatorMemory extends FlagMemory { + powerPriorities: PowerConstant[] +} + +/** + * Simple directive to run a power creep where the flag name is the power creep name + */ +@profile +export class DirectiveBaseOperator extends Directive { + + static directiveName = 'BaseOperator'; + static color = COLOR_CYAN; + static secondaryColor = COLOR_PURPLE; + + memory: DirectiveBaseOperatorMemory; + + // Power Creep Hack + powerCreep: PowerCreep; + + defaultPowerPriorities: [ + PWR_GENERATE_OPS, + PWR_REGEN_SOURCE, + PWR_OPERATE_TOWER, + PWR_OPERATE_LAB, + PWR_OPERATE_SPAWN, + PWR_OPERATE_EXTENSION, + PWR_REGEN_MINERAL]; + + // overlords: { + // scout?: StationaryScoutOverlord; + // destroy?: SwarmDestroyerOverlord | PairDestroyerOverlord; + // guard?: OutpostDefenseOverlord; + // controllerAttack?: ControllerAttackerOverlord; + // }; + + constructor(flag: Flag) { + super(flag); + this.powerCreep = Game.powerCreeps[flag.name]; + if (!this.powerCreep) { + log.error(`Power Creep not found for ${this.print}, deleting directive`); + this.remove(); + } + this.memory.powerPriorities = this.defaultPowerPriorities; + } + + spawnMoarOverlords() { + } + + init(): void { + + } + + + // Wrapped powerCreep methods =========================================================================================== + + renew(powerSource: StructurePowerBank | StructurePowerSpawn) { + if (this.pos.inRangeToPos(powerSource.pos, 1)) { + return this.powerCreep.renew(powerSource); + } else { + return this.powerCreep.moveTo(powerSource); + } + } + + enablePower(controller: StructureController) { + if (this.pos.inRangeToPos(controller.pos, 1)) { + return this.powerCreep.enableRoom(controller); + } else { + return this.powerCreep.moveTo(controller); + } + } + + usePower(power: PowerConstant) { + switch(power) { + case PWR_GENERATE_OPS: this.generateOps(); + case PWR_OPERATE_SPAWN: this.operateSpawn(); + } + + } + + /** + * Generate 1/2/4/6/8 ops resource units. Cooldown 50 ticks. Required creep level: 0/2/7/14/22. + */ + generateOps() { + if (this.powerCreep.powers[PWR_GENERATE_OPS].cooldown !> 0) { + return this.powerCreep.usePower(PWR_GENERATE_OPS); + } + return ERR_TIRED; + } + + operateSpawn(spawn?: StructureSpawn) { + // if (this.powerCreep.powers[PWR_oper]) + // if (!spawn) { + // spawn = _.first(this.room!.spawns.filter(spawn => spawn.effects.length == 0)); + // if (!spawn) { + // return ERR; + // } + // } + if (this.pos.inRangeToPos(spawn.pos, 1)) { + return this.powerCreep.usePower(PWR_OPERATE_SPAWN, spawn); + } else { + return this.powerCreep.moveTo(spawn); + } + } + + operateTower(tower: StructureTower) { + if (this.pos.inRangeToPos(tower.pos, POWER_INFO[PWR_OPERATE_TOWER].range)) { + return this.powerCreep.usePower(PWR_OPERATE_TOWER, tower); + } else { + return this.powerCreep.moveTo(tower); + } + } + + operateStorage(storage: StructureStorage) { + if (this.pos.inRangeToPos(storage.pos, POWER_INFO[PWR_OPERATE_STORAGE].range)) { + return this.powerCreep.usePower(PWR_OPERATE_STORAGE, storage); + } else { + return this.powerCreep.moveTo(storage); + } + } + + operateExtensions(container: StructureStorage | StructureTerminal | StructureContainer) { + if (this.pos.inRangeToPos(container.pos, POWER_INFO[PWR_OPERATE_EXTENSION].range)) { + return this.powerCreep.usePower(PWR_OPERATE_EXTENSION, container); + } else { + return this.powerCreep.moveTo(container); + } + } + + operateObserver(observer: StructureObserver) { + if (this.pos.inRangeToPos(observer.pos, POWER_INFO[PWR_OPERATE_OBSERVER].range)) { + return this.powerCreep.usePower(PWR_OPERATE_OBSERVER, observer); + } else { + return this.powerCreep.moveTo(observer); + } + } + + operateTerminal(terminal: StructureTerminal) { + if (this.pos.inRangeToPos(terminal.pos, POWER_INFO[PWR_OPERATE_TERMINAL].range)) { + return this.powerCreep.usePower(PWR_OPERATE_TERMINAL, terminal); + } else { + return this.powerCreep.moveTo(terminal); + } + } + + operatePower(power: StructurePowerSpawn) { + if (this.pos.inRangeToPos(power.pos, POWER_INFO[PWR_OPERATE_POWER].range)) { + return this.powerCreep.usePower(PWR_OPERATE_POWER, power); + } else { + return this.powerCreep.moveTo(power); + } + } + + operateController(controller: StructureController) { + if (this.pos.inRangeToPos(controller.pos, POWER_INFO[PWR_OPERATE_CONTROLLER].range)) { + return this.powerCreep.usePower(PWR_OPERATE_CONTROLLER, controller); + } else { + return this.powerCreep.moveTo(controller); + } + } + + // operateFactory(factory: StructureFactory) { + // if (this.pos.inRangeToPos(factory.pos, POWER_INFO[PWR_OPERATE_FACTORY].range)) { + // return this.powerCreep.usePower(PWR_OPERATE_FACTORY, factory); + // } else { + // return this.moveTo(factory); + // } + // } + + shield() { + if (this.powerCreep.powers[PWR_SHIELD].cooldown !> 0) { + return this.powerCreep.usePower(PWR_SHIELD); + } + return ERR_TIRED; + } + + regenSource(source : Source) { + if (this.pos.inRangeToPos(source.pos, POWER_INFO[PWR_REGEN_SOURCE].range)) { + return this.powerCreep.usePower(PWR_REGEN_SOURCE, source); + } else { + return this.powerCreep.moveTo(source); + } + } + + regenMineral(mineral: Mineral) { + if (this.pos.inRangeToPos(mineral.pos, POWER_INFO[PWR_REGEN_MINERAL].range)) { + return this.powerCreep.usePower(PWR_REGEN_MINERAL, mineral); + } else { + return this.powerCreep.moveTo(mineral); + } + } + + fortify(rampart: StructureRampart) { + if (this.pos.inRangeToPos(rampart.pos, POWER_INFO[PWR_FORTIFY].range)) { + return this.powerCreep.usePower(PWR_FORTIFY, rampart); + } else { + return this.powerCreep.moveTo(rampart); + } + } + + operateLab(lab: StructureLab) { + if (this.pos.inRangeToPos(lab.pos, POWER_INFO[PWR_OPERATE_LAB].range)) { + return this.powerCreep.usePower(PWR_OPERATE_LAB, lab); + } else { + return this.powerCreep.moveTo(lab); + } + } + + + runPowers() { + + } + + + + run(): void { + if (!this.room) { + return; + } else if (this.powerCreep.ticksToLive == undefined && this.powerCreep.spawnCooldownTime !> 0 && this.room && this.room.powerSpawn) { + // Spawn creep + this.powerCreep.spawn(this.room.powerSpawn); + } else if (this.room.controller && !this.room.controller.isPowerEnabled) { + // Enable power + this.enablePower(this.room.controller); + } else if (this.powerCreep && this.powerCreep.ticksToLive && this.powerCreep.ticksToLive < 300 && this.room.powerSpawn) { + this.renew(this.room.powerSpawn); + } else { + this.runPowers(); + } + + + } + + visuals(): void { + Visualizer.marker(this.pos, {color: 'red'}); + } + +} \ No newline at end of file diff --git a/src/directives/powerCreeps/powers/generateOps.ts b/src/directives/powerCreeps/powers/generateOps.ts new file mode 100644 index 000000000..f2af8df29 --- /dev/null +++ b/src/directives/powerCreeps/powers/generateOps.ts @@ -0,0 +1,13 @@ +import {profile} from "../../../profiler/decorator"; +import {Power} from "./genericPower"; + +export const powerId = PWR_GENERATE_OPS; + +/** + * An abstract class for encapsulating power creep power usage. + */ +@profile +export abstract class GenerateOps extends Power{ + + run() {} +} \ No newline at end of file diff --git a/src/directives/powerCreeps/powers/genericPower.ts b/src/directives/powerCreeps/powers/genericPower.ts new file mode 100644 index 000000000..10b7787a9 --- /dev/null +++ b/src/directives/powerCreeps/powers/genericPower.ts @@ -0,0 +1,17 @@ +import {profile} from "../../../profiler/decorator"; +import {powerId} from "./generateOps"; + +/** + * An abstract class for encapsulating power creep power usage. + */ +@profile +export abstract class Power { + static powerId: PowerConstant; + + canRunPower(pc: PowerCreep) { + const power = pc.powers[powerId]; + return power && power.level > 0 && power.cooldown == 0; + } + + run() {} +} \ No newline at end of file From 2b207b60a77bf9083de4f25eb8a0eadb470692ff Mon Sep 17 00:00:00 2001 From: Matthew Roy Date: Thu, 23 May 2019 13:17:53 -0700 Subject: [PATCH 02/10] More work done --- .../powerCreeps/powers/generateOps.ts | 19 +++++++- .../powerCreeps/powers/genericPower.ts | 46 +++++++++++++++++-- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/directives/powerCreeps/powers/generateOps.ts b/src/directives/powerCreeps/powers/generateOps.ts index f2af8df29..7879ab578 100644 --- a/src/directives/powerCreeps/powers/generateOps.ts +++ b/src/directives/powerCreeps/powers/generateOps.ts @@ -1,5 +1,6 @@ import {profile} from "../../../profiler/decorator"; import {Power} from "./genericPower"; +import {log} from "../../../console/log"; export const powerId = PWR_GENERATE_OPS; @@ -7,7 +8,21 @@ export const powerId = PWR_GENERATE_OPS; * An abstract class for encapsulating power creep power usage. */ @profile -export abstract class GenerateOps extends Power{ +export abstract class GenerateOps extends Power { - run() {} + operatePower() { + if (this.powerCreep.carry.ops && this.powerCreep.carry.ops > (this.powerCreep.carryCapacity * 0.9)) { + const storage = this.powerCreep.room!.storage; + if (!storage) { + log.error(`Ops power creep with no storage`); + } else { + this.powerCreep.moveTo(this.powerCreep.room!.storage!.pos); + this.powerCreep.transfer(storage, RESOURCE_OPS, this.powerCreep.carry.ops); + } + } else { + return this.powerCreep.usePower(powerId); + } + return ERR_TIRED; + + } } \ No newline at end of file diff --git a/src/directives/powerCreeps/powers/genericPower.ts b/src/directives/powerCreeps/powers/genericPower.ts index 10b7787a9..29ef4b76d 100644 --- a/src/directives/powerCreeps/powers/genericPower.ts +++ b/src/directives/powerCreeps/powers/genericPower.ts @@ -8,10 +8,50 @@ import {powerId} from "./generateOps"; export abstract class Power { static powerId: PowerConstant; - canRunPower(pc: PowerCreep) { - const power = pc.powers[powerId]; + _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 + }; + + + _powerCreep: { + name: string; + }; + + /** + * Dereferences the Task's target + */ + get target(): RoomObject | null { + return deref(this._target.ref); + } + + canRunPower() { + const power = this.powerCreep.powers[powerId]; return power && power.level > 0 && power.cooldown == 0; } - run() {} + /** + * Return the wrapped creep which is executing this task + */ + get powerCreep(): PowerCreep { // Get task's own creep by its name + // Returns zerg wrapper instead of creep to use monkey-patched functions + return Game.powerCreeps[this._powerCreep.name]; + } + + /** + * Set the creep which is executing this task + */ + set powerCreep(pc: PowerCreep) { + this._powerCreep.name = pc.name; + } + + run() { + if (this.canRunPower()) { + this.operatePower() + } + } + + operatePower() { + + } } \ No newline at end of file From 835fed9038ed20e4374871cce1d3b5eb8df212b0 Mon Sep 17 00:00:00 2001 From: Matthew Roy Date: Fri, 24 May 2019 15:55:58 -0700 Subject: [PATCH 03/10] Opgen part done --- src/directives/powerCreeps/baseOperator.ts | 267 +++++++++--------- .../powerCreeps/powers/generateOps.ts | 12 +- 2 files changed, 142 insertions(+), 137 deletions(-) diff --git a/src/directives/powerCreeps/baseOperator.ts b/src/directives/powerCreeps/baseOperator.ts index 63fb97bf4..93adbd7fe 100644 --- a/src/directives/powerCreeps/baseOperator.ts +++ b/src/directives/powerCreeps/baseOperator.ts @@ -3,6 +3,8 @@ import {profile} from "../../profiler/decorator"; import {Directive} from "../Directive"; import {log} from "../../console/log"; import {Visualizer} from "../../visuals/Visualizer"; +import {Power} from "./powers/genericPower"; +import {GenerateOps} from "./powers/generateOps"; interface DirectiveBaseOperatorMemory extends FlagMemory { @@ -47,7 +49,7 @@ export class DirectiveBaseOperator extends Directive { log.error(`Power Creep not found for ${this.print}, deleting directive`); this.remove(); } - this.memory.powerPriorities = this.defaultPowerPriorities; + this.memory.powerPriorities = this.memory.powerPriorities || this.defaultPowerPriorities; } spawnMoarOverlords() { @@ -78,147 +80,152 @@ export class DirectiveBaseOperator extends Directive { usePower(power: PowerConstant) { switch(power) { - case PWR_GENERATE_OPS: this.generateOps(); - case PWR_OPERATE_SPAWN: this.operateSpawn(); + case PWR_GENERATE_OPS: return new GenerateOps(); +// case PWR_OPERATE_SPAWN: return this.operateSpawn(); } } - - /** - * Generate 1/2/4/6/8 ops resource units. Cooldown 50 ticks. Required creep level: 0/2/7/14/22. - */ - generateOps() { - if (this.powerCreep.powers[PWR_GENERATE_OPS].cooldown !> 0) { - return this.powerCreep.usePower(PWR_GENERATE_OPS); - } - return ERR_TIRED; - } - - operateSpawn(spawn?: StructureSpawn) { - // if (this.powerCreep.powers[PWR_oper]) - // if (!spawn) { - // spawn = _.first(this.room!.spawns.filter(spawn => spawn.effects.length == 0)); - // if (!spawn) { - // return ERR; - // } - // } - if (this.pos.inRangeToPos(spawn.pos, 1)) { - return this.powerCreep.usePower(PWR_OPERATE_SPAWN, spawn); - } else { - return this.powerCreep.moveTo(spawn); - } - } - - operateTower(tower: StructureTower) { - if (this.pos.inRangeToPos(tower.pos, POWER_INFO[PWR_OPERATE_TOWER].range)) { - return this.powerCreep.usePower(PWR_OPERATE_TOWER, tower); - } else { - return this.powerCreep.moveTo(tower); - } - } - - operateStorage(storage: StructureStorage) { - if (this.pos.inRangeToPos(storage.pos, POWER_INFO[PWR_OPERATE_STORAGE].range)) { - return this.powerCreep.usePower(PWR_OPERATE_STORAGE, storage); - } else { - return this.powerCreep.moveTo(storage); - } - } - - operateExtensions(container: StructureStorage | StructureTerminal | StructureContainer) { - if (this.pos.inRangeToPos(container.pos, POWER_INFO[PWR_OPERATE_EXTENSION].range)) { - return this.powerCreep.usePower(PWR_OPERATE_EXTENSION, container); - } else { - return this.powerCreep.moveTo(container); - } - } - - operateObserver(observer: StructureObserver) { - if (this.pos.inRangeToPos(observer.pos, POWER_INFO[PWR_OPERATE_OBSERVER].range)) { - return this.powerCreep.usePower(PWR_OPERATE_OBSERVER, observer); - } else { - return this.powerCreep.moveTo(observer); - } - } - - operateTerminal(terminal: StructureTerminal) { - if (this.pos.inRangeToPos(terminal.pos, POWER_INFO[PWR_OPERATE_TERMINAL].range)) { - return this.powerCreep.usePower(PWR_OPERATE_TERMINAL, terminal); - } else { - return this.powerCreep.moveTo(terminal); - } - } - - operatePower(power: StructurePowerSpawn) { - if (this.pos.inRangeToPos(power.pos, POWER_INFO[PWR_OPERATE_POWER].range)) { - return this.powerCreep.usePower(PWR_OPERATE_POWER, power); - } else { - return this.powerCreep.moveTo(power); - } - } - - operateController(controller: StructureController) { - if (this.pos.inRangeToPos(controller.pos, POWER_INFO[PWR_OPERATE_CONTROLLER].range)) { - return this.powerCreep.usePower(PWR_OPERATE_CONTROLLER, controller); - } else { - return this.powerCreep.moveTo(controller); - } - } - - // operateFactory(factory: StructureFactory) { - // if (this.pos.inRangeToPos(factory.pos, POWER_INFO[PWR_OPERATE_FACTORY].range)) { - // return this.powerCreep.usePower(PWR_OPERATE_FACTORY, factory); + // + // /** + // * Generate 1/2/4/6/8 ops resource units. Cooldown 50 ticks. Required creep level: 0/2/7/14/22. + // */ + // generateOps() { + // if (this.powerCreep.powers[PWR_GENERATE_OPS].cooldown !> 0) { + // return this.powerCreep.usePower(PWR_GENERATE_OPS); + // } + // return ERR_TIRED; + // } + // + // operateSpawn(spawn?: StructureSpawn) { + // // if (this.powerCreep.powers[PWR_oper]) + // // if (!spawn) { + // // spawn = _.first(this.room!.spawns.filter(spawn => spawn.effects.length == 0)); + // // if (!spawn) { + // // return ERR; + // // } + // // } + // if (this.pos.inRangeToPos(spawn.pos, 1)) { + // return this.powerCreep.usePower(PWR_OPERATE_SPAWN, spawn); // } else { - // return this.moveTo(factory); + // return this.powerCreep.moveTo(spawn); + // } + // } + // + // operateTower(tower: StructureTower) { + // if (this.pos.inRangeToPos(tower.pos, POWER_INFO[PWR_OPERATE_TOWER].range)) { + // return this.powerCreep.usePower(PWR_OPERATE_TOWER, tower); + // } else { + // return this.powerCreep.moveTo(tower); + // } + // } + // + // operateStorage(storage: StructureStorage) { + // if (this.pos.inRangeToPos(storage.pos, POWER_INFO[PWR_OPERATE_STORAGE].range)) { + // return this.powerCreep.usePower(PWR_OPERATE_STORAGE, storage); + // } else { + // return this.powerCreep.moveTo(storage); + // } + // } + // + // operateExtensions(container: StructureStorage | StructureTerminal | StructureContainer) { + // if (this.pos.inRangeToPos(container.pos, POWER_INFO[PWR_OPERATE_EXTENSION].range)) { + // return this.powerCreep.usePower(PWR_OPERATE_EXTENSION, container); + // } else { + // return this.powerCreep.moveTo(container); + // } + // } + // + // operateObserver(observer: StructureObserver) { + // if (this.pos.inRangeToPos(observer.pos, POWER_INFO[PWR_OPERATE_OBSERVER].range)) { + // return this.powerCreep.usePower(PWR_OPERATE_OBSERVER, observer); + // } else { + // return this.powerCreep.moveTo(observer); + // } + // } + // + // operateTerminal(terminal: StructureTerminal) { + // if (this.pos.inRangeToPos(terminal.pos, POWER_INFO[PWR_OPERATE_TERMINAL].range)) { + // return this.powerCreep.usePower(PWR_OPERATE_TERMINAL, terminal); + // } else { + // return this.powerCreep.moveTo(terminal); + // } + // } + // + // operatePower(power: StructurePowerSpawn) { + // if (this.pos.inRangeToPos(power.pos, POWER_INFO[PWR_OPERATE_POWER].range)) { + // return this.powerCreep.usePower(PWR_OPERATE_POWER, power); + // } else { + // return this.powerCreep.moveTo(power); + // } + // } + // + // operateController(controller: StructureController) { + // if (this.pos.inRangeToPos(controller.pos, POWER_INFO[PWR_OPERATE_CONTROLLER].range)) { + // return this.powerCreep.usePower(PWR_OPERATE_CONTROLLER, controller); + // } else { + // return this.powerCreep.moveTo(controller); + // } + // } + // + // // operateFactory(factory: StructureFactory) { + // // if (this.pos.inRangeToPos(factory.pos, POWER_INFO[PWR_OPERATE_FACTORY].range)) { + // // return this.powerCreep.usePower(PWR_OPERATE_FACTORY, factory); + // // } else { + // // return this.moveTo(factory); + // // } + // // } + // + // shield() { + // if (this.powerCreep.powers[PWR_SHIELD].cooldown !> 0) { + // return this.powerCreep.usePower(PWR_SHIELD); + // } + // return ERR_TIRED; + // } + // + // regenSource(source : Source) { + // if (this.pos.inRangeToPos(source.pos, POWER_INFO[PWR_REGEN_SOURCE].range)) { + // return this.powerCreep.usePower(PWR_REGEN_SOURCE, source); + // } else { + // return this.powerCreep.moveTo(source); + // } + // } + // + // regenMineral(mineral: Mineral) { + // if (this.pos.inRangeToPos(mineral.pos, POWER_INFO[PWR_REGEN_MINERAL].range)) { + // return this.powerCreep.usePower(PWR_REGEN_MINERAL, mineral); + // } else { + // return this.powerCreep.moveTo(mineral); + // } + // } + // + // fortify(rampart: StructureRampart) { + // if (this.pos.inRangeToPos(rampart.pos, POWER_INFO[PWR_FORTIFY].range)) { + // return this.powerCreep.usePower(PWR_FORTIFY, rampart); + // } else { + // return this.powerCreep.moveTo(rampart); + // } + // } + // + // operateLab(lab: StructureLab) { + // if (this.pos.inRangeToPos(lab.pos, POWER_INFO[PWR_OPERATE_LAB].range)) { + // return this.powerCreep.usePower(PWR_OPERATE_LAB, lab); + // } else { + // return this.powerCreep.moveTo(lab); // } // } - - shield() { - if (this.powerCreep.powers[PWR_SHIELD].cooldown !> 0) { - return this.powerCreep.usePower(PWR_SHIELD); - } - return ERR_TIRED; - } - - regenSource(source : Source) { - if (this.pos.inRangeToPos(source.pos, POWER_INFO[PWR_REGEN_SOURCE].range)) { - return this.powerCreep.usePower(PWR_REGEN_SOURCE, source); - } else { - return this.powerCreep.moveTo(source); - } - } - - regenMineral(mineral: Mineral) { - if (this.pos.inRangeToPos(mineral.pos, POWER_INFO[PWR_REGEN_MINERAL].range)) { - return this.powerCreep.usePower(PWR_REGEN_MINERAL, mineral); - } else { - return this.powerCreep.moveTo(mineral); - } - } - - fortify(rampart: StructureRampart) { - if (this.pos.inRangeToPos(rampart.pos, POWER_INFO[PWR_FORTIFY].range)) { - return this.powerCreep.usePower(PWR_FORTIFY, rampart); - } else { - return this.powerCreep.moveTo(rampart); - } - } - - operateLab(lab: StructureLab) { - if (this.pos.inRangeToPos(lab.pos, POWER_INFO[PWR_OPERATE_LAB].range)) { - return this.powerCreep.usePower(PWR_OPERATE_LAB, lab); - } else { - return this.powerCreep.moveTo(lab); - } - } runPowers() { - + const priorities = this.memory.powerPriorities; + for (let powerId of priorities) { + let powerToUse = this.usePower(powerId); + if (powerToUse && powerToUse.operatePower()) { + break; + } + } } - run(): void { if (!this.room) { return; diff --git a/src/directives/powerCreeps/powers/generateOps.ts b/src/directives/powerCreeps/powers/generateOps.ts index 7879ab578..e7b5f90ee 100644 --- a/src/directives/powerCreeps/powers/generateOps.ts +++ b/src/directives/powerCreeps/powers/generateOps.ts @@ -8,21 +8,19 @@ export const powerId = PWR_GENERATE_OPS; * An abstract class for encapsulating power creep power usage. */ @profile -export abstract class GenerateOps extends Power { - +export class GenerateOps extends Power { operatePower() { if (this.powerCreep.carry.ops && this.powerCreep.carry.ops > (this.powerCreep.carryCapacity * 0.9)) { - const storage = this.powerCreep.room!.storage; - if (!storage) { + const terminal = this.powerCreep.room!.terminal; + if (!terminal) { log.error(`Ops power creep with no storage`); } else { - this.powerCreep.moveTo(this.powerCreep.room!.storage!.pos); - this.powerCreep.transfer(storage, RESOURCE_OPS, this.powerCreep.carry.ops); + this.powerCreep.moveTo(terminal); + this.powerCreep.transfer(terminal, RESOURCE_OPS, this.powerCreep.carry.ops); } } else { return this.powerCreep.usePower(powerId); } return ERR_TIRED; - } } \ No newline at end of file From 2062d72d2c93c5b3d0ff0c8fe8b977fbc590ff71 Mon Sep 17 00:00:00 2001 From: Matthew Roy Date: Fri, 24 May 2019 17:21:26 -0700 Subject: [PATCH 04/10] Making the tasks work --- src/directives/powerCreeps/baseOperator.ts | 42 ++++++++++++------- .../powerCreeps/powers/generateOps.ts | 5 +++ .../powerCreeps/powers/genericPower.ts | 15 +++++++ 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/directives/powerCreeps/baseOperator.ts b/src/directives/powerCreeps/baseOperator.ts index 93adbd7fe..f094a09fc 100644 --- a/src/directives/powerCreeps/baseOperator.ts +++ b/src/directives/powerCreeps/baseOperator.ts @@ -8,7 +8,7 @@ import {GenerateOps} from "./powers/generateOps"; interface DirectiveBaseOperatorMemory extends FlagMemory { - powerPriorities: PowerConstant[] + powerPriorities: PowerConstant[]; } /** @@ -26,7 +26,7 @@ export class DirectiveBaseOperator extends Directive { // Power Creep Hack powerCreep: PowerCreep; - defaultPowerPriorities: [ + defaultPowerPriorities: PowerConstant[] = [ PWR_GENERATE_OPS, PWR_REGEN_SOURCE, PWR_OPERATE_TOWER, @@ -63,24 +63,29 @@ export class DirectiveBaseOperator extends Directive { // Wrapped powerCreep methods =========================================================================================== renew(powerSource: StructurePowerBank | StructurePowerSpawn) { - if (this.pos.inRangeToPos(powerSource.pos, 1)) { + if (this.powerCreep.pos.inRangeToPos(powerSource.pos, 1)) { return this.powerCreep.renew(powerSource); } else { - return this.powerCreep.moveTo(powerSource); + return this.powerCreep.moveTo(powerSource, {ignoreRoads: true, range: 1, swampCost: 1, reusePath: 0, visualizePathStyle: {lineStyle: "dashed", fill: 'yellow'}}); } } enablePower(controller: StructureController) { - if (this.pos.inRangeToPos(controller.pos, 1)) { + log.alert(`Trying to enable power for ${controller} with `); + if (this.powerCreep.pos.inRangeToPos(controller.pos, 1)) { return this.powerCreep.enableRoom(controller); } else { - return this.powerCreep.moveTo(controller); + //let path = this.powerCreep.pos.findPathTo(controller, {ignoreRoads: true, range: 1, swampCost: 1}); + //log.alert(`Trying to enable power for ${controller} with ${JSON.stringify(path)}`); + //return this.powerCreep.moveByPath(path); + return this.powerCreep.moveTo(controller.pos, {ignoreRoads: true, range: 1, swampCost: 1, reusePath: 0, visualizePathStyle: {lineStyle: "solid"}}); } } usePower(power: PowerConstant) { + console.log(`The power constant is ${power}`) switch(power) { - case PWR_GENERATE_OPS: return new GenerateOps(); + case PWR_GENERATE_OPS: return new GenerateOps(this.powerCreep); // case PWR_OPERATE_SPAWN: return this.operateSpawn(); } @@ -217,8 +222,10 @@ export class DirectiveBaseOperator extends Directive { runPowers() { const priorities = this.memory.powerPriorities; - for (let powerId of priorities) { - let powerToUse = this.usePower(powerId); + console.log(`Powerid of priority list of ${priorities}`); + for (let powerId in priorities) { + console.log(`Powerid of ${powerId} and list of ${priorities}`); + let powerToUse = this.usePower(priorities[powerId]); if (powerToUse && powerToUse.operatePower()) { break; } @@ -227,18 +234,23 @@ export class DirectiveBaseOperator extends Directive { run(): void { + console.log(`Running power creep ${JSON.stringify(this.powerCreep)} with ttl ${this.powerCreep.ticksToLive} with ${this.room!.powerSpawn}`); if (!this.room) { return; - } else if (this.powerCreep.ticksToLive == undefined && this.powerCreep.spawnCooldownTime !> 0 && this.room && this.room.powerSpawn) { + } else if (!this.powerCreep.ticksToLive && this.room && this.room.powerSpawn) { // Spawn creep - this.powerCreep.spawn(this.room.powerSpawn); + let res = this.powerCreep.spawn(this.room.powerSpawn); + log.alert(`Running ${this.powerCreep} with spawn of ${res}`); } else if (this.room.controller && !this.room.controller.isPowerEnabled) { // Enable power - this.enablePower(this.room.controller); - } else if (this.powerCreep && this.powerCreep.ticksToLive && this.powerCreep.ticksToLive < 300 && this.room.powerSpawn) { - this.renew(this.room.powerSpawn); + let res = this.enablePower(this.room.controller); + log.alert(`Running ${this.powerCreep} with enable power of ${res}`); + } else if (this.powerCreep && this.powerCreep.ticksToLive && this.powerCreep.ticksToLive < 400 && this.room.powerSpawn) { + let res = this.renew(this.room.powerSpawn); + log.alert(`Running ${this.powerCreep} with renew of ${res}`); } else { - this.runPowers(); + let res = this.runPowers(); + log.alert(`Running ${this.powerCreep} with power of ${res}`); } diff --git a/src/directives/powerCreeps/powers/generateOps.ts b/src/directives/powerCreeps/powers/generateOps.ts index e7b5f90ee..2f02070bd 100644 --- a/src/directives/powerCreeps/powers/generateOps.ts +++ b/src/directives/powerCreeps/powers/generateOps.ts @@ -9,6 +9,11 @@ export const powerId = PWR_GENERATE_OPS; */ @profile export class GenerateOps extends Power { + + constructor(powerCreep: PowerCreep, target?: RoomObject) { + super(powerCreep, target); + } + operatePower() { if (this.powerCreep.carry.ops && this.powerCreep.carry.ops > (this.powerCreep.carryCapacity * 0.9)) { const terminal = this.powerCreep.room!.terminal; diff --git a/src/directives/powerCreeps/powers/genericPower.ts b/src/directives/powerCreeps/powers/genericPower.ts index 29ef4b76d..97a07042e 100644 --- a/src/directives/powerCreeps/powers/genericPower.ts +++ b/src/directives/powerCreeps/powers/genericPower.ts @@ -1,5 +1,6 @@ import {profile} from "../../../profiler/decorator"; import {powerId} from "./generateOps"; +import {log} from "../../../console/log"; /** * An abstract class for encapsulating power creep power usage. @@ -18,6 +19,20 @@ export abstract class Power { name: string; }; + constructor(powerCreep: PowerCreep, target?: RoomObject) { + log.notify(`Creating power task for ${powerCreep}`); + this._powerCreep = { + name: powerCreep.name, + }; + if (target) { + this._target = { + ref : target.ref, + _pos: target.pos, + } + } + + } + /** * Dereferences the Task's target */ From 3fca31d7de893838f27e359fbc66ca277cf3aa28 Mon Sep 17 00:00:00 2001 From: Matthew Roy Date: Fri, 24 May 2019 23:15:03 -0700 Subject: [PATCH 05/10] Temporary commit, remove later --- src/declarations/prototypes.d.ts | 11 + src/zerg/PowerZerg.ts | 51 +++ src/zerg/ZergShell.ts | 592 +++++++++++++++++++++++++++++++ 3 files changed, 654 insertions(+) create mode 100644 src/zerg/PowerZerg.ts create mode 100644 src/zerg/ZergShell.ts diff --git a/src/declarations/prototypes.d.ts b/src/declarations/prototypes.d.ts index 1d0e9f187..093f452a9 100644 --- a/src/declarations/prototypes.d.ts +++ b/src/declarations/prototypes.d.ts @@ -7,6 +7,17 @@ interface Creep { inRampart: boolean; } +interface PowerCreep { + hitsPredicted?: number; + intel?: { [property: string]: number }; + memory: CreepMemory; + fatigue: number; + body: BodyPartDefinition[]; + boosts: _ResourceConstantSansEnergy[]; + boostCounts: { [boostType: string]: number }; + inRampart: boolean; +} + interface ConstructionSite { isWalkable: boolean; } diff --git a/src/zerg/PowerZerg.ts b/src/zerg/PowerZerg.ts new file mode 100644 index 000000000..36e5bff54 --- /dev/null +++ b/src/zerg/PowerZerg.ts @@ -0,0 +1,51 @@ +import {CombatIntel} from '../intel/CombatIntel'; +import {Movement, NO_ACTION} from '../movement/Movement'; +import {profile} from '../profiler/decorator'; +import {CombatTargeting} from '../targeting/CombatTargeting'; +import {GoalFinder} from '../targeting/GoalFinder'; +import {randomHex} from '../utilities/utils'; +import {Zerg} from './Zerg'; + +interface CombatZergMemory extends CreepMemory { + recovering: boolean; + lastInDanger: number; + partner?: string; + swarm?: string; +} + +export const DEFAULT_PARTNER_TICK_DIFFERENCE = 650; +export const DEFAULT_SWARM_TICK_DIFFERENCE = 500; + +/** + * CombatZerg is an extension of the Zerg class which contains additional combat-related methods + */ +@profile +export class PowerZerg extends Zerg { + + memory: CombatZergMemory; + isPowerZerg: boolean; + + constructor(creep: Creep, notifyWhenAttacked = true) { + super(creep, notifyWhenAttacked); + this.isPowerZerg = true; + _.defaults(this.memory, { + recovering : false, + lastInDanger: 0, + targets : {} + }); + } + + static fatigue() { + return 0; + } + + static body() { + return [MOVE]; + } + + static attack(target: Creep | Structure): 0 | -1 | -4 | -7 | -9 | -12 | -11 { + return ERR_TIRED; + } + + +} diff --git a/src/zerg/ZergShell.ts b/src/zerg/ZergShell.ts new file mode 100644 index 000000000..44b11c033 --- /dev/null +++ b/src/zerg/ZergShell.ts @@ -0,0 +1,592 @@ +import {Colony} from '../Colony'; +import {log} from '../console/log'; +import {isCreep, isZerg} from '../declarations/typeGuards'; +import {CombatIntel} from '../intel/CombatIntel'; +import {Movement, MoveOptions} from '../movement/Movement'; +import {Overlord} from '../overlords/Overlord'; +import {profile} from '../profiler/decorator'; +import {initializeTask} from '../tasks/initializer'; +import {Task} from '../tasks/Task'; +import {NEW_OVERMIND_INTERVAL} from '../~settings'; +import {PowerZerg} from "./PowerZerg"; + +export function getOverlord(creep: Zerg | Creep): Overlord | null { + if (creep.memory[_MEM.OVERLORD]) { + return Overmind.overlords[creep.memory[_MEM.OVERLORD]!] || null; + } else { + return null; + } +} + +export function setOverlord(creep: Zerg | Creep, newOverlord: Overlord | null) { + // Remove cache references to old assignments + const roleName = creep.memory.role; + const ref = creep.memory[_MEM.OVERLORD]; + const oldOverlord: Overlord | null = ref ? Overmind.overlords[ref] : null; + if (ref && Overmind.cache.overlords[ref] && Overmind.cache.overlords[ref][roleName]) { + _.remove(Overmind.cache.overlords[ref][roleName], name => name == creep.name); + } + if (newOverlord) { + // Change to the new overlord's colony + creep.memory[_MEM.COLONY] = newOverlord.colony.name; + // Change assignments in memory + creep.memory[_MEM.OVERLORD] = newOverlord.ref; + // Update the cache references + if (!Overmind.cache.overlords[newOverlord.ref]) { + Overmind.cache.overlords[newOverlord.ref] = {}; + } + if (!Overmind.cache.overlords[newOverlord.ref][roleName]) { + Overmind.cache.overlords[newOverlord.ref][roleName] = []; + } + Overmind.cache.overlords[newOverlord.ref][roleName].push(creep.name); + } else { + creep.memory[_MEM.OVERLORD] = null; + } + if (oldOverlord) oldOverlord.recalculateCreeps(); + if (newOverlord) newOverlord.recalculateCreeps(); +} + +export function normalizeZerg(creep: Zerg | Creep): Zerg | Creep { + return Overmind.zerg[creep.name] || creep; +} + +export function toCreep(creep: Zerg | Creep): Creep { + return isZerg(creep) ? creep.creep : creep; +} + +// Last pipeline is more complex because it depends on the energy a creep has; sidelining this for now +const actionPipelines: string[][] = [ + ['harvest', 'attack', 'build', 'repair', 'dismantle', 'attackController', 'rangedHeal', 'heal'], + ['rangedAttack', 'rangedMassAttack', 'build', 'repair', 'rangedHeal'], + // ['upgradeController', 'build', 'repair', 'withdraw', 'transfer', 'drop'], +]; + +interface ParkingOptions { + range: number; + exactRange: boolean; + offroad: boolean; +} + +interface FleeOptions { + dropEnergy?: boolean; + invalidateTask?: boolean; +} + +const RANGES = { + BUILD : 3, + REPAIR : 3, + TRANSFER: 1, + WITHDRAW: 1, + HARVEST : 1, + DROP : 0, +}; + +/** + * The Zerg class is a wrapper for owned creeps and contains all wrapped creep methods and many additional methods for + * direct control of a creep. + */ +@profile +export class Zerg { + + creep: Creep | PowerZerg; // The creep that this wrapper class will control + body: BodyPartDefinition[]; // These properties are all wrapped from this.creep.* to this.* + carry: StoreDefinition; // | + carryCapacity: number; // | + fatigue: number; // | + hits: number; // | + hitsMax: number; // | + id: string; // | + memory: CreepMemory; // | See the ICreepMemory interface for structure + name: string; // | + pos: RoomPosition; // | + nextPos: RoomPosition; // | The next position the creep will be in after registering a move intent + ref: string; // | + roleName: string; // | + room: Room; // | + saying: string; // | + spawning: boolean; // | + ticksToLive: number | undefined; // | + lifetime: number; + actionLog: { [actionName: string]: boolean }; // Tracks the actions that a creep has completed this tick + blockMovement: boolean; // Whether the zerg is allowed to move or not + private _task: Task | null; // Cached Task object that is instantiated once per tick and on change + + constructor(creep: Creep, notifyWhenAttacked = true) { + // Copy over creep references + this.creep = creep; + this.body = creep.body; + this.carry = creep.carry; + this.carryCapacity = creep.carryCapacity; + this.fatigue = creep.fatigue; + this.hits = creep.hits; + this.hitsMax = creep.hitsMax; + this.id = creep.id; + this.memory = creep.memory; + this.name = creep.name; + this.pos = creep.pos; + this.nextPos = creep.pos; + this.ref = creep.ref; + this.roleName = creep.memory.role; + this.room = creep.room; + this.saying = creep.saying; + this.spawning = creep.spawning; + this.ticksToLive = creep.ticksToLive; + // Extra properties + this.lifetime = this.getBodyparts(CLAIM) > 0 ? CREEP_CLAIM_LIFE_TIME : CREEP_LIFE_TIME; + this.actionLog = {}; + this.blockMovement = false; + // Register global references + Overmind.zerg[this.name] = this; + global[this.name] = this; + // Handle attack notification when at lifetime - 1 + if (!notifyWhenAttacked && (this.ticksToLive || 0) >= this.lifetime - (NEW_OVERMIND_INTERVAL + 1)) { + // creep.notifyWhenAttacked only uses the 0.2CPU intent cost if it changes the intent value + this.notifyWhenAttacked(notifyWhenAttacked); + } + } + + /** + * Refresh all changeable properties of the creep or delete from Overmind and global when dead + */ + refresh(): void { + const creep = Game.creeps[this.name]; + if (creep) { + this.creep = creep; + this.pos = creep.pos; + this.nextPos = creep.pos; + this.body = creep.body; + this.carry = creep.carry; + this.carryCapacity = creep.carryCapacity; + this.fatigue = creep.fatigue; + this.hits = creep.hits; + this.memory = creep.memory; + this.roleName = creep.memory.role; + this.room = creep.room; + this.saying = creep.saying; + this.spawning = creep.spawning; + this.ticksToLive = creep.ticksToLive; + this.actionLog = {}; + this.blockMovement = false; + this._task = null; // todo + } else { + log.debug(`Deleting from global`); + delete Overmind.zerg[this.name]; + delete global[this.name]; + } + } + + debug(...args: any[]) { + if (this.memory.debug) { + log.debug(this.print, args); + } + } + + get ticksUntilSpawned(): number | undefined { + if (this.spawning) { + const spawner = this.pos.lookForStructure(STRUCTURE_SPAWN) as StructureSpawn; + if (spawner && spawner.spawning) { + return spawner.spawning.remainingTime; + } else { + // Shouldn't ever get here + console.log(`Error determining ticks to spawn for ${this.name} @ ${this.pos.print}!`); + } + } + } + + get print(): string { + return '[' + this.name + ']'; + } + + cancelOrder(methodName: string): OK | ERR_NOT_FOUND { + const result = this.creep.cancelOrder(methodName); + if (result == OK) this.actionLog[methodName] = false; + return result; + } + + drop(resourceType: ResourceConstant, amount?: number) { + const result = this.creep.drop(resourceType, amount); + if (!this.actionLog.drop) this.actionLog.drop = (result == OK); + return result; + } + + goDrop(pos: RoomPosition, resourceType: ResourceConstant, amount?: number) { + if (this.pos.inRangeToPos(pos, RANGES.DROP)) { + return this.drop(resourceType, amount); + } else { + return this.goTo(pos); + } + } + + generateSafeMode(target: StructureController) { + return this.creep.generateSafeMode(target); + } + + harvest(source: Source | Mineral) { + const result = this.creep.harvest(source); + if (!this.actionLog.harvest) this.actionLog.harvest = (result == OK); + return result; + } + + goHarvest(source: Source | Mineral) { + if (this.pos.inRangeToPos(source.pos, RANGES.HARVEST)) { + return this.harvest(source); + } else { + return this.goTo(source); + } + } + + move(direction: DirectionConstant, force = false) { + if (!this.blockMovement && !force) { + const result = this.creep.move(direction); + if (result == OK) { + if (!this.actionLog.move) this.actionLog.move = true; + this.nextPos = this.pos.getPositionAtDirection(direction); + } + return result; + } else { + return ERR_BUSY; + } + } + + notifyWhenAttacked(enabled: boolean) { + return this.creep.notifyWhenAttacked(enabled); + } + + pickup(resource: Resource) { + const result = this.creep.pickup(resource); + if (!this.actionLog.pickup) this.actionLog.pickup = (result == OK); + return result; + } + + /* Say a message; maximum message length is 10 characters */ + say(message: string, pub?: boolean) { + return this.creep.say(message, pub); + } + + signController(target: StructureController, text: string) { + const result = this.creep.signController(target, text); + if (!this.actionLog.signController) this.actionLog.signController = (result == OK); + return result; + } + + suicide() { + return this.creep.suicide(); + } + + transfer(target: Creep | Zerg | Structure, resourceType: ResourceConstant = RESOURCE_ENERGY, amount?: number) { + let result: ScreepsReturnCode; + if (target instanceof Zerg) { + result = this.creep.transfer(target.creep, resourceType, amount); + } else { + result = this.creep.transfer(target, resourceType, amount); + } + if (!this.actionLog.transfer) this.actionLog.transfer = (result == OK); + return result; + } + + goTransfer(target: Creep | Zerg | Structure, resourceType: ResourceConstant = RESOURCE_ENERGY, amount?: number) { + if (this.pos.inRangeToPos(target.pos, RANGES.TRANSFER)) { + return this.transfer(target, resourceType, amount); + } else { + return this.goTo(target); + } + } + + withdraw(target: Structure | Tombstone, resourceType: ResourceConstant = RESOURCE_ENERGY, amount?: number) { + const result = this.creep.withdraw(target, resourceType, amount); + if (!this.actionLog.withdraw) this.actionLog.withdraw = (result == OK); + return result; + } + + goWithdraw(target: Structure | Tombstone, resourceType: ResourceConstant = RESOURCE_ENERGY, amount?: number) { + if (this.pos.inRangeToPos(target.pos, RANGES.WITHDRAW)) { + return this.withdraw(target, resourceType, amount); + } else { + return this.goTo(target); + } + } + + // Simultaneous creep actions -------------------------------------------------------------------------------------- + + /** + * Determine whether the given action will conflict with an action the creep has already taken. + * See http://docs.screeps.com/simultaneous-actions.html for more details. + */ + canExecute(actionName: string): boolean { + // Only one action can be executed from within a single pipeline + let conflictingActions: string[] = [actionName]; + for (const pipeline of actionPipelines) { + if (pipeline.includes(actionName)) conflictingActions = conflictingActions.concat(pipeline); + } + for (const action of conflictingActions) { + if (this.actionLog[action]) { + return false; + } + } + return true; + } + + // Body configuration and related data ----------------------------------------------------------------------------- + + getActiveBodyparts(type: BodyPartConstant): number { + return this.creep.getActiveBodyparts(type); + } + + /* The same as creep.getActiveBodyparts, but just counts bodyparts regardless of condition. */ + getBodyparts(partType: BodyPartConstant): number { + return _.filter(this.body, (part: BodyPartDefinition) => part.type == partType).length; + } + + // Custom creep methods ============================================================================================ + + // Carry methods + + get hasMineralsInCarry(): boolean { + for (const resourceType in this.carry) { + if (resourceType != RESOURCE_ENERGY && (this.carry[resourceType] || 0) > 0) { + return true; + } + } + return false; + } + + // Boosting logic -------------------------------------------------------------------------------------------------- + + get boosts(): _ResourceConstantSansEnergy[] { + return this.creep.boosts; + } + + get boostCounts(): { [boostType: string]: number } { + return this.creep.boostCounts; + } + + get needsBoosts(): boolean { + if (this.overlord) { + return this.overlord.shouldBoost(this); + } + return false; + } + + // Overlord logic -------------------------------------------------------------------------------------------------- + + get overlord(): Overlord | null { + return getOverlord(this); + } + + set overlord(newOverlord: Overlord | null) { + setOverlord(this, newOverlord); + } + + /* Reassigns the creep to work under a new overlord and as a new role. */ + reassign(newOverlord: Overlord | null, newRole: string, invalidateTask = true) { + this.overlord = newOverlord; + this.roleName = newRole; + this.memory.role = newRole; + if (invalidateTask) { + this.task = null; + } + } + + // Task logic ------------------------------------------------------------------------------------------------------ + + /** + * Wrapper for _task + */ + get task(): Task | null { + if (!this._task) { + this._task = this.memory.task ? initializeTask(this.memory.task) : null; + } + return this._task; + } + + /** + * Assign the creep a task with the setter, replacing creep.assign(Task) + */ + set task(task: Task | null) { + // Unregister target from old task if applicable + const oldProtoTask = this.memory.task; + if (oldProtoTask) { + const oldRef = oldProtoTask._target.ref; + if (Overmind.cache.targets[oldRef]) { + _.remove(Overmind.cache.targets[oldRef], name => name == this.name); + } + } + // Set the new task + this.memory.task = task ? task.proto : null; + if (task) { + if (task.target) { + // Register task target in cache if it is actively targeting something (excludes goTo and similar) + if (!Overmind.cache.targets[task.target.ref]) { + Overmind.cache.targets[task.target.ref] = []; + } + Overmind.cache.targets[task.target.ref].push(this.name); + } + // Register references to creep + task.creep = this; + } + // Clear cache + this._task = null; + } + + /** + * Does the creep have a valid task at the moment? + */ + get hasValidTask(): boolean { + return !!this.task && this.task.isValid(); + } + + /** + * Creeps are idle if they don't have a task. + */ + get isIdle(): boolean { + return !this.task || !this.task.isValid(); + } + + /** + * Execute the task you currently have. + */ + run(): number | undefined { + if (this.task) { + return this.task.run(); + } + } + + // Colony association ---------------------------------------------------------------------------------------------- + + /** + * Colony that the creep belongs to. + */ + get colony(): Colony { + return Overmind.colonies[this.memory[_MEM.COLONY]]; + } + + set colony(newColony: Colony) { + this.memory[_MEM.COLONY] = newColony.name; + } + + /** + * If the creep is in a colony room or outpost + */ + get inColonyRoom(): boolean { + return Overmind.colonyMap[this.room.name] == this.memory[_MEM.COLONY]; + } + + // Movement and location ------------------------------------------------------------------------------------------- + + goTo(destination: RoomPosition | HasPos, options: MoveOptions = {}) { + return Movement.goTo(this, destination, options); + } + + goToRoom(roomName: string, options: MoveOptions = {}) { + return Movement.goToRoom(this, roomName, options); + } + + inSameRoomAs(target: HasPos): boolean { + return this.pos.roomName == target.pos.roomName; + } + + safelyInRoom(roomName: string): boolean { + return this.room.name == roomName && !this.pos.isEdge; + } + + get inRampart(): boolean { + return this.creep.inRampart; + } + + get isMoving(): boolean { + const moveData = this.memory._go as MoveData | undefined; + return !!moveData && !!moveData.path && moveData.path.length > 1; + } + + /** + * Kite around hostiles in the room + */ + kite(avoidGoals: (RoomPosition | HasPos)[] = this.room.hostiles, options: MoveOptions = {}): number | undefined { + _.defaults(options, { + fleeRange: 5 + }); + return Movement.kite(this, avoidGoals, options); + } + + private defaultFleeGoals() { + let fleeGoals: (RoomPosition | HasPos)[] = []; + fleeGoals = fleeGoals.concat(this.room.hostiles) + .concat(_.filter(this.room.keeperLairs, lair => (lair.ticksToSpawn || Infinity) < 10)); + return fleeGoals; + } + + /** + * Flee from hostiles in the room, while not repathing every tick + */ + flee(avoidGoals: (RoomPosition | HasPos)[] = this.room.fleeDefaults, + fleeOptions: FleeOptions = {}, + moveOptions: MoveOptions = {}): boolean { + if (avoidGoals.length == 0) { + return false; + } else if (this.room.controller && this.room.controller.my && this.room.controller.safeMode) { + return false; + } else { + const fleeing = Movement.flee(this, avoidGoals, fleeOptions.dropEnergy, moveOptions) != undefined; + if (fleeing) { + // Drop energy if needed + if (fleeOptions.dropEnergy && this.carry.energy > 0) { + const nearbyContainers = this.pos.findInRange(this.room.storageUnits, 1); + if (nearbyContainers.length > 0) { + this.transfer(_.first(nearbyContainers), RESOURCE_ENERGY); + } else { + this.drop(RESOURCE_ENERGY); + } + } + // Invalidate task + if (fleeOptions.invalidateTask) { + this.task = null; + } + } + return fleeing; + } + } + + /** + * Park the creep off-roads + */ + park(pos: RoomPosition = this.pos, maintainDistance = false): number { + return Movement.park(this, pos, maintainDistance); + } + + /** + * Moves a creep off of the current tile to the first available neighbor + */ + moveOffCurrentPos(): number | undefined { + return Movement.moveOffCurrentPos(this); + } + + /** + * Moves onto an exit tile + */ + moveOnExit(): ScreepsReturnCode | undefined { + return Movement.moveOnExit(this); + } + + /** + * Moves off of an exit tile + */ + moveOffExit(avoidSwamp = true): ScreepsReturnCode { + return Movement.moveOffExit(this, avoidSwamp); + } + + moveOffExitToward(pos: RoomPosition, detour = true): number | undefined { + return Movement.moveOffExitToward(this, pos, detour); + } + + // Miscellaneous fun stuff ----------------------------------------------------------------------------------------- + + sayLoop(messageList: string[], pub?: boolean) { + return this.say(messageList[Game.time % messageList.length], pub); + } + + sayRandom(phrases: string[], pub?: boolean) { + return this.say(phrases[Math.floor(Math.random() * phrases.length)], pub); + } + +} + From 108c55b4be036a9672cca63c9c2d467f7d61a398 Mon Sep 17 00:00:00 2001 From: Matthew Roy Date: Wed, 12 Jun 2019 12:48:52 -0700 Subject: [PATCH 06/10] Storing new operator form quickly --- src/directives/powerCreeps/baseOperator.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/directives/powerCreeps/baseOperator.ts b/src/directives/powerCreeps/baseOperator.ts index f094a09fc..0bee0feb3 100644 --- a/src/directives/powerCreeps/baseOperator.ts +++ b/src/directives/powerCreeps/baseOperator.ts @@ -11,6 +11,12 @@ interface DirectiveBaseOperatorMemory extends FlagMemory { powerPriorities: PowerConstant[]; } +export enum types { + opgen, + baseoperator, + basedefender +} + /** * Simple directive to run a power creep where the flag name is the power creep name */ @@ -234,6 +240,10 @@ export class DirectiveBaseOperator extends Directive { run(): void { + + // For the power creeps that just sit on power spawn + const isStationary = this.powerCreep.name.toLowerCase().indexOf(types.basedefender.toString()); + console.log(`Running power creep ${JSON.stringify(this.powerCreep)} with ttl ${this.powerCreep.ticksToLive} with ${this.room!.powerSpawn}`); if (!this.room) { return; @@ -241,11 +251,11 @@ export class DirectiveBaseOperator extends Directive { // Spawn creep let res = this.powerCreep.spawn(this.room.powerSpawn); log.alert(`Running ${this.powerCreep} with spawn of ${res}`); - } else if (this.room.controller && !this.room.controller.isPowerEnabled) { + } else if (this.room.controller && !this.room.controller.isPowerEnabled && !isStationary) { // Enable power let res = this.enablePower(this.room.controller); log.alert(`Running ${this.powerCreep} with enable power of ${res}`); - } else if (this.powerCreep && this.powerCreep.ticksToLive && this.powerCreep.ticksToLive < 400 && this.room.powerSpawn) { + } else if (this.powerCreep && this.powerCreep.ticksToLive && this.powerCreep.ticksToLive < 900 && this.room.powerSpawn) { let res = this.renew(this.room.powerSpawn); log.alert(`Running ${this.powerCreep} with renew of ${res}`); } else { From 75385eec3a6db5cb048c484707625169879fa48b Mon Sep 17 00:00:00 2001 From: Matthew Roy Date: Wed, 17 Jul 2019 11:24:25 -0700 Subject: [PATCH 07/10] Adding power spawn processing --- src/Colony.ts | 8 ++++++++ src/hiveClusters/commandCenter.ts | 8 ++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Colony.ts b/src/Colony.ts index c23be5588..451937220 100644 --- a/src/Colony.ts +++ b/src/Colony.ts @@ -546,6 +546,13 @@ export class Colony { return allAssets; } + private runPowerSpawn() { + if (this.powerSpawn && this.assets.energy > 300000 && this.powerSpawn.energy > 50 + && this.powerSpawn.power > 0) { + this.powerSpawn.processPower(); + } + } + /** * Initializes the state of the colony each tick */ @@ -567,6 +574,7 @@ export class Colony { this.linkNetwork.run(); // Run the link network this.roadLogistics.run(); // Run the road network this.roomPlanner.run(); // Run the room planner + this.runPowerSpawn(); // Run power spawn - short term this.stats(); // Log stats per tick } diff --git a/src/hiveClusters/commandCenter.ts b/src/hiveClusters/commandCenter.ts index 51e0c07ef..fc799f281 100644 --- a/src/hiveClusters/commandCenter.ts +++ b/src/hiveClusters/commandCenter.ts @@ -135,8 +135,12 @@ export class CommandCenter extends HiveCluster { } } // Refill power spawn - if (this.powerSpawn && this.powerSpawn.energy < this.powerSpawn.energyCapacity) { - this.transportRequests.requestInput(this.powerSpawn, Priority.NormalLow); + if (this.powerSpawn) { + if (this.powerSpawn.energy < this.powerSpawn.energyCapacity) { + this.transportRequests.requestInput(this.powerSpawn, Priority.NormalLow); + } else if (this.powerSpawn.power < this.powerSpawn.powerCapacity) { + this.transportRequests.requestInput(this.powerSpawn, Priority.Low, {resourceType: RESOURCE_POWER}); + } } // Refill nuker with low priority if (this.nuker) { From 6e33d733e2e2232935b12f0537f895bf26380365 Mon Sep 17 00:00:00 2001 From: Matthew Roy Date: Mon, 12 Aug 2019 12:36:06 -0700 Subject: [PATCH 08/10] No longer storing power creep reference --- src/directives/powerCreeps/baseOperator.ts | 120 +++++++++++---------- 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/src/directives/powerCreeps/baseOperator.ts b/src/directives/powerCreeps/baseOperator.ts index 0bee0feb3..545a12344 100644 --- a/src/directives/powerCreeps/baseOperator.ts +++ b/src/directives/powerCreeps/baseOperator.ts @@ -30,7 +30,8 @@ export class DirectiveBaseOperator extends Directive { memory: DirectiveBaseOperatorMemory; // Power Creep Hack - powerCreep: PowerCreep; + //powerCreep: PowerCreep; + powerCreepName: string; defaultPowerPriorities: PowerConstant[] = [ PWR_GENERATE_OPS, @@ -50,8 +51,8 @@ export class DirectiveBaseOperator extends Directive { constructor(flag: Flag) { super(flag); - this.powerCreep = Game.powerCreeps[flag.name]; - if (!this.powerCreep) { + const powerCreep = Game.powerCreeps[flag.name]; + if (!powerCreep) { log.error(`Power Creep not found for ${this.print}, deleting directive`); this.remove(); } @@ -68,30 +69,30 @@ export class DirectiveBaseOperator extends Directive { // Wrapped powerCreep methods =========================================================================================== - renew(powerSource: StructurePowerBank | StructurePowerSpawn) { - if (this.powerCreep.pos.inRangeToPos(powerSource.pos, 1)) { - return this.powerCreep.renew(powerSource); + renew(powerCreep: PowerCreep, powerSource: StructurePowerBank | StructurePowerSpawn) { + if (powerCreep.pos.inRangeToPos(powerSource.pos, 1)) { + return powerCreep.renew(powerSource); } else { - return this.powerCreep.moveTo(powerSource, {ignoreRoads: true, range: 1, swampCost: 1, reusePath: 0, visualizePathStyle: {lineStyle: "dashed", fill: 'yellow'}}); + return powerCreep.moveTo(powerSource, {ignoreRoads: true, range: 1, swampCost: 1, reusePath: 0, visualizePathStyle: {lineStyle: "dashed", fill: 'yellow'}}); } } - enablePower(controller: StructureController) { + enablePower(powerCreep: PowerCreep, controller: StructureController) { log.alert(`Trying to enable power for ${controller} with `); - if (this.powerCreep.pos.inRangeToPos(controller.pos, 1)) { - return this.powerCreep.enableRoom(controller); + if (powerCreep.pos.inRangeToPos(controller.pos, 1)) { + return powerCreep.enableRoom(controller); } else { - //let path = this.powerCreep.pos.findPathTo(controller, {ignoreRoads: true, range: 1, swampCost: 1}); + //let path = powerCreep.pos.findPathTo(controller, {ignoreRoads: true, range: 1, swampCost: 1}); //log.alert(`Trying to enable power for ${controller} with ${JSON.stringify(path)}`); - //return this.powerCreep.moveByPath(path); - return this.powerCreep.moveTo(controller.pos, {ignoreRoads: true, range: 1, swampCost: 1, reusePath: 0, visualizePathStyle: {lineStyle: "solid"}}); + //return powerCreep.moveByPath(path); + return powerCreep.moveTo(controller.pos, {ignoreRoads: true, range: 1, swampCost: 1, reusePath: 0, visualizePathStyle: {lineStyle: "solid"}}); } } - usePower(power: PowerConstant) { + usePower(powerCreep: PowerCreep, power: PowerConstant) { console.log(`The power constant is ${power}`) switch(power) { - case PWR_GENERATE_OPS: return new GenerateOps(this.powerCreep); + case PWR_GENERATE_OPS: return new GenerateOps(powerCreep); // case PWR_OPERATE_SPAWN: return this.operateSpawn(); } @@ -101,14 +102,14 @@ export class DirectiveBaseOperator extends Directive { // * Generate 1/2/4/6/8 ops resource units. Cooldown 50 ticks. Required creep level: 0/2/7/14/22. // */ // generateOps() { - // if (this.powerCreep.powers[PWR_GENERATE_OPS].cooldown !> 0) { - // return this.powerCreep.usePower(PWR_GENERATE_OPS); + // if (powerCreep.powers[PWR_GENERATE_OPS].cooldown !> 0) { + // return powerCreep.usePower(PWR_GENERATE_OPS); // } // return ERR_TIRED; // } // // operateSpawn(spawn?: StructureSpawn) { - // // if (this.powerCreep.powers[PWR_oper]) + // // if (powerCreep.powers[PWR_oper]) // // if (!spawn) { // // spawn = _.first(this.room!.spawns.filter(spawn => spawn.effects.length == 0)); // // if (!spawn) { @@ -116,122 +117,122 @@ export class DirectiveBaseOperator extends Directive { // // } // // } // if (this.pos.inRangeToPos(spawn.pos, 1)) { - // return this.powerCreep.usePower(PWR_OPERATE_SPAWN, spawn); + // return powerCreep.usePower(PWR_OPERATE_SPAWN, spawn); // } else { - // return this.powerCreep.moveTo(spawn); + // return powerCreep.moveTo(spawn); // } // } // // operateTower(tower: StructureTower) { // if (this.pos.inRangeToPos(tower.pos, POWER_INFO[PWR_OPERATE_TOWER].range)) { - // return this.powerCreep.usePower(PWR_OPERATE_TOWER, tower); + // return powerCreep.usePower(PWR_OPERATE_TOWER, tower); // } else { - // return this.powerCreep.moveTo(tower); + // return powerCreep.moveTo(tower); // } // } // // operateStorage(storage: StructureStorage) { // if (this.pos.inRangeToPos(storage.pos, POWER_INFO[PWR_OPERATE_STORAGE].range)) { - // return this.powerCreep.usePower(PWR_OPERATE_STORAGE, storage); + // return powerCreep.usePower(PWR_OPERATE_STORAGE, storage); // } else { - // return this.powerCreep.moveTo(storage); + // return powerCreep.moveTo(storage); // } // } // // operateExtensions(container: StructureStorage | StructureTerminal | StructureContainer) { // if (this.pos.inRangeToPos(container.pos, POWER_INFO[PWR_OPERATE_EXTENSION].range)) { - // return this.powerCreep.usePower(PWR_OPERATE_EXTENSION, container); + // return powerCreep.usePower(PWR_OPERATE_EXTENSION, container); // } else { - // return this.powerCreep.moveTo(container); + // return powerCreep.moveTo(container); // } // } // // operateObserver(observer: StructureObserver) { // if (this.pos.inRangeToPos(observer.pos, POWER_INFO[PWR_OPERATE_OBSERVER].range)) { - // return this.powerCreep.usePower(PWR_OPERATE_OBSERVER, observer); + // return powerCreep.usePower(PWR_OPERATE_OBSERVER, observer); // } else { - // return this.powerCreep.moveTo(observer); + // return powerCreep.moveTo(observer); // } // } // // operateTerminal(terminal: StructureTerminal) { // if (this.pos.inRangeToPos(terminal.pos, POWER_INFO[PWR_OPERATE_TERMINAL].range)) { - // return this.powerCreep.usePower(PWR_OPERATE_TERMINAL, terminal); + // return powerCreep.usePower(PWR_OPERATE_TERMINAL, terminal); // } else { - // return this.powerCreep.moveTo(terminal); + // return powerCreep.moveTo(terminal); // } // } // // operatePower(power: StructurePowerSpawn) { // if (this.pos.inRangeToPos(power.pos, POWER_INFO[PWR_OPERATE_POWER].range)) { - // return this.powerCreep.usePower(PWR_OPERATE_POWER, power); + // return powerCreep.usePower(PWR_OPERATE_POWER, power); // } else { - // return this.powerCreep.moveTo(power); + // return powerCreep.moveTo(power); // } // } // // operateController(controller: StructureController) { // if (this.pos.inRangeToPos(controller.pos, POWER_INFO[PWR_OPERATE_CONTROLLER].range)) { - // return this.powerCreep.usePower(PWR_OPERATE_CONTROLLER, controller); + // return powerCreep.usePower(PWR_OPERATE_CONTROLLER, controller); // } else { - // return this.powerCreep.moveTo(controller); + // return powerCreep.moveTo(controller); // } // } // // // operateFactory(factory: StructureFactory) { // // if (this.pos.inRangeToPos(factory.pos, POWER_INFO[PWR_OPERATE_FACTORY].range)) { - // // return this.powerCreep.usePower(PWR_OPERATE_FACTORY, factory); + // // return powerCreep.usePower(PWR_OPERATE_FACTORY, factory); // // } else { // // return this.moveTo(factory); // // } // // } // // shield() { - // if (this.powerCreep.powers[PWR_SHIELD].cooldown !> 0) { - // return this.powerCreep.usePower(PWR_SHIELD); + // if (powerCreep.powers[PWR_SHIELD].cooldown !> 0) { + // return powerCreep.usePower(PWR_SHIELD); // } // return ERR_TIRED; // } // // regenSource(source : Source) { // if (this.pos.inRangeToPos(source.pos, POWER_INFO[PWR_REGEN_SOURCE].range)) { - // return this.powerCreep.usePower(PWR_REGEN_SOURCE, source); + // return powerCreep.usePower(PWR_REGEN_SOURCE, source); // } else { - // return this.powerCreep.moveTo(source); + // return powerCreep.moveTo(source); // } // } // // regenMineral(mineral: Mineral) { // if (this.pos.inRangeToPos(mineral.pos, POWER_INFO[PWR_REGEN_MINERAL].range)) { - // return this.powerCreep.usePower(PWR_REGEN_MINERAL, mineral); + // return powerCreep.usePower(PWR_REGEN_MINERAL, mineral); // } else { - // return this.powerCreep.moveTo(mineral); + // return powerCreep.moveTo(mineral); // } // } // // fortify(rampart: StructureRampart) { // if (this.pos.inRangeToPos(rampart.pos, POWER_INFO[PWR_FORTIFY].range)) { - // return this.powerCreep.usePower(PWR_FORTIFY, rampart); + // return powerCreep.usePower(PWR_FORTIFY, rampart); // } else { - // return this.powerCreep.moveTo(rampart); + // return powerCreep.moveTo(rampart); // } // } // // operateLab(lab: StructureLab) { // if (this.pos.inRangeToPos(lab.pos, POWER_INFO[PWR_OPERATE_LAB].range)) { - // return this.powerCreep.usePower(PWR_OPERATE_LAB, lab); + // return powerCreep.usePower(PWR_OPERATE_LAB, lab); // } else { - // return this.powerCreep.moveTo(lab); + // return powerCreep.moveTo(lab); // } // } - runPowers() { + runPowers(powerCreep: PowerCreep) { const priorities = this.memory.powerPriorities; console.log(`Powerid of priority list of ${priorities}`); for (let powerId in priorities) { console.log(`Powerid of ${powerId} and list of ${priorities}`); - let powerToUse = this.usePower(priorities[powerId]); + let powerToUse = this.usePower(powerCreep, priorities[powerId]); if (powerToUse && powerToUse.operatePower()) { break; } @@ -240,27 +241,28 @@ export class DirectiveBaseOperator extends Directive { run(): void { + const powerCreep = Game.powerCreeps[this.powerCreepName]; // For the power creeps that just sit on power spawn - const isStationary = this.powerCreep.name.toLowerCase().indexOf(types.basedefender.toString()); + const isStationary = powerCreep.name.toLowerCase().indexOf(types.basedefender.toString()); - console.log(`Running power creep ${JSON.stringify(this.powerCreep)} with ttl ${this.powerCreep.ticksToLive} with ${this.room!.powerSpawn}`); + console.log(`Running power creep ${JSON.stringify(powerCreep)} with ttl ${powerCreep.ticksToLive} with ${this.room!.powerSpawn}`); if (!this.room) { return; - } else if (!this.powerCreep.ticksToLive && this.room && this.room.powerSpawn) { + } else if (!powerCreep.ticksToLive && this.room && this.room.powerSpawn) { // Spawn creep - let res = this.powerCreep.spawn(this.room.powerSpawn); - log.alert(`Running ${this.powerCreep} with spawn of ${res}`); + let res = powerCreep.spawn(this.room.powerSpawn); + log.alert(`Running ${powerCreep} with spawn of ${res}`); } else if (this.room.controller && !this.room.controller.isPowerEnabled && !isStationary) { // Enable power - let res = this.enablePower(this.room.controller); - log.alert(`Running ${this.powerCreep} with enable power of ${res}`); - } else if (this.powerCreep && this.powerCreep.ticksToLive && this.powerCreep.ticksToLive < 900 && this.room.powerSpawn) { - let res = this.renew(this.room.powerSpawn); - log.alert(`Running ${this.powerCreep} with renew of ${res}`); + let res = this.enablePower(powerCreep, this.room.controller); + log.alert(`Running ${powerCreep} with enable power of ${res}`); + } else if (powerCreep && powerCreep.ticksToLive && powerCreep.ticksToLive < 900 && this.room.powerSpawn) { + let res = this.renew(powerCreep, this.room.powerSpawn); + log.alert(`Running ${powerCreep} with renew of ${res}`); } else { - let res = this.runPowers(); - log.alert(`Running ${this.powerCreep} with power of ${res}`); + let res = this.runPowers(powerCreep); + log.alert(`Running ${powerCreep} with power of ${res}`); } From 7b88a065c7de35bcfdd17d4b8cdad19b58eb3cdc Mon Sep 17 00:00:00 2001 From: Matthew Roy Date: Mon, 12 Aug 2019 17:05:10 -0700 Subject: [PATCH 09/10] Added tower boosting and withdrawal of ops --- src/directives/powerCreeps/baseOperator.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/directives/powerCreeps/baseOperator.ts b/src/directives/powerCreeps/baseOperator.ts index 545a12344..9975e0352 100644 --- a/src/directives/powerCreeps/baseOperator.ts +++ b/src/directives/powerCreeps/baseOperator.ts @@ -5,6 +5,7 @@ import {log} from "../../console/log"; import {Visualizer} from "../../visuals/Visualizer"; import {Power} from "./powers/genericPower"; import {GenerateOps} from "./powers/generateOps"; +import {DirectiveNukeResponse} from "../situational/nukeResponse"; interface DirectiveBaseOperatorMemory extends FlagMemory { @@ -265,6 +266,16 @@ export class DirectiveBaseOperator extends Directive { log.alert(`Running ${powerCreep} with power of ${res}`); } + if (this.room.hostiles.length > 2 || (powerCreep.pos && DirectiveNukeResponse.isPresent(powerCreep.pos, 'room'))) { + const towersToBoost = this.colony.towers.filter(tower => !tower.effects || tower.effects.length == 0); + if (towersToBoost.length > 0) { + powerCreep.usePower(PWR_OPERATE_TOWER, towersToBoost[0]) + } + if ((!powerCreep.carry.ops || powerCreep.carry.ops < 20) && this.room.storage && this.room.storage.store.ops && this.room.storage.store.ops > 100) { + powerCreep.withdraw(this.room.storage, RESOURCE_OPS, 100); + } + } + } From eed5f7970734cc83885a705292059125415a8d38 Mon Sep 17 00:00:00 2001 From: Matthew Roy Date: Tue, 13 Aug 2019 09:12:10 -0700 Subject: [PATCH 10/10] Adding operate extension --- src/directives/powerCreeps/baseOperator.ts | 2 ++ .../powerCreeps/powers/operateExtension.ts | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/directives/powerCreeps/powers/operateExtension.ts diff --git a/src/directives/powerCreeps/baseOperator.ts b/src/directives/powerCreeps/baseOperator.ts index 9975e0352..84e3659bd 100644 --- a/src/directives/powerCreeps/baseOperator.ts +++ b/src/directives/powerCreeps/baseOperator.ts @@ -6,6 +6,7 @@ import {Visualizer} from "../../visuals/Visualizer"; import {Power} from "./powers/genericPower"; import {GenerateOps} from "./powers/generateOps"; import {DirectiveNukeResponse} from "../situational/nukeResponse"; +import {OperateExtension} from "./powers/operateExtension"; interface DirectiveBaseOperatorMemory extends FlagMemory { @@ -94,6 +95,7 @@ export class DirectiveBaseOperator extends Directive { console.log(`The power constant is ${power}`) switch(power) { case PWR_GENERATE_OPS: return new GenerateOps(powerCreep); + case PWR_OPERATE_EXTENSION: return new OperateExtension(powerCreep); // case PWR_OPERATE_SPAWN: return this.operateSpawn(); } diff --git a/src/directives/powerCreeps/powers/operateExtension.ts b/src/directives/powerCreeps/powers/operateExtension.ts new file mode 100644 index 000000000..dac9c6021 --- /dev/null +++ b/src/directives/powerCreeps/powers/operateExtension.ts @@ -0,0 +1,30 @@ +import {profile} from "../../../profiler/decorator"; +import {Power} from "./genericPower"; +import {log} from "../../../console/log"; + +export const powerId = PWR_OPERATE_EXTENSION; + +/** + * An abstract class for encapsulating power creep power usage. + */ +@profile +export class OperateExtension extends Power { + + constructor(powerCreep: PowerCreep, target?: RoomObject) { + super(powerCreep, target); + } + + operatePower() { + if (this.powerCreep.carry.ops && this.powerCreep.carry.ops > 2 && this.powerCreep.room + && this.powerCreep.room.energyAvailable < this.powerCreep.room.energyCapacityAvailable * 0.5) { + const terminal = this.powerCreep.room!.storage; + if (!terminal) { + log.error(`Ops power creep with no storage`); + } else { + this.powerCreep.moveTo(terminal); + return this.powerCreep.usePower(powerId, terminal); + } + } + return ERR_TIRED; + } +} \ No newline at end of file