├── src ├── typings │ ├── spawn.d.ts │ ├── structure.d.ts │ ├── memory.d.ts │ ├── room-position.d.ts │ ├── process-sleep.d.ts │ └── process.d.ts ├── components │ ├── cli │ │ ├── hello.ts │ │ ├── start-colony-process.ts │ │ ├── first-room.ts │ │ ├── kill.ts │ │ ├── test.ts │ │ ├── wrapper.ts │ │ ├── new-room.ts │ │ ├── killChild.ts │ │ ├── outpost.ts │ │ ├── start-remote-mining.ts │ │ ├── ps.ts │ │ ├── migrate-init.ts │ │ ├── start-reservation-outpost.ts │ │ └── mining.ts │ ├── processes │ │ ├── memory │ │ │ ├── overmind.ts │ │ │ └── creep.ts │ │ ├── constants.ts │ │ ├── process-status.ts │ │ ├── raid │ │ │ └── basic.ts │ │ ├── init.ts │ │ ├── construction.ts │ │ ├── room │ │ │ ├── building-planner.ts │ │ │ ├── defense.ts │ │ │ ├── starter-courier.ts │ │ │ ├── road-planner.ts │ │ │ ├── crane.ts │ │ │ ├── maintainer.ts │ │ │ ├── starter.ts │ │ │ ├── maintainer-creep.ts │ │ │ ├── spawn.ts │ │ │ ├── claim.ts │ │ │ ├── starter-creep.ts │ │ │ ├── starter-claim-creep.ts │ │ │ ├── librarian.ts │ │ │ ├── link-manager.ts │ │ │ ├── colony.ts │ │ │ └── upgrader.ts │ │ ├── hello-world.ts │ │ ├── creep.ts │ │ ├── overmind.ts │ │ ├── process.ts │ │ ├── remote-room │ │ │ ├── reserve-creep.ts │ │ │ ├── reservation-outpost.ts │ │ │ ├── outpost-starter.ts │ │ │ └── outpost.ts │ │ └── mining │ │ │ ├── miner-with-link-creep.ts │ │ │ ├── courier.ts │ │ │ ├── miner-creep.ts │ │ │ └── mining.ts │ └── utils │ │ ├── spawn.ts │ │ └── colony.ts ├── shared │ └── memoryManager.ts ├── prototypes │ ├── structure.ts │ └── room-position.ts ├── config │ └── config.ts ├── main.ts └── minimist.ts ├── config.example.json ├── .gitmodules ├── .editorconfig ├── typings.json ├── .vscode └── settings.json ├── .gitattributes ├── tsconfig.json ├── tslint.json ├── .gitignore ├── LICENSE ├── package.json ├── libs ├── gulp-screeps-upload.js └── gulp-dot-flatten.js ├── gulpfile.js └── README.md /src/typings/spawn.d.ts: -------------------------------------------------------------------------------- 1 | type bodyMap = { [key: string]: number }; 2 | -------------------------------------------------------------------------------- /src/typings/structure.d.ts: -------------------------------------------------------------------------------- 1 | interface Structure { 2 | needEnergy(): boolean; 3 | } 4 | -------------------------------------------------------------------------------- /src/typings/memory.d.ts: -------------------------------------------------------------------------------- 1 | interface Memory { 2 | processMemory: any; 3 | processTable: any; 4 | } 5 | -------------------------------------------------------------------------------- /src/typings/room-position.d.ts: -------------------------------------------------------------------------------- 1 | interface RoomPosition { 2 | adjacentPositions: () => RoomPosition[]; 3 | } 4 | -------------------------------------------------------------------------------- /src/components/cli/hello.ts: -------------------------------------------------------------------------------- 1 | export = function (argv: string[]) { 2 | console.log("Hello, world:" + argv[0]); 3 | }; 4 | -------------------------------------------------------------------------------- /src/components/processes/memory/overmind.ts: -------------------------------------------------------------------------------- 1 | export interface OvermindMemory { 2 | spawningRoomName: string 3 | } 4 | -------------------------------------------------------------------------------- /src/typings/process-sleep.d.ts: -------------------------------------------------------------------------------- 1 | export interface ProcessSleep { 2 | start: number; 3 | duration: number; 4 | } 5 | -------------------------------------------------------------------------------- /config.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "email": "YOUR_USERNAME", 3 | "password": "YOUR_PASSWORD", 4 | "branch": "default" 5 | } 6 | -------------------------------------------------------------------------------- /src/components/processes/memory/creep.ts: -------------------------------------------------------------------------------- 1 | export interface CreepMemory { 2 | creepName: string; 3 | id: string; 4 | } 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/components/kernel"] 2 | path = src/components/kernel 3 | url = git@github.com:NhanHo/screeps-kernel.git 4 | -------------------------------------------------------------------------------- /src/components/processes/constants.ts: -------------------------------------------------------------------------------- 1 | export enum ProcessPriority { 2 | Ticly = 1, 3 | TiclyLast, 4 | LowPriority 5 | } 6 | -------------------------------------------------------------------------------- /src/components/processes/process-status.ts: -------------------------------------------------------------------------------- 1 | export let ProcessStatus = { 2 | DEAD: -1, 3 | ALIVE: 0, 4 | SLEEP: 1, 5 | }; 6 | -------------------------------------------------------------------------------- /src/shared/memoryManager.ts: -------------------------------------------------------------------------------- 1 | export let memory: Memory; 2 | 3 | export function loadMemory(): void { 4 | this.memory = Memory; 5 | } 6 | -------------------------------------------------------------------------------- /src/components/cli/start-colony-process.ts: -------------------------------------------------------------------------------- 1 | import ColonyProcess = require("../processes/room/colony"); 2 | export = function (argv: string[]) { 3 | ColonyProcess.start(argv[0]); 4 | } 5 | -------------------------------------------------------------------------------- /src/components/cli/first-room.ts: -------------------------------------------------------------------------------- 1 | import first_room_process = require("../processes/room/starter"); 2 | 3 | export = function (argv: string[]) { 4 | first_room_process.start(argv[0]) 5 | } 6 | -------------------------------------------------------------------------------- /src/components/processes/raid/basic.ts: -------------------------------------------------------------------------------- 1 | /*import OvermindProcess = require("../overmind"); 2 | 3 | class BasicRaidProcess extends OvermindProcess { 4 | 5 | } 6 | 7 | export = BasicRaidProcess;*/ 8 | -------------------------------------------------------------------------------- /src/components/cli/kill.ts: -------------------------------------------------------------------------------- 1 | import { killProcess, storeProcessTable } from "../kernel/kernel/kernel"; 2 | export = function (argv: string[]) { 3 | let pid = parseInt(argv[0], 10); 4 | killProcess(pid); 5 | storeProcessTable(); 6 | }; 7 | -------------------------------------------------------------------------------- /src/components/cli/test.ts: -------------------------------------------------------------------------------- 1 | import { processTable } from "../kernel/kernel/kernel"; 2 | export = function (___: any) { 3 | for (let pid in processTable) { 4 | const process = processTable[pid]; 5 | console.log(pid + ":" + process.constructor.name); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/components/cli/wrapper.ts: -------------------------------------------------------------------------------- 1 | declare var require: any; 2 | export = function (s: string) { 3 | let arr = s.trim().split(" "); 4 | let procName = arr[0]; 5 | let argv = arr.splice(1); 6 | let proc = require("components.cli." + procName); 7 | if (proc) 8 | proc(argv); 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.py] 13 | indent_style = space 14 | indent_size = 4 15 | 16 | [*.rb] 17 | indent_style = space 18 | indent_size = 4 19 | -------------------------------------------------------------------------------- /src/components/processes/init.ts: -------------------------------------------------------------------------------- 1 | import Process = require("../kernel/kernel/process"); 2 | 3 | class InitProcess extends Process { 4 | public classPath(): string { 5 | return "components.processes.init"; 6 | } 7 | 8 | public run(): number { 9 | return 0; 10 | } 11 | } 12 | 13 | export = InitProcess; 14 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "resir014-screeps", 3 | "dependencies": { 4 | "minimist": "registry:npm/minimist#1.0.0+20160723033700" 5 | }, 6 | "globalDependencies": { 7 | "lodash": "registry:dt/lodash#3.10.0+20160619033623", 8 | "screeps": "github:screepers/Screeps-Typescript-Declarations/dist/screeps.d.ts" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/components/processes/construction.ts: -------------------------------------------------------------------------------- 1 | import Process = require("./process"); 2 | 3 | export = class ConstructionProcess extends Process { 4 | public classPath = "components.processes.construction"; 5 | public run(): number { 6 | return 0; 7 | } 8 | 9 | public requestBuilding() { 10 | return null; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "editor.insertSpaces": true, 4 | "editor.renderWhitespace": true, 5 | "files.encoding": "utf8", 6 | "files.trimTrailingWhitespace": true, 7 | "files.insertFinalNewline": true, 8 | "search.exclude": { 9 | "dist/**": true, 10 | "node_modules/**": true, 11 | "typings/**": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/components/cli/new-room.ts: -------------------------------------------------------------------------------- 1 | import ClaimProcess = require("../processes/room/claim"); 2 | import { addProcess, storeProcessTable } from "../kernel/kernel/kernel"; 3 | export = function (argv: string[]) { 4 | let p = new ClaimProcess(0, 0); 5 | addProcess(p); 6 | p.memory.spawningRoomName = argv[0]; 7 | p.memory.targetRoomName = argv[1]; 8 | storeProcessTable(); 9 | } 10 | -------------------------------------------------------------------------------- /src/components/cli/killChild.ts: -------------------------------------------------------------------------------- 1 | import { killProcess, storeProcessTable, processTable } from "../kernel/kernel/kernel"; 2 | export = function (argv: string[]) { 3 | let parentPid = parseInt(argv[0], 10); 4 | for (let pid in processTable) { 5 | let p = processTable[pid]; 6 | if (p.parentPID === parentPid) { 7 | killProcess(parseInt(pid)); 8 | } 9 | } 10 | storeProcessTable(); 11 | 12 | }; 13 | -------------------------------------------------------------------------------- /src/typings/process.d.ts: -------------------------------------------------------------------------------- 1 | import { ProcessPriority } from "../components/processes/constants"; 2 | import { ProcessSleep } from "./process-sleep"; 3 | export interface Process { 4 | pid: number; 5 | parentPID: number; 6 | status: number; 7 | classPath: string; 8 | priority: ProcessPriority; 9 | sleepInfo?: ProcessSleep; 10 | memory: any; 11 | setMemory(memory: any): void; 12 | run(): number; 13 | stop(signal: number): number; 14 | } 15 | -------------------------------------------------------------------------------- /src/components/cli/outpost.ts: -------------------------------------------------------------------------------- 1 | import * as Kernel from "../kernel/kernel/kernel"; 2 | import OutpostStarter = require("../processes/remote-room/outpost-starter"); 3 | export = function (argv: string[]) { 4 | const colonyRoomName = argv[0]; 5 | const outpostRoomName = argv[1]; 6 | let p = new OutpostStarter(0, 0); 7 | Kernel.addProcess(p); 8 | p.memory.spawningRoomName = colonyRoomName; 9 | p.memory.targetRoomName = outpostRoomName; 10 | Kernel.storeProcessTable(); 11 | } 12 | -------------------------------------------------------------------------------- /src/prototypes/structure.ts: -------------------------------------------------------------------------------- 1 | let loadStructurePrototype = function () { 2 | Structure.prototype.needEnergy = function () { 3 | if (this.structureType !== STRUCTURE_EXTENSION && 4 | this.structureType !== STRUCTURE_TOWER) { 5 | return false; 6 | } else if (this.structureType === STRUCTURE_TOWER) { 7 | return this.energy < 100; 8 | } 9 | return this.energy < this.energyCapacity; 10 | }; 11 | }; 12 | 13 | export = loadStructurePrototype; 14 | -------------------------------------------------------------------------------- /src/components/cli/start-remote-mining.ts: -------------------------------------------------------------------------------- 1 | /*import RemoteMiningStarter = require("../processes/mining/remote-mining-starter"); 2 | import { addProcess, storeProcessTable } from "../kernel/kernel"; 3 | export = function (argv: any) { 4 | let spawningRoomName = argv[0]; 5 | let targetRoomName = argv[1]; 6 | let p = new RemoteMiningStarter(0, 0); 7 | addProcess(p); 8 | p.memory.spawningRoomName = spawningRoomName; 9 | p.memory.targetRoomName = targetRoomName; 10 | storeProcessTable(); 11 | 12 | }*/ 13 | 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /src/config/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Enable this if you want a lot of text to be logged to console. 3 | * @type {boolean} 4 | */ 5 | export const VERBOSE: boolean = true; 6 | 7 | /** 8 | * @type {number} 9 | */ 10 | export const MAX_HARVESTERS_PER_SOURCE: number = 4; 11 | 12 | /** 13 | * Default amount of minimal ticksToLive Screep can have, before it goes to renew. 14 | * This is only default value, that don't have to be used. 15 | * So it doesn't cover all Screeps. 16 | * @type {number} 17 | */ 18 | export const DEFAULT_MIN_LIFE_BEFORE_NEEDS_REFILL: number = 700; 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "removeComments": true, 6 | "noResolve": false, 7 | "noImplicitAny": false, 8 | "experimentalDecorators": true, 9 | "strictNullChecks": true, 10 | "noUnusedParameters": true, 11 | "noUnusedLocals": true 12 | }, 13 | "compileOnSave": false, 14 | "include": [ 15 | "typings/**/*.d.ts", 16 | "src/**/*.ts", 17 | "src/**/*.d.ts" 18 | ], 19 | "exclude": [ 20 | "dist", 21 | "node_modules", 22 | "libs" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends" : [ 3 | "tslint:recommended" 4 | ], 5 | "rules": { 6 | "forin": false, 7 | "interface-name": [false], 8 | "no-console": [false], 9 | "variable-name": [ 10 | true, 11 | "ban-keywords", 12 | "check-format", 13 | "allow-pascal-case", 14 | "allow-leading-underscore" 15 | ], 16 | "curly": false, 17 | "semicolon": false, 18 | "typedef-whitespace": "nospace", 19 | "whitespace": [ 20 | false, 21 | "check-typecast" 22 | ], 23 | "object-literal-sort-keys": false, 24 | "max-line-length": [true, 100] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/components/utils/spawn.ts: -------------------------------------------------------------------------------- 1 | import { processTable } from "../kernel/kernel/kernel"; 2 | 3 | import SpawnProcess = require("../processes/room/spawn"); 4 | export let getSpawnProcess = function (roomName: string): SpawnProcess | null { 5 | for (let pid in processTable) { 6 | let process = processTable[pid]; 7 | if (process instanceof SpawnProcess) { 8 | let spawnProcess = process; 9 | if (spawnProcess.getRoomName() === roomName) { 10 | return spawnProcess; 11 | } 12 | } 13 | } 14 | return null; 15 | }; 16 | -------------------------------------------------------------------------------- /src/components/utils/colony.ts: -------------------------------------------------------------------------------- 1 | import { processTable } from "../kernel/kernel/kernel"; 2 | 3 | import ColonyProcess = require("../processes/room/colony"); 4 | export let getColonyProcess = function (roomName: string): ColonyProcess | null { 5 | for (let pid in processTable) { 6 | let process = processTable[pid]; 7 | if (process instanceof ColonyProcess) { 8 | let colonyProcess = process; 9 | if (colonyProcess.getRoomName() === roomName) { 10 | return colonyProcess; 11 | } 12 | } 13 | } 14 | return null; 15 | }; 16 | 17 | -------------------------------------------------------------------------------- /src/prototypes/room-position.ts: -------------------------------------------------------------------------------- 1 | let loadRoomPrototype = function () { 2 | RoomPosition.prototype.adjacentPositions = function () { 3 | let dx = [0, 1, 1, 1, 0, -1, -1, -1]; 4 | let dy = [-1, -1, 0, 1, 1, 1, 0, -1]; 5 | let result: RoomPosition[] = []; 6 | for (let i = 0; i < 8; i = i + 1) { 7 | let x = this.x + dx[i]; 8 | let y = this.y + dy[i]; 9 | if (x >= 0 && x <= 49 && y >= 0 && y <= 49) { 10 | result.push(new RoomPosition(x, y, this.roomName)); 11 | } 12 | } 13 | return result; 14 | }; 15 | }; 16 | 17 | export = loadRoomPrototype; 18 | -------------------------------------------------------------------------------- /src/components/processes/room/building-planner.ts: -------------------------------------------------------------------------------- 1 | import { addProcess } from "../../kernel/kernel/kernel"; 2 | import Process = require("../../kernel/kernel/process"); 3 | class BuildingPlannerProcess extends Process { 4 | public classPath() { 5 | return "components.processes.room.building-planner"; 6 | } 7 | public static start(roomName: string, colonyPid: number): BuildingPlannerProcess { 8 | const p = new BuildingPlannerProcess(0, colonyPid); 9 | addProcess(p); 10 | p.memory.roomName = roomName; 11 | return p; 12 | } 13 | 14 | public run(): number { 15 | return 0; 16 | } 17 | } 18 | 19 | export = BuildingPlannerProcess; 20 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import * as Kernel from "./components/kernel/kernel/kernel"; 2 | import room_position = require("./prototypes/room-position"); 3 | import structure_prototype = require("./prototypes/structure"); 4 | declare var global: any; 5 | import cli = require("./components/cli/wrapper"); 6 | room_position(); 7 | structure_prototype(); 8 | 9 | export function loop() { 10 | // This is executed every tick 11 | global.__ = cli; 12 | Kernel.loadProcessTable(); 13 | Kernel.garbageCollection(); 14 | Kernel.run(); 15 | Kernel.storeProcessTable(); 16 | 17 | // We reload the process table, to make sure it's updated for our command line 18 | Kernel.loadProcessTable(); 19 | } 20 | -------------------------------------------------------------------------------- /src/components/cli/ps.ts: -------------------------------------------------------------------------------- 1 | import { processTable } from "../kernel/kernel/kernel"; 2 | //import Process = require("../processes/process"); 3 | export = function (argv: string[]) { 4 | let parentID; 5 | console.log(JSON.stringify(argv)); 6 | if (!argv.length) 7 | parentID = 0; 8 | else 9 | parentID = parseInt(argv[0]); 10 | for (let pid in processTable) { 11 | let process: any = processTable[pid]; 12 | if (process.parentPID === parentID) { 13 | if (process.psInfo) 14 | console.log(process.pid + ": " + process.psInfo()); 15 | else 16 | console.log(process.pid + ": " + process.constructor.name); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/components/processes/hello-world.ts: -------------------------------------------------------------------------------- 1 | import { addProcess, storeProcessTable } from "../kernel/kernel/kernel"; 2 | import Process = require("../kernel/kernel/process"); 3 | class HelloWorldProcess extends Process { 4 | public static startNewCounter() { 5 | let p = new HelloWorldProcess(0, 0); 6 | addProcess(p); 7 | storeProcessTable(); 8 | } 9 | 10 | public status: number; 11 | public className: string; 12 | public classPath() { 13 | return "components.process.hello-world"; 14 | } 15 | public pid: number; 16 | public parentPID: number; 17 | 18 | public run(): number { 19 | let memory = this.memory; 20 | memory.counter = memory.counter || 0; 21 | console.log(memory.counter); 22 | memory.counter += 1; 23 | return 0; 24 | } 25 | 26 | } 27 | 28 | export = HelloWorldProcess; 29 | -------------------------------------------------------------------------------- /src/components/processes/creep.ts: -------------------------------------------------------------------------------- 1 | import Process = require("../kernel/kernel/process"); 2 | import { CreepMemory } from "./memory/creep"; 3 | import { getProcessById } from "../kernel/kernel/kernel"; 4 | import OvermindProcess = require("./overmind"); 5 | abstract class CreepProcess extends Process { 6 | public memory: CreepMemory; 7 | public run(): number { 8 | let creep = Game.creeps[this.memory.creepName]; 9 | 10 | if (!creep) { 11 | if (this.parentPID !== 0) { 12 | let p = getProcessById(this.parentPID); 13 | p.creepDies(this.memory.id, this.pid); 14 | } 15 | return this.stop(0); 16 | } else { 17 | this.runCreep(creep); 18 | return 0; 19 | } 20 | } 21 | 22 | protected abstract runCreep(creep: Creep): number; 23 | } 24 | 25 | export = CreepProcess; 26 | -------------------------------------------------------------------------------- /src/components/processes/overmind.ts: -------------------------------------------------------------------------------- 1 | import Process = require("../kernel/kernel/process"); 2 | import { getSpawnProcess } from "../utils/spawn"; 3 | import { addProcess } from "../kernel/kernel/kernel"; 4 | import { OvermindMemory } from "./memory/overmind"; 5 | abstract class OvermindProcess extends Process { 6 | protected static addProcess = addProcess; 7 | 8 | public memory: OvermindMemory; 9 | public abstract receiveCreep(id: string, creep: Creep); 10 | public abstract creepDies(id: string, pid: number); 11 | 12 | protected spawnCreep(creepID: string, bodyParts: bodyMap, priority?: number) { 13 | // TODO: Check and throw error when there is no roomName 14 | let spawnProcess = getSpawnProcess(this.memory.spawningRoomName); 15 | if (spawnProcess) { 16 | spawnProcess.spawn(creepID, bodyParts, this.pid, priority); 17 | } 18 | } 19 | } 20 | 21 | export = OvermindProcess; 22 | -------------------------------------------------------------------------------- /src/components/processes/process.ts: -------------------------------------------------------------------------------- 1 | import * as Kernel from "../kernel/kernel/kernel"; 2 | import { ProcessPriority } from "./constants"; 3 | import { ProcessStatus } from "./process-status"; 4 | import { ProcessSleep } from "../../typings/process-sleep"; 5 | abstract class Process { 6 | public status: number; 7 | public classPath: string; 8 | public sleepInfo?: ProcessSleep; 9 | public priority: ProcessPriority; 10 | public memory: any; 11 | protected kernel = Kernel; 12 | constructor(public pid: number, 13 | public parentPID: number, 14 | priority = ProcessPriority.LowPriority) { 15 | 16 | this.status = ProcessStatus.ALIVE; 17 | this.priority = priority; 18 | }; 19 | 20 | public abstract run(): number; 21 | public setMemory(memory: any): void { 22 | this.memory = memory; 23 | }; 24 | 25 | public stop(signal: number) { 26 | Kernel.killProcess(this.pid); 27 | return signal; 28 | } 29 | } 30 | 31 | export = Process; 32 | -------------------------------------------------------------------------------- /src/components/processes/remote-room/reserve-creep.ts: -------------------------------------------------------------------------------- 1 | import CreepProcess = require("../creep"); 2 | import { CreepMemory } from "../memory/creep"; 3 | interface ReserveCreepMemory extends CreepMemory { 4 | roomName: string; 5 | } 6 | class ReserveCreep extends CreepProcess { 7 | public classPath() { 8 | return "components.processes.remote-room.reserve-creep"; 9 | } 10 | public memory: ReserveCreepMemory; 11 | public runCreep(creep: Creep): number { 12 | const roomName = this.memory.roomName; 13 | const room = Game.rooms[roomName]; 14 | if (room) { 15 | if (!creep.pos.isNearTo(room.controller!.pos)) { 16 | creep.moveTo(room.controller!.pos); 17 | } else { 18 | creep.reserveController(room.controller!); 19 | } 20 | } else { 21 | const roomPos = new RoomPosition(25, 25, roomName); 22 | creep.moveTo(roomPos); 23 | } 24 | return 0; 25 | }; 26 | } 27 | 28 | export = ReserveCreep; 29 | -------------------------------------------------------------------------------- /src/components/cli/migrate-init.ts: -------------------------------------------------------------------------------- 1 | import { addProcess, storeProcessTable, processTable } from "../kernel/kernel/kernel"; 2 | import Process = require("../kernel/kernel/process"); 3 | import InitProcess = require("../processes/init"); 4 | export = function (___: any) { 5 | let p = new InitProcess(0, 0); 6 | let pidZero = processTable[0]; 7 | if (!pidZero) { 8 | addProcess(p); 9 | p.pid = 0; 10 | storeProcessTable(); 11 | } else { 12 | addProcess(pidZero); 13 | let newPid = pidZero.pid; 14 | let processList: Process[] = _.values(processTable) as Process[]; 15 | for (let process of processList) { 16 | if (process.parentPID === 0) { 17 | process.parentPID = newPid; 18 | } 19 | } 20 | pidZero.parentPID = 0; 21 | Memory.processMemory[newPid] = _.cloneDeep(Memory.processMemory[0]); 22 | delete (processTable[0]); 23 | addProcess(p); 24 | p.pid = 0; 25 | storeProcessTable(); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore basic folders 2 | /dist 3 | /node_modules 4 | /typings 5 | 6 | # Screeps config file 7 | /config.json 8 | 9 | # Numerous always-ignore extensions 10 | *.diff 11 | *.err 12 | *.orig 13 | *.log 14 | *.rej 15 | *.swo 16 | *.swp 17 | *.zip 18 | *.vi 19 | *~ 20 | \#*.*# 21 | \#*# 22 | .#* 23 | 24 | # ========================= 25 | # Operating System Files 26 | # ========================= 27 | 28 | # OSX 29 | # ========================= 30 | 31 | .DS_Store 32 | .AppleDouble 33 | .LSOverride 34 | 35 | # Thumbnails 36 | ._* 37 | 38 | # Files that might appear on external disk 39 | .Spotlight-V100 40 | .Trashes 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | 49 | # Windows 50 | # ========================= 51 | 52 | # Windows image file caches 53 | Thumbs.db 54 | ehthumbs.db 55 | 56 | # Folder config file 57 | Desktop.ini 58 | 59 | # Recycle Bin used on file shares 60 | $RECYCLE.BIN/ 61 | 62 | # Windows Installer files 63 | *.cab 64 | *.msi 65 | *.msm 66 | *.msp 67 | 68 | # Windows shortcuts 69 | *.lnk 70 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Nhan Ho 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "screeps-starter", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "./dist/main.js", 6 | "repository": "resir014/screeps-typescript-starter", 7 | "scripts": { 8 | "test": "node_modules/.bin/jest" 9 | }, 10 | "author": "", 11 | "license": "MIT", 12 | "devDependencies": { 13 | "babel-jest": "*", 14 | "babel-preset-es2015": "^6.14.0", 15 | "deep-equal": "^1.0.1", 16 | "gulp": "^3.9.1", 17 | "gulp-babel": "^6.1.2", 18 | "gulp-clean": "^0.3.2", 19 | "gulp-collect": "^0.1.0", 20 | "gulp-jest": "^0.5.2", 21 | "gulp-rename": "^1.2.2", 22 | "gulp-tslint": "^8.1.2", 23 | "gulp-typescript": "^3.2.3", 24 | "gulp-util": "^3.0.7", 25 | "jest-cli": "^15.1.1", 26 | "lodash": "^3.10.0", 27 | "q": "^1.4.1", 28 | "recast": "^0.11.10", 29 | "through2": "^2.0.1", 30 | "tslint": "^5.8.0", 31 | "typescript": "^2.5.3", 32 | "typings": "^2.1.1", 33 | "vm": "^0.1.0" 34 | }, 35 | "dependencies": { 36 | "glob-stream": "^6.1.0", 37 | "minimist": "^1.2.0" 38 | }, 39 | "jest": { 40 | "rootDir": "__tests__" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/components/processes/room/defense.ts: -------------------------------------------------------------------------------- 1 | import { addProcess, getProcessById } from "../../kernel/kernel/kernel"; 2 | import Process = require("../../kernel/kernel/process"); 3 | class DefenseProcess extends Process { 4 | public static start(roomName: string, parentPID: number) { 5 | let p = new DefenseProcess(0, parentPID); 6 | p = addProcess(p); 7 | p.memory.roomName = roomName; 8 | return p.pid; 9 | } 10 | 11 | public classPath() { 12 | return "components.processes.room.defense"; 13 | } 14 | public run(): number { 15 | const colonyProcess = getProcessById(this.parentPID); 16 | if (!colonyProcess) 17 | return this.stop(0); 18 | 19 | const roomName = this.memory.roomName; 20 | const room = Game.rooms[roomName]; 21 | const hostileCreepList = room.find(FIND_HOSTILE_CREEPS) as Creep[]; 22 | if (hostileCreepList.length) { 23 | const towerList = room.find(FIND_MY_STRUCTURES, 24 | { filter: { structureType: STRUCTURE_TOWER } }) as Tower[]; 25 | for (const tower of towerList) { 26 | tower.attack(hostileCreepList[0]); 27 | } 28 | 29 | } 30 | return 0; 31 | } 32 | 33 | } 34 | 35 | export = DefenseProcess; 36 | -------------------------------------------------------------------------------- /src/components/cli/start-reservation-outpost.ts: -------------------------------------------------------------------------------- 1 | import ReservationOutpostProcess = require("../processes/remote-room/reservation-outpost"); 2 | import { processTable, addProcess, storeProcessTable } from "../kernel/kernel/kernel"; 3 | import ColonyProcess = require("../processes/room/colony"); 4 | let getColonyProcess = function (roomName: string): ColonyProcess | null { 5 | for (let pid in processTable) { 6 | let process = processTable[pid]; 7 | if (process instanceof ColonyProcess) { 8 | let colonyProcess = process; 9 | if (colonyProcess.getRoomName() === roomName) { 10 | return colonyProcess; 11 | } 12 | } 13 | } 14 | return null; 15 | }; 16 | 17 | export = function (argv: any[]) { 18 | let colonyRoomName = argv[0]; 19 | let outpostRoomName = argv[1]; 20 | let colonyProcess = getColonyProcess(colonyRoomName); 21 | if (colonyProcess) { 22 | let p = new ReservationOutpostProcess(0, colonyProcess.pid); 23 | addProcess(p); 24 | p.memory.roomName = outpostRoomName; 25 | p.memory.spawningRoomName = colonyRoomName; 26 | storeProcessTable(); 27 | } else { 28 | console.log("Failed to start reservation process: Can't find the colony process " + 29 | "of room " + colonyRoomName); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/components/processes/room/starter-courier.ts: -------------------------------------------------------------------------------- 1 | import CreepProcess = require("../creep"); 2 | import { CreepMemory } from "../memory/creep"; 3 | 4 | enum CreepState { 5 | GETTING_ENERGY = 1, 6 | DELIVERING, 7 | } 8 | 9 | interface StarterCourierMemory extends CreepMemory { 10 | targetCreep: string | undefined; 11 | state: CreepState; 12 | } 13 | 14 | class StarterCourier extends CreepProcess { 15 | public memory: StarterCourierMemory; 16 | public classPath() { 17 | return "components.processes.room.starter-courier"; 18 | } 19 | 20 | public runCreep(creep: Creep): number { 21 | this.memory.state = this.memory.state || CreepState.GETTING_ENERGY; 22 | if (this.memory.state === CreepState.GETTING_ENERGY) { 23 | this.getEnergy(creep); 24 | } else { 25 | this.deliverEnergy(creep); 26 | } 27 | return 0; 28 | } 29 | 30 | private findEnergySource(creep: Creep) { 31 | creep; 32 | } 33 | 34 | private getEnergy(creep: Creep) { 35 | const targetCreep: Creep = Game.getObjectById(this.memory.targetCreep!) as Creep; 36 | if (!targetCreep) { 37 | this.findEnergySource(creep); 38 | } 39 | } 40 | 41 | private deliverEnergy(creep: Creep) { 42 | creep; 43 | } 44 | } 45 | 46 | export = StarterCourier; 47 | -------------------------------------------------------------------------------- /src/components/processes/room/road-planner.ts: -------------------------------------------------------------------------------- 1 | import { getProcessById, sleepProcess } from "../../kernel/kernel/kernel" 2 | import Process = require("../../kernel/kernel/process"); 3 | import ColonyProcess = require("./colony"); 4 | 5 | class RoadPlannerProcess extends Process { 6 | public classPath() { 7 | return "components.processes.room.road-planner"; 8 | } 9 | public run(): number { 10 | const colonyProcess: ColonyProcess = getProcessById(this.parentPID) as ColonyProcess; 11 | if (!colonyProcess || !(colonyProcess instanceof ColonyProcess)) { 12 | this.stop(0); 13 | } 14 | const room = Game.rooms[colonyProcess.memory.roomName]; 15 | const controller = room.controller!; 16 | const sources = room.find(FIND_SOURCES) as Source[]; 17 | for (const source of sources) { 18 | const path = PathFinder.search(source.pos, controller.pos); 19 | for (const pos of path.path) { 20 | if (Game.map.getTerrainAt(pos) === "swamp") { 21 | const constructionSites = pos.lookFor(LOOK_CONSTRUCTION_SITES) as ConstructionSite[]; 22 | if (constructionSites.length === 0) { 23 | pos.createConstructionSite(STRUCTURE_ROAD); 24 | } 25 | } 26 | } 27 | } 28 | sleepProcess(this, 1500); 29 | return 0; 30 | }; 31 | } 32 | 33 | export = RoadPlannerProcess; 34 | -------------------------------------------------------------------------------- /src/components/cli/mining.ts: -------------------------------------------------------------------------------- 1 | import MiningProcess = require("../processes/mining/mining"); 2 | import { addProcess, storeProcessTable } from "../kernel/kernel/kernel"; 3 | import Process = require("../kernel/kernel/process"); 4 | import { getColonyProcess } from "../utils/colony"; 5 | let addProcessAndSave = function (p: Process) { 6 | addProcess(p); 7 | storeProcessTable(); 8 | } 9 | 10 | /*let startRoomMining = function (roomName: string) { 11 | let room = Game.rooms[roomName]; 12 | let sources = room.find(FIND_SOURCES) as Source[]; 13 | 14 | for (let source of sources) { 15 | let mining = new MiningProcess(0, 0); 16 | addProcessAndSave(mining); 17 | mining.setup(roomName, source.id); 18 | } 19 | 20 | } 21 | ;*/ 22 | 23 | export = function (argv: string[]) { 24 | let sourceId = argv[0]; 25 | let roomName = argv[1]; 26 | let flag = Game.flags[sourceId]; 27 | let source = Game.getObjectById(sourceId); 28 | if (!source) { 29 | console.log("Can't find source"); 30 | } 31 | if (!flag) { 32 | source.pos.createFlag(sourceId, COLOR_YELLOW); 33 | } 34 | 35 | let colony = getColonyProcess(roomName); 36 | if (!colony) { 37 | console.log("There is no colony process for room:" + roomName); 38 | return; 39 | } 40 | 41 | let p = new MiningProcess(0, colony.pid); 42 | addProcessAndSave(p); 43 | 44 | p.memory.sourceId = sourceId; 45 | p.memory.spawningRoomName = roomName; 46 | p.memory.flagName = sourceId; 47 | } 48 | -------------------------------------------------------------------------------- /src/components/processes/remote-room/reservation-outpost.ts: -------------------------------------------------------------------------------- 1 | import OvermindProcess = require("../overmind"); 2 | import { OvermindMemory } from "../memory/overmind"; 3 | interface ReservationOutpostMemory extends OvermindMemory { 4 | colonyPid: number; 5 | roomName: string; 6 | reservationCreep: string; 7 | } 8 | 9 | class ReservationOutpostProcess extends OvermindProcess { 10 | public classPath() { 11 | return "components.processes.remote-room.reservation-outpost"; 12 | } 13 | 14 | public memory: ReservationOutpostMemory; 15 | public receiveCreep(__: string, creep: Creep) { 16 | this.memory.reservationCreep = creep.name; 17 | } 18 | 19 | public creepDies(__: string, ___: number) { }; 20 | public run(): number { 21 | let creep = Game.creeps[this.memory.reservationCreep]; 22 | if (!creep) { 23 | this.spawnCreep("reserver", { MOVE: 2, CLAIM: 2 }); 24 | } else { 25 | let room = Game.rooms[this.memory.roomName]; 26 | if (!room) { 27 | creep.moveTo(new RoomPosition(25, 25, this.memory.roomName)); 28 | return 0; 29 | } 30 | if (!room.controller) { 31 | console.log(`Pid ${this.pid} is trying to reserve a room without controller`); 32 | return 0; 33 | } 34 | if (creep.pos.isNearTo(room.controller)) 35 | creep.reserveController(room.controller); 36 | else 37 | creep.moveTo(room.controller); 38 | } 39 | return 0; 40 | } 41 | 42 | 43 | } 44 | export = ReservationOutpostProcess; 45 | -------------------------------------------------------------------------------- /src/components/processes/remote-room/outpost-starter.ts: -------------------------------------------------------------------------------- 1 | import OvermindProcess = require("../overmind"); 2 | import { OvermindMemory } from "../memory/overmind"; 3 | import OutpostProcess = require("./outpost"); 4 | import { addProcess } from "../../kernel/kernel/kernel"; 5 | 6 | interface OutpostStarterMemory extends OvermindMemory { 7 | targetRoomName: string; 8 | scout: string; 9 | } 10 | class OutpostStarterProcess extends OvermindProcess { 11 | public classPath() { 12 | return "components.processes.remote-room.outpost-starter"; 13 | } 14 | public memory: OutpostStarterMemory; 15 | 16 | public run(): number { 17 | let memory = this.memory; 18 | let room = Game.rooms[memory.targetRoomName]; 19 | if (!room) { 20 | return this.scout(); 21 | } else { 22 | const outpostProcess = new OutpostProcess(0, 0); 23 | addProcess(outpostProcess); 24 | outpostProcess.memory.roomName = memory.targetRoomName; 25 | outpostProcess.memory.spawningRoomName = memory.spawningRoomName; 26 | 27 | outpostProcess.startMining(); 28 | 29 | console.log("Output process started, terminate OutpostStarter process"); 30 | return this.stop(0); 31 | } 32 | } 33 | 34 | public creepDies() { return; }; 35 | public receiveCreep(creepID: string, creep: Creep) { 36 | if (creepID === "scout") { 37 | this.memory.scout = creep.name; 38 | } 39 | } 40 | 41 | private scout(): number { 42 | let creep = Game.creeps[this.memory.scout]; 43 | if (!creep) { 44 | this.spawnCreep("scout", { MOVE: 1 }); 45 | } else { 46 | creep.moveTo(new RoomPosition(25, 25, this.memory.targetRoomName)); 47 | } 48 | 49 | return 0; 50 | } 51 | } 52 | 53 | export = OutpostStarterProcess; 54 | -------------------------------------------------------------------------------- /libs/gulp-screeps-upload.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const _ = require('lodash'); 4 | const gutil = require('gulp-util'); 5 | const deepEqual = require('deep-equal'); 6 | const gulpCollect = require('gulp-collect'); 7 | const https = require('https'); 8 | const path = require('path'); 9 | const Q = require('q'); 10 | 11 | module.exports = (email, password, branch, logAmount) => { 12 | return gulpCollect.list((fileVinyls, cb) => { 13 | let cbd = Q.defer(); 14 | _gulpUploadVinylsAsModules(fileVinyls, cbd.makeNodeResolver(), email, password, branch, logAmount); 15 | return cbd.promise; 16 | }); 17 | }; 18 | 19 | var __lastUploaded = null; 20 | 21 | function _gulpUploadVinylsAsModules(fileVinyls, cb, email, password, branch, logAmount) { 22 | let modules = {}; 23 | for (let fileVinyl of fileVinyls) { 24 | let moduleName = path.basename(fileVinyl.path); 25 | modules[moduleName] = fileVinyl.contents.toString('utf-8'); 26 | } 27 | 28 | if (logAmount && logAmount > 0) { 29 | gutil.log('Modules: '); 30 | for (let key in modules) { 31 | gutil.log(`- ${gutil.colors.cyan(key)}`); 32 | } 33 | } 34 | 35 | let data = { branch: branch, modules: modules }; 36 | if (deepEqual(__lastUploaded, data)) { 37 | // gutil.log('Skipping upload due to equal outputs.'); 38 | return cb(null, {}); 39 | } 40 | 41 | __lastUploaded = data; 42 | 43 | gutil.log(`Uploading to branch ${gutil.colors.cyan(branch)}...`); 44 | 45 | let req = https.request({ 46 | hostname: 'screeps.com', 47 | port: 443, 48 | path: '/api/user/code', 49 | method: 'POST', 50 | auth: `${email}:${password}`, 51 | headers: { 52 | 'Content-Type': 'application/json; charset=utf-8', 53 | }, 54 | }, res => { 55 | gutil.log(`Build ${gutil.colors.cyan('completed')} with HTTP response ${gutil.colors.magenta(res.statusCode)}`); 56 | cb(null, {}); 57 | }); 58 | 59 | req.end(JSON.stringify(data)); 60 | } 61 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const clean = require('gulp-clean'); 4 | const gulp = require('gulp'); 5 | const gulpDotFlatten = require('./libs/gulp-dot-flatten.js'); 6 | const gulpRename = require('gulp-rename'); 7 | const gulpScreepsUpload = require('./libs/gulp-screeps-upload.js'); 8 | const path = require('path'); 9 | const PluginError = require('gulp-util').PluginError; 10 | const ts = require('gulp-typescript'); 11 | const tslint = require('gulp-tslint'); 12 | const tsconfig = ts.createProject('tsconfig.json', { typescript: require('typescript') }); 13 | const gs = require('glob-stream'); 14 | const config = require('./config.json'); 15 | 16 | gulp.task('lint', () => { 17 | return (gulp.src(['./src/**/*.ts', '!./**/node_modules/**', '!./**/typings/**'])) 18 | .pipe(tslint({ formatter: 'prose' })) 19 | .pipe(tslint.report({ 20 | summarizeFailureOutput: true, 21 | emitError: false, 22 | })); 23 | }); 24 | 25 | gulp.task('clean', () => { 26 | return gulp.src('dist', { read: false }) 27 | .pipe(clean()); 28 | }); 29 | 30 | let compileFailed = false; 31 | 32 | gulp.task('compile', [], () => { 33 | compileFailed = false; 34 | return tsconfig.src() 35 | .pipe(ts(tsconfig)) 36 | .on('error', (err) => { compileFailed = true; }) 37 | .js.pipe(gulp.dest('dist/js')); 38 | }); 39 | 40 | gulp.task('checked-compile', ['compile'], () => { 41 | if (!compileFailed) 42 | return true; 43 | throw new PluginError('gulp-typescript', 'failed to compile: not executing further tasks'); 44 | }); 45 | 46 | gulp.task('flatten', ['checked-compile'], () => { 47 | return gulp.src('./dist/js/**/*.js') 48 | .pipe(gulpDotFlatten(0)) 49 | .pipe(gulp.dest('./dist/flat')); 50 | }); 51 | 52 | gulp.task('upload', ['flatten'], () => { 53 | return gulp.src('./dist/flat/*.js') 54 | .pipe(gulpRename(path => { path.extname = ''; })) 55 | .pipe(gulpScreepsUpload(config.email, config.password, config.branch, 0)); 56 | }); 57 | 58 | gulp.task('watch', () => { 59 | gulp.watch('./src/**/*.ts', ['build']); 60 | }); 61 | 62 | gulp.task('build', ['upload']); 63 | gulp.task('test', ['lint']); 64 | gulp.task('default', ['watch']); 65 | -------------------------------------------------------------------------------- /src/components/processes/mining/miner-with-link-creep.ts: -------------------------------------------------------------------------------- 1 | import CreepProcess = require("../creep"); 2 | import { CreepMemory } from "../memory/creep"; 3 | import { getProcessById } from "../../kernel/kernel/kernel"; 4 | import MiningProcess = require("../mining/mining"); 5 | interface MinerWithLinkCreepMemory extends CreepMemory { 6 | miningSpot: any[]; 7 | sourceId: string; 8 | depositId: string; 9 | } 10 | class MinerWithLinkCreep extends CreepProcess { 11 | public memory: MinerWithLinkCreepMemory; 12 | public classPath() { 13 | return "components.processes.mining.miner-with-link-creep"; 14 | } 15 | public runCreep(creep: Creep): number { 16 | let [x, y, roomName] = this.memory.miningSpot; 17 | let pos = new RoomPosition(x, y, roomName); 18 | if (!creep.pos.isEqualTo(pos)) { 19 | creep.moveTo(pos); 20 | } else { 21 | let source = Game.getObjectById(this.memory.sourceId); 22 | creep.harvest(source); 23 | const energy = creep.pos.lookFor(LOOK_ENERGY); 24 | if (energy.length) { 25 | creep.pickup(energy[0]); 26 | } 27 | 28 | if (_.sum(creep.carry) >= (creep.carryCapacity - 15)) { 29 | let storage = Game.getObjectById(this.memory.depositId) as Link | Storage; 30 | if (storage) { 31 | creep.transfer(storage, RESOURCE_ENERGY); 32 | } else { 33 | console.log("Missing a storage in room:" + creep.room.name); 34 | this.stop(0); 35 | } 36 | } 37 | 38 | } 39 | 40 | return 0; 41 | } 42 | 43 | public run(): number { 44 | let creep = Game.creeps[this.memory.creepName]; 45 | 46 | if (!creep) { 47 | console.log("A creep has disappeared:" + this.memory.creepName); 48 | if (this.parentPID !== 0) { 49 | let p = getProcessById(this.parentPID); 50 | p.minerDies(this.pid); 51 | } 52 | return this.stop(0); 53 | } else { 54 | this.runCreep(creep); 55 | return 0; 56 | } 57 | } 58 | 59 | public setUp(creepName: string, sourceId: string, depositId: string, miningSpot: any) { 60 | this.memory.creepName = creepName; 61 | this.memory.sourceId = sourceId; 62 | this.memory.miningSpot = miningSpot; 63 | this.memory.depositId = depositId; 64 | } 65 | } 66 | 67 | export = MinerWithLinkCreep; 68 | -------------------------------------------------------------------------------- /src/components/processes/mining/courier.ts: -------------------------------------------------------------------------------- 1 | import Process = require("../../kernel/kernel/process"); 2 | import MiningProcess = require("./mining"); 3 | import { getProcessById } from "../../kernel/kernel/kernel"; 4 | class CourierProcess extends Process { 5 | public classPath() { 6 | return "components.processes.mining.courier"; 7 | } 8 | 9 | public run(): number { 10 | let memory = this.memory; 11 | let name = memory.name; 12 | if (name && Game.creeps[name]) { 13 | this.runCreep(name); 14 | } else { 15 | let p: any = getProcessById(this.parentPID); 16 | if (p) 17 | p.courierDies(this.pid); 18 | return super.stop(0); 19 | } 20 | return 0; 21 | } 22 | 23 | public setUp(creepName: string, receiverId: string) { 24 | this.memory.name = creepName; 25 | this.memory.receiverId = receiverId; 26 | } 27 | public runCreep(creepName: string): number { 28 | let memory = this.memory; 29 | let creep = Game.creeps[creepName]; 30 | let minerCreep: Creep | null = Game.creeps[memory.minerName]; 31 | 32 | if (!minerCreep) { 33 | memory.minerName = null; 34 | minerCreep = this.getNewMinerCreep(); 35 | if (minerCreep) 36 | memory.minerName = minerCreep.name; 37 | } 38 | 39 | if (creep.carry.energy === creep.carryCapacity) { 40 | let receiver = Game.getObjectById(memory.receiverId); 41 | creep.moveTo(receiver); 42 | creep.transfer(receiver, RESOURCE_ENERGY); 43 | } else { 44 | if (minerCreep) { 45 | creep.moveTo(minerCreep); 46 | if (_.sum(minerCreep.carry) >= 0.9 * minerCreep.carryCapacity) 47 | minerCreep.transfer(creep, RESOURCE_ENERGY); 48 | const containerList = _.filter(minerCreep.pos.lookFor(LOOK_STRUCTURES), 49 | (s: Structure) => s.structureType === STRUCTURE_CONTAINER); 50 | 51 | if (containerList.length) { 52 | let container = containerList[0]; 53 | 54 | if (_.sum(container.store) > 200) { 55 | creep.withdraw(container, RESOURCE_ENERGY); 56 | } 57 | } 58 | 59 | } 60 | } 61 | return 0; 62 | } 63 | 64 | private getNewMinerCreep(): Creep | null { 65 | let p: MiningProcess = getProcessById(this.parentPID); 66 | return p.getMinerCreep(); 67 | } 68 | } 69 | 70 | export = CourierProcess; 71 | -------------------------------------------------------------------------------- /src/components/processes/room/crane.ts: -------------------------------------------------------------------------------- 1 | import OvermindProcess = require("../overmind"); 2 | 3 | interface Coord { 4 | x: number; 5 | y: number; 6 | } 7 | interface CraneMemory { 8 | creepName: string; 9 | spawningRoomName: string; 10 | pos: Coord; 11 | fromID: string; 12 | toID: string; 13 | } 14 | 15 | class CraneProcess extends OvermindProcess { 16 | public memory: CraneMemory; 17 | public classPath() { 18 | return "components.processes.room.crane"; 19 | } 20 | 21 | public creepDies(_id: string, _pid: number) { 22 | 23 | } 24 | 25 | public receiveCreep(_id: string, creep: Creep) { 26 | this.memory.creepName = creep.name; 27 | } 28 | 29 | public run(): number { 30 | const creep = Game.creeps[this.memory.creepName]; 31 | const room = Game.rooms[this.memory.spawningRoomName]; 32 | const energyAvailable = room.energyCapacityAvailable; 33 | if (!creep) { 34 | let multiplier = Math.floor((energyAvailable - 50) / 50); 35 | if (multiplier > 4) 36 | multiplier = 4; 37 | this.spawnCreep("crane", { MOVE: 1, CARRY: multiplier }); 38 | } else { 39 | const pos = this.memory.pos; 40 | if (!creep.pos.isEqualTo(pos.x, pos.y)) 41 | creep.moveTo(pos.x, pos.y); 42 | else { 43 | const fromObj = Game.getObjectById(this.memory.fromID) as Link; 44 | const toObj = Game.getObjectById(this.memory.toID) as Storage; 45 | if (fromObj) { 46 | creep.withdraw(fromObj, RESOURCE_ENERGY); 47 | } 48 | if (creep.carry.energy && creep.carry.energy > 0) 49 | creep.transfer(toObj, RESOURCE_ENERGY); 50 | 51 | } 52 | } 53 | return 0; 54 | } 55 | 56 | // When starting, we need to make sure that no one is already doing a similar task 57 | public static start(roomName: string, pos: Coord, fromID: string, toID: string, parentPID: number = 0) { 58 | const p = new CraneProcess(0, parentPID); 59 | const processTable = p.kernel.processTable 60 | for (const i in processTable) { 61 | const p = processTable[i]; 62 | if (p instanceof CraneProcess) { 63 | if ((p.memory.spawningRoomName === roomName) && 64 | (p.memory.fromID === fromID) && 65 | (p.memory.toID === toID)) { 66 | return p.pid; 67 | } 68 | } 69 | } 70 | p.kernel.addProcess(p); 71 | p.memory.spawningRoomName = roomName; 72 | p.memory.pos = pos; 73 | p.memory.fromID = fromID; 74 | p.memory.toID = toID; 75 | return p.pid; 76 | } 77 | } 78 | 79 | export = CraneProcess; 80 | -------------------------------------------------------------------------------- /src/components/processes/room/maintainer.ts: -------------------------------------------------------------------------------- 1 | import * as Kernel from "../../kernel/kernel/kernel"; 2 | import { OvermindMemory } from "../memory/overmind"; 3 | import OvermindProcess = require("../overmind"); 4 | import MaintainerCreep = require("./maintainer-creep"); 5 | interface MaintainerMemory extends OvermindMemory { 6 | roomName: string; 7 | childPidList: number[]; 8 | } 9 | export = class MaintainerProcess extends OvermindProcess { 10 | public static start(roomName: string, parentPID: number) { 11 | const p = new MaintainerProcess(0, parentPID); 12 | MaintainerProcess.addProcess(p); 13 | p.memory.spawningRoomName = roomName; 14 | p.memory.roomName = roomName; 15 | p.memory.childPidList = []; 16 | return p.pid; 17 | } 18 | 19 | public classPath() { 20 | return "components.processes.room.maintainer"; 21 | } 22 | public memory: MaintainerMemory; 23 | public creepDies(__: string, pid: number) { 24 | this.memory.childPidList = _.filter(this.memory.childPidList, (p) => (p !== pid)); 25 | } 26 | 27 | public receiveCreep(id: string, creep: Creep) { 28 | if (id === "maintainer") { 29 | const p = new MaintainerCreep(0, this.pid); 30 | MaintainerProcess.addProcess(p); 31 | p.memory.creepName = creep.name; 32 | p.memory.roomName = this.memory.roomName; 33 | this.memory.childPidList.push(p.pid); 34 | } 35 | 36 | } 37 | 38 | public run(): number { 39 | const parent = Kernel.getProcessById(this.parentPID); 40 | if (!parent || (parent.constructor.name !== "ColonyProcess")) { 41 | return this.stop(0); 42 | } 43 | const room: Room = Game.rooms[this.memory.spawningRoomName]!; 44 | if (room!.storage!.store!.energy! < 40000) { 45 | Kernel.sleepProcess(this, 1500); 46 | return 0; 47 | } 48 | 49 | const wallAndRamparts = room.find(FIND_STRUCTURES, 50 | { 51 | filter: (s: Structure) => s.structureType === STRUCTURE_WALL || 52 | s.structureType === STRUCTURE_RAMPART, 53 | }); 54 | 55 | const hpList = _.map(wallAndRamparts, (s: Structure) => s.hits); 56 | const constructions = room.find(FIND_CONSTRUCTION_SITES); 57 | 58 | if ((_.min(hpList) > 1000000) && (constructions.length === 0)) { 59 | Kernel.sleepProcess(this, 1000); 60 | return 0; 61 | } 62 | this.memory.childPidList = this.memory.childPidList || []; 63 | 64 | if (this.memory.childPidList.length < 2) { 65 | const energyCapacity = room.energyCapacityAvailable - 500 - 250; 66 | const multiplier = Math.floor(energyCapacity / (50 + 50)); 67 | this.spawnCreep("maintainer", { MOVE: multiplier + 5, CARRY: multiplier, WORK: 5 }); 68 | } 69 | return 0; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /libs/gulp-dot-flatten.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | const gutil = require('gulp-util'); 5 | const through2 = require('through2'); 6 | const PluginError = require('gulp-util').PluginError; 7 | const recast = require('recast'); 8 | 9 | module.exports = function (logAmount, stringFilter) { 10 | return through2.obj(function (file, enc, next) { 11 | if (logAmount && logAmount > 2) { 12 | gutil.log(`>>> flattener starting file '${gutil.colors.cyan(path.dirname(file.relative) + path.sep + path.basename(file.path))}'`); 13 | } 14 | 15 | if (!file.isDirectory() && !file.isNull() && !file.isStream()) { 16 | try { 17 | file.contents = new Buffer(recast.print(recast.visit(recast.parse(file.contents.toString()), { 18 | visitCallExpression: function (filePath) { 19 | var expr = filePath.node; 20 | 21 | if (expr.callee.name != 'require') { 22 | this.traverse(filePath); 23 | } else if (expr.callee.name == 'require') { 24 | this.traverse(filePath); 25 | if (expr.arguments.length && expr.arguments[0].value && expr.arguments[0].value[0] == '.') { 26 | let arg = expr.arguments[0]; 27 | let value = path.posix.normalize(path.dirname(file.relative).split(path.sep).join(path.posix.sep) + '/./' + arg.value); 28 | let result = './' + value.split('/').join('.'); 29 | 30 | if (stringFilter) result = stringFilter(result); 31 | 32 | if (logAmount && logAmount > 1) { 33 | gutil.log(`> in file '${gutil.colors.cyan(path.dirname(file.relative) + path.sep + path.basename(file.path))}', flattened path '${gutil.colors.cyan(expr.arguments[0].value)}' into '${gutil.colors.cyan(result)}'`); 34 | } 35 | 36 | expr.arguments[0] = arg.raw.charAt(0) + result + arg.raw.charAt(0); 37 | } else { 38 | if (logAmount && logAmount > 2) { 39 | gutil.log('> failed test: expr.arguments.length && expr.arguments[0].value[0] == \'.\' : ' + expr.arguments[0].value); 40 | } 41 | } 42 | } else { 43 | return false; 44 | } 45 | }, 46 | })).code); 47 | 48 | let relPath = path.dirname(file.relative).split(path.sep); 49 | relPath.push(path.basename(file.path)); 50 | 51 | let newName = relPath.join('.'); 52 | 53 | while (newName[0] == '.') newName = newName.slice(1); 54 | if (stringFilter) newName = stringFilter(result); 55 | 56 | if (logAmount && logAmount > 0) { 57 | gutil.log(`>> flattened file '${gutil.colors.cyan(path.dirname(file.relative) + path.sep + path.basename(file.path))}' into '${gutil.colors.cyan(newName)}'`); 58 | } 59 | 60 | file.path = path.join(file.base, '', newName); 61 | this.push(file); 62 | } catch (e) { 63 | this.emit('error', new PluginError('flatten', e)); 64 | } 65 | } 66 | 67 | next(); 68 | }); 69 | }; 70 | -------------------------------------------------------------------------------- /src/components/processes/room/starter.ts: -------------------------------------------------------------------------------- 1 | import { addProcess, getProcessById, storeProcessTable } from "../../kernel/kernel/kernel"; 2 | import Process = require("../../kernel/kernel/process"); 3 | import StarterCreepProcess = require("../room/starter-creep"); 4 | class StarterProcess extends Process { 5 | public static start(roomName: string) { 6 | const p = new StarterProcess(0, 0); 7 | addProcess(p); 8 | p.memory.roomName = roomName; 9 | storeProcessTable(); 10 | } 11 | 12 | public classPath() { 13 | return "components.processes.room.starter"; 14 | } 15 | 16 | public getNeededIndex(creepPIDList: number[]): number { 17 | const process = _.map(creepPIDList, getProcessById) as StarterCreepProcess[]; 18 | const odd = _.filter(process, ((p) => p.getIndex() === 1)); 19 | const even = _.filter(process, ((p) => p.getIndex() === 0)); 20 | if (odd.length < even.length) 21 | return 1; 22 | return 0; 23 | } 24 | public creepDies(childPid: number) { 25 | this.memory.creepPIDList = _.filter(this.memory.creepPIDList, (pid) => pid !== childPid); 26 | }; 27 | public run(): number { 28 | const memory = this.memory; 29 | memory.creepPIDList = memory.creepPIDList || []; 30 | const creepList: string[] = memory.creepPIDList; 31 | const roomName = memory.roomName; 32 | const room = Game.rooms[roomName]; 33 | const energyCapacity = room.energyCapacityAvailable; 34 | let multiplier = Math.floor(energyCapacity / 250); 35 | if (creepList.length < 6) { 36 | if (creepList.length === 0) { 37 | multiplier = Math.floor(room.energyAvailable / 250); 38 | } 39 | const result = this.spawnCreep({ WORK: 1 * multiplier, MOVE: 2 * multiplier, CARRY: 1 * multiplier }); 40 | 41 | if (_.isString(result)) { 42 | const process = new StarterCreepProcess(0, this.pid); 43 | addProcess(process); 44 | process.memory.index = this.getNeededIndex(memory.creepPIDList); 45 | process.memory.creepName = result; 46 | memory.creepPIDList.push(process.pid); 47 | } 48 | } 49 | return 0; 50 | } 51 | 52 | private spawnCreep(bodyParts: bodyMap) { 53 | const makeBody = function(bodyMap: bodyMap): string[] { 54 | const partMap: { [s: string]: string } = { 55 | WORK, 56 | MOVE, 57 | CARRY, 58 | ATTACK, 59 | }; 60 | const replicatePart = function(times: number, part: string) { 61 | return _.map(_.times(times, (x) => x), 62 | () => partMap[part]); 63 | }; 64 | return _.chain(bodyMap).map(replicatePart).flatten().value() as string[]; 65 | }; 66 | const room = Game.rooms[this.memory.roomName]; 67 | const spawns = room.find(FIND_STRUCTURES, { filter: (s: Spawn) => s.structureType === STRUCTURE_SPAWN }) as Spawn[]; 68 | if (spawns.length) { 69 | return spawns[0].createCreep(makeBody(bodyParts), undefined); 70 | } 71 | } 72 | } 73 | 74 | export = StarterProcess; 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is actively under development. Looking for contributors! 2 | 3 | I can be found in game or on Slack with username "NhanHo". 4 | 5 | # TLDR : 6 | Implemented with a fancy process system. This can be used on a completely new account. Right now the features go up to "all the code needed for a RCL 4 room", proper mining and remote mining. 7 | 8 | 9 | # How to try this out 10 | 11 | For your own safety, it's better to only try this in a completely new colony (ie. you just respawn) for now. 12 | 13 | First, edit `config.example.json` and put in the appropriate infomation, then copy it to `config.json` 14 | 15 | In screeps console, enter `RawMemory.set("{}")`. This will delete everything you have in your memory. 16 | 17 | ``` 18 | git clone https://github.com/NhanHo/ScreepsOS.git ScreepsOS 19 | cd ScreepsOS 20 | npm install 21 | ./node_modules/.bin/typings install 22 | ./node_modules/.bin/gulp build #This will actually upload code to your account, use compile instead of build if you don't want that to happen 23 | 24 | ``` 25 | 26 | The code should now be deployed to your screeps account. Assuming that you have a spawn named `Spawn1` in a room, input `__("first-room E12N12")` will start a process that spawn creep and start trying to upgrade your room (change the room name to your room name). Note that this does NOT put down structure automatically, so you will have to do that on your own. 27 | 28 | The code for `first-room` process can be found in `src/components/processes/room/starter.ts` 29 | It is recommended to use this process until RCL 4 before switching to the set of processes for high level room. 30 | (More info to come with regard on how to transition to the normal room process for higher level room). 31 | 32 | # An OS for [Screeps](https://www.screeps.com). 33 | 34 | - Motivation can be found here (unfinished document): https://gist.github.com/NhanHo/02949ea3a148c583d57570a1600b4d85 35 | 36 | # Process 37 | - To implement a process, extends class `Process` and implemented the appropriate `run` function. 38 | - A memory object is given to each process at `this.memory`, use this instead of the global Memory to facility proper cleanup. 39 | - Figure out some way to start that process 40 | # Implemented: 41 | 42 | - Basic kernel 43 | - Room starter code (multi purposes creeps for room < RCL 4) process 44 | - Spawn process (with rudimentary priority) 45 | - Mining process (with separate courier) 46 | - Extensions filling process (unoptimized, fill any and all empty extensions) 47 | - Invader shooting process: get all towers and shoot at 48 | - Remote mining 49 | - Command line interface to manage your empire. 50 | 51 | # TODO: All of the features below is planned to be implemented soon™ 52 | 53 | - A list of all available command lines (For the moment, check out `src/components/cli` directory. Every files is a command line that can be used in screeps's console) 54 | - A construction process: since there is a limit of 100 construction sites allowed, we need something to manage the global construction sites. 55 | - Path caching 56 | - Extend mining to energy source 57 | - Labs stuffs 58 | - Boosting stuffs 59 | - Source keeper mining 60 | - Nuke defense 61 | - Kernel: A better scheduler 62 | - Kernel: proper handling of parent/child pid 63 | 64 | NO attacking code will be released publicly, although defense code might. 65 | -------------------------------------------------------------------------------- /src/components/processes/room/maintainer-creep.ts: -------------------------------------------------------------------------------- 1 | import CreepProcess = require("../creep"); 2 | import { CreepMemory } from "../memory/creep"; 3 | const WORKING = 1; 4 | const GET_ENERGY = 2; 5 | 6 | interface MaintainerMemory extends CreepMemory { 7 | roomName: string; 8 | targetId: string; 9 | current: number; 10 | } 11 | export = class MaintainerCreep extends CreepProcess { 12 | public memory: MaintainerMemory; 13 | public classPath() { 14 | return "components.processes.room.maintainer-creep"; 15 | } 16 | 17 | public runCreep(creep: Creep): number { 18 | let obj = Game.getObjectById(this.memory.targetId) as Structure | ConstructionSite | null; 19 | if (!obj) { 20 | obj = this.acquireNewTarget(); 21 | if (obj) 22 | this.memory.targetId = obj.id; 23 | } 24 | if (obj) { 25 | if (creep.carry.energy === 0) { 26 | this.memory.current = GET_ENERGY; 27 | } 28 | if (creep.carry.energy === creep.carryCapacity && this.memory.current !== WORKING) { 29 | this.memory.current = WORKING; 30 | obj = this.acquireNewTarget(); 31 | if (obj) 32 | this.memory.targetId = obj.id; 33 | else 34 | return 0; 35 | } 36 | 37 | if (this.memory.current === GET_ENERGY) { 38 | this.getEnergy(creep); 39 | } else { 40 | this.working(creep, obj); 41 | } 42 | } 43 | 44 | return 0; 45 | } 46 | 47 | private getLowHealthRampart(room: Room) { 48 | const ramparts = room.find(FIND_STRUCTURES, { filter: (s: Rampart) => s.structureType === STRUCTURE_RAMPART && s.hits < 1000 }) as Rampart[]; 49 | const rampart = ramparts.pop(); 50 | if (rampart) 51 | return rampart; 52 | return null; 53 | } 54 | private acquireNewTarget(): Structure | ConstructionSite | null { 55 | const room = Game.rooms[this.memory.roomName]; 56 | 57 | const lowHealthRampart = this.getLowHealthRampart(room); 58 | if (lowHealthRampart) { 59 | return lowHealthRampart; 60 | } 61 | const constructions = room.find(FIND_CONSTRUCTION_SITES) as ConstructionSite[]; 62 | const construction = constructions.pop(); 63 | if (construction) { 64 | return construction; 65 | } 66 | 67 | const structures = room.find(FIND_STRUCTURES, { filter: (s: Structure) => ((s.structureType === STRUCTURE_RAMPART) || (s.structureType === STRUCTURE_WALL)) }) as Structure[]; 68 | const sorted = _.chain(structures).sortBy((s) => s.hits).reverse(); 69 | const s = sorted.value().pop(); 70 | if (s) 71 | return s; 72 | 73 | return null; 74 | } 75 | 76 | private getEnergy(creep: Creep) { 77 | const room = Game.rooms[this.memory.roomName]; 78 | const storage = room.storage; 79 | if (storage) { 80 | creep.moveTo(storage); 81 | creep.withdraw(storage, RESOURCE_ENERGY); 82 | } 83 | } 84 | private working(creep: Creep, obj: Structure | ConstructionSite) { 85 | if (!creep.pos.inRangeTo(obj.pos, 3)) 86 | return creep.moveTo(obj); 87 | 88 | if (obj instanceof ConstructionSite) { 89 | creep.build(obj); 90 | } else { 91 | creep.repair(obj); 92 | } 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/components/processes/room/spawn.ts: -------------------------------------------------------------------------------- 1 | import { addProcess, getProcessById } from "../../kernel/kernel/kernel"; 2 | import Process = require("../../kernel/kernel/process"); 3 | import { ProcessPriority } from "../constants"; 4 | interface CreepRequest { 5 | pid: number; 6 | creepID: string; 7 | bodyParts: bodyMap; 8 | priority: number; 9 | } 10 | class SpawnProcess extends Process { 11 | public static start(roomName: string, parentPID: number) { 12 | let p = new SpawnProcess(0, parentPID); 13 | p = addProcess(p, ProcessPriority.TiclyLast); 14 | p.memory.roomName = roomName; 15 | return p; 16 | } 17 | 18 | public classPath() { 19 | return "components.processes.room.spawn"; 20 | } 21 | public getRoomName() { 22 | return this.memory.roomName; 23 | } 24 | public spawn(id: string, bodyMap: bodyMap, pid: number, priority = 10): number { 25 | const memory = this.memory; 26 | const existing = _.find(memory.requestList as CreepRequest[], (r) => (r.creepID === id) && (r.pid === pid)); 27 | if (existing) { 28 | return -1; 29 | } else { 30 | const creepRequest = { pid, creepID: id, bodyParts: bodyMap, priority }; 31 | memory.requestList.push(creepRequest); 32 | return 0; 33 | } 34 | 35 | } 36 | public run(): number { 37 | const colonyProcess = getProcessById(this.parentPID); 38 | if (!colonyProcess) 39 | return this.stop(0); 40 | 41 | const roomName = this.memory.roomName; 42 | if (!roomName) 43 | return this.stop(0); 44 | const makeBody = function(bodyMap: bodyMap): string[] { 45 | // TODO : Fix the part map, this need to include all part type somehow 46 | const partMap: { [s: string]: string } = { 47 | WORK, 48 | MOVE, 49 | CARRY, 50 | ATTACK, 51 | CLAIM, 52 | }; 53 | const replicatePart = function(times: number, part: string) { 54 | return _.map(_.times(times, (x) => x), 55 | () => partMap[part]); 56 | }; 57 | return _.chain(bodyMap).map(replicatePart).flatten().value() as string[]; 58 | }; 59 | 60 | const memory = this.memory; 61 | memory.requestList = memory.requestList || []; 62 | memory.requestList = _.sortBy(memory.requestList as CreepRequest[], (i) => i.priority); 63 | const request: CreepRequest = memory.requestList.pop(); 64 | const spawn = this.findFreeSpawn(this.memory.roomName); 65 | if (request) { 66 | if (spawn) { 67 | const body = makeBody(request.bodyParts); 68 | const canSpawn = spawn.canCreateCreep(body); 69 | if (canSpawn === OK) { 70 | const process: any = getProcessById(request.pid); 71 | const creepName = spawn.createCreep(body); 72 | process.receiveCreep(request.creepID, Game.creeps[creepName]); 73 | } 74 | } 75 | } 76 | return 0; 77 | 78 | } 79 | 80 | private findFreeSpawn(roomName: string) { 81 | const spawns = _.filter(Game.spawns, 82 | function(spawn) { 83 | return spawn.room.name === roomName && 84 | spawn.spawning == null && 85 | spawn.canCreateCreep([MOVE]) === OK && 86 | spawn.isActive(); 87 | }); 88 | if (spawns.length > 0) 89 | return spawns[0]; 90 | return null; 91 | }; 92 | } 93 | 94 | export = SpawnProcess; 95 | -------------------------------------------------------------------------------- /src/components/processes/mining/miner-creep.ts: -------------------------------------------------------------------------------- 1 | import Process = require("../../kernel/kernel/process"); 2 | import { getProcessById } from "../../kernel/kernel/kernel"; 3 | import MiningProcess = require("../mining/mining"); 4 | class MinerCreepProcess extends Process { 5 | public classPath() { 6 | return "components.processes.mining.miner-creep"; 7 | } 8 | /* Memory has 9 | * sourceID 10 | * creep name 11 | */ 12 | 13 | public getMinerCreep(): Creep | null { 14 | return Game.creeps[this.memory.name]; 15 | } 16 | 17 | public runCreep(creep: Creep) { 18 | // Right now, we will make the miner check for its own container, and build or repair as needed 19 | // Ideally, this could be done from outside. 20 | // TODO: Best way to do this would be to have a separate creep that will do repair, and spawn it as necessary (and by separate creep, I mean a different class) 21 | const source = Game.getObjectById(this.memory.sourceId); 22 | const containerList = _.filter(creep.pos.lookFor(LOOK_STRUCTURES), 23 | s => s.structureType === STRUCTURE_CONTAINER); 24 | const container = containerList![0]; 25 | if (creep.pos.isNearTo(source)) { 26 | creep.harvest(source); 27 | const energy = creep.pos.lookFor(LOOK_ENERGY); 28 | if (energy.length) { 29 | creep.pickup(energy[0]); 30 | } 31 | if (container) { 32 | if (container.hits < (0.5 * container.hitsMax)) { 33 | if ((creep.carry.energy) && (creep.carry.energy > 30)) 34 | creep.repair(container); 35 | } 36 | if (container.store.energy > 0) 37 | container.transfer(creep, RESOURCE_ENERGY); 38 | if (container.store.energy > 1800) { 39 | let p = getProcessById(this.parentPID); 40 | p.needMoreCourier(); 41 | } 42 | if (_.sum(container.store) < 700) { 43 | let p = getProcessById(this.parentPID); 44 | p.lowContainerUsage(); 45 | } 46 | } else { 47 | let constructionSite: ConstructionSite[] = creep.pos.lookFor(LOOK_CONSTRUCTION_SITES); 48 | if (!constructionSite.length) { 49 | creep.pos.createConstructionSite(STRUCTURE_CONTAINER); 50 | constructionSite = creep.pos.lookFor(LOOK_CONSTRUCTION_SITES); 51 | } 52 | if ((creep.carry.energy) && (creep.carry.energy > 30)) 53 | creep.build(constructionSite[0]); 54 | } 55 | } else { 56 | let [x, y, roomName] = this.memory.miningSpot; 57 | let pos = new RoomPosition(x, y, roomName); 58 | creep.moveTo(pos); 59 | 60 | } 61 | } 62 | 63 | public stop(signal: number): number { 64 | let p: any = getProcessById(this.parentPID); 65 | if (p) 66 | p.minerDies(this.pid); 67 | return super.stop(signal); 68 | } 69 | 70 | public setUp(creepName: string, sourceId: string) { 71 | this.memory.name = creepName; 72 | this.memory.sourceId = sourceId; 73 | } 74 | public run(): number { 75 | let creep = Game.creeps[this.memory.name]; 76 | if (!creep) { 77 | this.stop(0) 78 | } else { 79 | if (!this.parentPID) { 80 | creep.suicide(); 81 | return this.stop(0); 82 | } 83 | this.runCreep(creep); 84 | } 85 | return 0; 86 | } 87 | } 88 | 89 | export = MinerCreepProcess; 90 | -------------------------------------------------------------------------------- /src/components/processes/room/claim.ts: -------------------------------------------------------------------------------- 1 | import { addProcess, getProcessById } from "../../kernel/kernel/kernel"; 2 | import Process = require("../../kernel/kernel/process"); 3 | import { getSpawnProcess } from "../../utils/spawn"; 4 | import StarterClaimCreepProcess = require("./starter-claim-creep"); 5 | interface ClaimMemory { 6 | spawningRoomName: string; 7 | targetRoomName: string; 8 | claimerCreep: string; 9 | starterCreepPid: number[]; 10 | } 11 | class ClaimProcess extends Process { 12 | public memory: ClaimMemory; 13 | public classPath() { 14 | return "components.processes.room.claim"; 15 | } 16 | 17 | public creepDies(pid: number) { 18 | this.memory.starterCreepPid = _.filter(this.memory.starterCreepPid, (p) => p !== pid); 19 | } 20 | 21 | public getNeededIndex(): number { 22 | const creepPIDList = this.memory.starterCreepPid; 23 | const process = _.filter(_.map(creepPIDList, getProcessById), 24 | (p: Process) => p instanceof StarterClaimCreepProcess) as StarterClaimCreepProcess[]; 25 | const odd = _.filter(process, ((p) => p.getIndex() === 1)); 26 | const even = _.filter(process, ((p) => p.getIndex() === 0)); 27 | if (odd.length < even.length) 28 | return 1; 29 | return 0; 30 | } 31 | 32 | public receiveCreep(id: string, creep: Creep): number { 33 | if (id === "starter") { 34 | const p = new StarterClaimCreepProcess(0, this.pid); 35 | addProcess(p); 36 | p.memory.creepName = creep.name; 37 | p.memory.targetRoomName = this.memory.targetRoomName; 38 | p.memory.index = this.getNeededIndex(); 39 | this.memory.starterCreepPid.push(p.pid); 40 | } 41 | if (id === "claimer") { 42 | this.memory.claimerCreep = creep.name; 43 | } 44 | 45 | return 0; 46 | } 47 | 48 | public run(): number { 49 | const targetRoom = Game.rooms[this.memory.targetRoomName]; 50 | if (!targetRoom || !targetRoom.controller!.my) { 51 | this.runClaimer(); 52 | } else { 53 | this.memory.starterCreepPid = this.memory.starterCreepPid || []; 54 | const starterPid = this.memory.starterCreepPid; 55 | if (starterPid.length < 6) { 56 | const spawningRoom = Game.rooms[this.memory.spawningRoomName]; 57 | const energyCapacity = spawningRoom.energyCapacityAvailable; 58 | const multiplier = Math.floor(energyCapacity / 250); 59 | this.spawnCreep("starter", 60 | { WORK: 1 * multiplier, MOVE: 2 * multiplier, CARRY: 1 * multiplier }, 5); 61 | } 62 | } 63 | return 0; 64 | } 65 | 66 | protected spawnCreep(creepID: string, bodyParts: bodyMap, priority?: number) { 67 | // TODO: Check and throw error when there is no roomName 68 | const spawnProcess = getSpawnProcess(this.memory.spawningRoomName); 69 | 70 | if (spawnProcess) { 71 | spawnProcess.spawn(creepID, bodyParts, this.pid, priority); 72 | } 73 | } 74 | 75 | private runClaimer() { 76 | const claimer = Game.creeps[this.memory.claimerCreep]; 77 | if (!claimer) { 78 | this.spawnCreep("claimer", { MOVE: 1, CLAIM: 1 }, 5); 79 | } else { 80 | const targetRoom = Game.rooms[this.memory.targetRoomName]; 81 | if (targetRoom) { 82 | claimer.moveTo(targetRoom.controller!); 83 | claimer.claimController(targetRoom.controller!); 84 | if (targetRoom.controller!.my) 85 | claimer.suicide(); 86 | } else { 87 | claimer.moveTo(new RoomPosition(25, 25, this.memory.targetRoomName)); 88 | } 89 | } 90 | 91 | } 92 | } 93 | 94 | export = ClaimProcess; 95 | -------------------------------------------------------------------------------- /src/components/processes/room/starter-creep.ts: -------------------------------------------------------------------------------- 1 | import { getProcessById } from "../../kernel/kernel/kernel"; 2 | import Process = require("../../kernel/kernel/process"); 3 | import StarterProcess = require("./starter"); 4 | class StarterCreepProcess extends Process { 5 | public classPath() { 6 | return "components.processes.room.starter-creep"; 7 | } 8 | 9 | public getIndex() { 10 | return this.memory.index; 11 | } 12 | public run(): number { 13 | const creep = Game.creeps[this.memory.creepName]; 14 | 15 | if (!creep) { 16 | console.log("A creep has disappeared:" + this.memory.creepName); 17 | const p = getProcessById(this.parentPID) as StarterProcess; 18 | p.creepDies(this.pid); 19 | return this.stop(0); 20 | } else { 21 | this.runCreep(creep); 22 | return 0; 23 | } 24 | } 25 | 26 | private runCreep(creep: Creep) { 27 | const starterProcess = getProcessById(this.parentPID) as StarterProcess; 28 | if (!starterProcess) { 29 | creep.suicide(); 30 | this.stop(0); 31 | } 32 | 33 | const memory = this.memory; 34 | const room = creep.room; 35 | const index = memory.index; 36 | const controller = room.controller!; 37 | 38 | const targets: ConstructionSite[] = room.find(FIND_CONSTRUCTION_SITES) as ConstructionSite[]; 39 | if (controller.level === 0) { 40 | creep.moveTo(controller); 41 | creep.claimController(controller); 42 | return; 43 | } 44 | if (memory.currentAction === undefined) memory.currentAction = "Mine"; 45 | 46 | if (memory.currentAction === "Mine") { 47 | if (creep.carry.energy === creep.carryCapacity) { 48 | memory.currentAction = "Build"; 49 | return; 50 | } 51 | 52 | const source: Source = creep.room.find(FIND_SOURCES)[index] as Source; 53 | 54 | creep.moveTo(source); 55 | creep.harvest(source); 56 | 57 | } else { 58 | if (creep.carry.energy === 0) { 59 | memory.currentAction = "Mine"; 60 | return; 61 | 62 | } 63 | if (controller.ticksToDowngrade < 1000) { 64 | creep.moveTo(controller); 65 | creep.upgradeController(controller); 66 | return; 67 | } 68 | 69 | const storages: Structure[] = creep.room.find(FIND_MY_STRUCTURES, { 70 | filter(s: Extension) { 71 | return s.structureType === STRUCTURE_EXTENSION 72 | && s.energy < s.energyCapacity; 73 | }, 74 | }) as Structure[]; 75 | 76 | const spawnNeedEnergy = creep.room.find(FIND_MY_SPAWNS, { filter(spawn: Spawn) { return spawn.energy < spawn.energyCapacity; } }); 77 | storages.push.apply(storages, spawnNeedEnergy); 78 | 79 | if (!storages.length) { 80 | if (targets.length) { 81 | creep.moveTo(targets[0]); 82 | creep.build(targets[0]); 83 | 84 | } else { 85 | if (controller.level > 3 && room.storage) { 86 | creep.moveTo(room.storage); 87 | creep.transfer(room.storage, RESOURCE_ENERGY); 88 | } else { 89 | creep.moveTo(controller); 90 | creep.upgradeController(controller); 91 | } 92 | } 93 | } else { 94 | const target = _.min(storages, function(item) { 95 | return creep.pos.getRangeTo(item); 96 | }); 97 | creep.moveTo(target); 98 | creep.transfer(target, RESOURCE_ENERGY); 99 | 100 | } 101 | } 102 | 103 | } 104 | } 105 | export = StarterCreepProcess; 106 | -------------------------------------------------------------------------------- /src/components/processes/remote-room/outpost.ts: -------------------------------------------------------------------------------- 1 | import OvermindProcess = require("../overmind"); 2 | import MiningProcess = require("../mining/mining"); 3 | import { addProcess, getProcessById, sleepProcess } from "../../kernel/kernel/kernel"; 4 | import { OvermindMemory } from "../memory/overmind"; 5 | import ReserveCreep = require("./reserve-creep"); 6 | interface OutpostMemory extends OvermindMemory { 7 | //colonyPid: number; 8 | miningPid: number[]; 9 | reserveCreepPid?: number; 10 | roomName: string; 11 | 12 | } 13 | 14 | class OutpostProcess extends OvermindProcess { 15 | public classPath() { 16 | return "components.processes.remote-room.outpost"; 17 | } 18 | 19 | public memory: OutpostMemory; 20 | public creepDies(id: string, pid: number) { 21 | if (id === "reserve") { 22 | if (pid !== this.memory.reserveCreepPid) { 23 | console.log("Error: We got a different reserve pid for outpost:" + 24 | this.memory.roomName) 25 | console.log("Error: Spawning extra reserve?"); 26 | } else 27 | this.memory.reserveCreepPid = undefined; 28 | } 29 | 30 | }; 31 | 32 | public receiveCreep(id: string, creep: Creep) { 33 | if (id === "reserve") { 34 | let p = new ReserveCreep(0, this.pid); 35 | addProcess(p); 36 | p.memory.id = "reserve"; 37 | p.memory.creepName = creep.name; 38 | p.memory.roomName = this.memory.roomName; 39 | this.memory.reserveCreepPid = p.pid; 40 | } 41 | 42 | } 43 | public startMining() { 44 | this.memory.miningPid = this.memory.miningPid || []; 45 | if (this.memory.miningPid.length > 0) 46 | return; 47 | 48 | const roomName = this.memory.roomName; 49 | const room = Game.rooms[roomName]; 50 | 51 | if (room) { 52 | console.log("Starting mining for room:" + this.memory.roomName); 53 | let sources = room.find(FIND_SOURCES) as Source[]; 54 | 55 | for (let source of sources) { 56 | let mining = new MiningProcess(0, this.pid); 57 | addProcess(mining); 58 | mining.setup(this.memory.spawningRoomName, source.id); 59 | this.memory.miningPid.push(mining.pid); 60 | } 61 | console.log("Mining successfully started for room:" + roomName); 62 | } 63 | } 64 | 65 | public run(): number { 66 | const reserveCreepPid = this.memory.reserveCreepPid; 67 | if (!reserveCreepPid || !getProcessById(reserveCreepPid)) { 68 | const room = Game.rooms[this.memory.roomName]; 69 | if (!room) 70 | return 0; 71 | if (!room.controller) { 72 | console.log(`Pid ${this.pid} Trying to reserve a room without controller?!`); 73 | return 0; 74 | } 75 | if (!room.controller.reservation || (room.controller.reservation.ticksToEnd < 4000)) 76 | this.spawnCreep("reserve", { CLAIM: 2, MOVE: 2 }); 77 | else 78 | this.spawnCreep("reserve", { CLAIM: 1, MOVE: 1 }); 79 | } 80 | 81 | if (this.memory.miningPid.length === 0) 82 | this.startMining(); 83 | this.invaderCheck(); 84 | return 0; 85 | } 86 | 87 | public psInfo() { 88 | return ("Outpost " + this.memory.roomName); 89 | } 90 | 91 | private invaderCheck() { 92 | const room = Game.rooms[this.memory.roomName]; 93 | if (!room) 94 | return; 95 | const invaderList = room.find(FIND_HOSTILE_CREEPS, 96 | { filter: c => c.owner.username === "Invader" }); 97 | const invader = invaderList.pop(); 98 | if (invader) { 99 | sleepProcess(this, 1500); 100 | for (let pid of this.memory.miningPid) { 101 | const p = getProcessById(pid); 102 | sleepProcess(p, 1500); 103 | } 104 | if (this.memory.reserveCreepPid) 105 | sleepProcess(getProcessById(this.memory.reserveCreepPid), 1500); 106 | } 107 | } 108 | 109 | } 110 | 111 | export = OutpostProcess; 112 | -------------------------------------------------------------------------------- /src/components/processes/room/starter-claim-creep.ts: -------------------------------------------------------------------------------- 1 | import { getProcessById } from "../../kernel/kernel/kernel"; 2 | import Process = require("../../kernel/kernel/process"); 3 | import ClaimProcess = require("./claim"); 4 | interface StarterClaimCreepMemory { 5 | index: number; 6 | targetRoomName: string; 7 | currentAction: string; 8 | creepName: string; 9 | } 10 | class StarterClaimCreepProcess extends Process { 11 | public classPath() { 12 | return "components.processes.room.starter-claim-creep"; 13 | } 14 | 15 | public memory: StarterClaimCreepMemory; 16 | 17 | public getIndex() { 18 | return this.memory.index; 19 | } 20 | public run(): number { 21 | const creep = Game.creeps[this.memory.creepName]; 22 | if (!creep) { 23 | console.log("A creep has disappeared:" + this.memory.creepName); 24 | const p = getProcessById(this.parentPID) as ClaimProcess; 25 | p.creepDies(this.pid); 26 | return this.stop(0); 27 | } else { 28 | this.runCreep(creep); 29 | return 0; 30 | } 31 | } 32 | 33 | private moveToAnotherRoom(creep: Creep): number { 34 | const room = Game.rooms[this.memory.targetRoomName]; 35 | if (creep.room.name !== room.name) { 36 | creep.moveTo(room.controller!); 37 | return 0; 38 | } 39 | return -1; 40 | 41 | } 42 | private runCreep(creep: Creep) { 43 | const starterProcess = getProcessById(this.parentPID) as ClaimProcess; 44 | if (!starterProcess) { 45 | creep.suicide(); 46 | this.stop(0); 47 | } 48 | 49 | if (this.moveToAnotherRoom(creep) === 0) 50 | return 0; 51 | 52 | const memory = this.memory; 53 | const room = creep.room; 54 | let index = memory.index; 55 | 56 | if (!index) { 57 | index = this.memory.index = starterProcess.getNeededIndex(); 58 | } 59 | const targets: ConstructionSite[] = room.find(FIND_CONSTRUCTION_SITES) as ConstructionSite[]; 60 | memory.currentAction = memory.currentAction || "Mine"; 61 | 62 | if (memory.currentAction === "Mine") { 63 | if (creep.carry.energy === creep.carryCapacity) { 64 | memory.currentAction = "Build"; 65 | return; 66 | } 67 | 68 | const source: Source = creep.room.find(FIND_SOURCES)[index] as Source; 69 | creep.moveTo(source); 70 | creep.harvest(source); 71 | if (creep.pos.inRangeTo(creep.room.controller!.pos, 3)) 72 | creep.upgradeController(creep.room.controller!); 73 | 74 | } else { 75 | if (creep.carry.energy === 0) { 76 | memory.currentAction = "Mine"; 77 | return; 78 | 79 | } 80 | if (creep.room.controller!.ticksToDowngrade < 1000) { 81 | creep.moveTo(creep.room.controller!); 82 | creep.upgradeController(creep.room.controller!); 83 | return; 84 | } 85 | 86 | const storages: Structure[] = creep.room.find(FIND_MY_STRUCTURES, { 87 | filter(s: Extension) { 88 | return s.structureType === STRUCTURE_EXTENSION 89 | && s.energy < s.energyCapacity; 90 | }, 91 | }) as Structure[]; 92 | 93 | const spawnNeedEnergy = creep.room.find(FIND_MY_SPAWNS, { filter(spawn: Spawn) { return spawn.energy < spawn.energyCapacity; } }); 94 | storages.push.apply(storages, spawnNeedEnergy); 95 | 96 | if (!storages.length) { 97 | if (targets.length) { 98 | creep.moveTo(targets[0]); 99 | creep.build(targets[0]); 100 | 101 | } else { 102 | if (room.controller!.level > 3 && room.storage) { 103 | creep.moveTo(room.storage); 104 | creep.transfer(room.storage, RESOURCE_ENERGY); 105 | } else { 106 | creep.moveTo(creep.room.controller!); 107 | creep.upgradeController(creep.room.controller!); 108 | } 109 | } 110 | } else { 111 | const target = _.min(storages, function(item) { 112 | return creep.pos.getRangeTo(item); 113 | }); 114 | creep.moveTo(target); 115 | creep.transfer(target, RESOURCE_ENERGY); 116 | 117 | } 118 | } 119 | 120 | } 121 | } 122 | export = StarterClaimCreepProcess; 123 | -------------------------------------------------------------------------------- /src/components/processes/room/librarian.ts: -------------------------------------------------------------------------------- 1 | import { getProcessById } from "../../kernel/kernel/kernel"; 2 | import Process = require("../../kernel/kernel/process"); 3 | import { getSpawnProcess } from "../../utils/spawn"; 4 | class LibrarianProcess extends Process { 5 | 6 | public classPath() { 7 | return "components.processes.room.librarian"; 8 | } 9 | 10 | public receiveCreep(id: string, creep: Creep) { 11 | if (id === "small") { 12 | this.memory.smallCreepName = creep.name; 13 | } 14 | if (id === "big") { 15 | this.memory.creepName = creep.name; 16 | } 17 | } 18 | public runCreep(creepName: string): number { 19 | const creep = Game.creeps[creepName]; 20 | 21 | const storage = creep.room.storage; 22 | let toSpawn = true; 23 | if (!storage) { 24 | toSpawn = false; 25 | } 26 | if (creep.carry.energy === 0) { 27 | if (storage) { 28 | if (!creep.pos.isNearTo(storage)) { 29 | creep.moveTo(storage); 30 | } else { 31 | creep.withdraw(storage, RESOURCE_ENERGY); 32 | } 33 | } 34 | } else { 35 | let storages: Array = creep.room.find(FIND_MY_STRUCTURES, { 36 | filter(s: any) { 37 | return (s.structureType === STRUCTURE_EXTENSION || s.structureType === STRUCTURE_TOWER) 38 | && s.needEnergy(); 39 | }, 40 | }) as Array; 41 | const spawnInDestRoom = creep.room.find(FIND_MY_SPAWNS, { filter(spawn: Spawn) { return spawn.energy < spawn.energyCapacity; } }); 42 | if (toSpawn) 43 | storages.push.apply(storages, spawnInDestRoom); 44 | 45 | if (storages.length) { 46 | let min = _.min(storages, function(item) { 47 | return creep.pos.getRangeTo(item); 48 | }); 49 | if (creep.pos.isNearTo(min)) { 50 | creep.transfer(min, RESOURCE_ENERGY); 51 | storages = _.filter(storages, (x) => x.id !== min.id); 52 | min = _.min(storages, function(item) { 53 | return creep.pos.getRangeTo(item); 54 | }); 55 | creep.moveTo(min); 56 | 57 | } else { 58 | creep.moveTo(min); 59 | } 60 | 61 | } 62 | } 63 | return 0; 64 | 65 | } 66 | 67 | public spawnSmallCreep(): number { 68 | const room = Game.rooms[this.memory.roomName]; 69 | const availableEnergy = room.energyAvailable; 70 | let modifier = Math.floor(availableEnergy / 100); 71 | if (modifier > 25) 72 | modifier = 25; 73 | 74 | this.spawnCreep("small", { CARRY: modifier, MOVE: modifier }, 100); 75 | return 0; 76 | } 77 | 78 | public spawnNormalCreep(): number { 79 | const room = Game.rooms[this.memory.roomName]; 80 | const availableEnergy = room.energyCapacityAvailable; 81 | let modifier = Math.floor(availableEnergy / 100); 82 | if (modifier > 25) 83 | modifier = 25; 84 | this.spawnCreep("big", { CARRY: modifier, MOVE: modifier }, 100); 85 | return 0; 86 | 87 | } 88 | 89 | public run(): number { 90 | const colonyProcess = getProcessById(this.parentPID); 91 | if (!colonyProcess) 92 | return this.stop(0); 93 | 94 | const memory = this.memory; 95 | let smallCreepName = memory.smallCreepName; 96 | let creepName = memory.creepName; 97 | 98 | if (smallCreepName && !Game.creeps[smallCreepName]) 99 | smallCreepName = memory.smallCreepName = null; 100 | 101 | if (creepName && !Game.creeps[creepName]) 102 | creepName = memory.creepName = null; 103 | 104 | if (!creepName) { 105 | if (!smallCreepName) { 106 | this.spawnSmallCreep(); 107 | } else { 108 | this.spawnNormalCreep(); 109 | } 110 | } 111 | 112 | if (smallCreepName) 113 | this.runCreep(smallCreepName); 114 | 115 | if (creepName) 116 | this.runCreep(creepName); 117 | return 0; 118 | } 119 | 120 | protected spawnCreep(creepID: string, bodyParts: bodyMap, priority?: number) { 121 | const spawnProcess = getSpawnProcess(this.memory.roomName); 122 | 123 | if (spawnProcess) { 124 | spawnProcess.spawn(creepID, bodyParts, this.pid, priority); 125 | } 126 | } 127 | } 128 | 129 | export = LibrarianProcess; 130 | -------------------------------------------------------------------------------- /src/components/processes/room/link-manager.ts: -------------------------------------------------------------------------------- 1 | import Process = require("../../kernel/kernel/process"); 2 | import CraneProcess = require("./crane"); 3 | 4 | interface LinkManagerMemory { 5 | roomName: string; 6 | senderLinks: string[]; 7 | receiverLinks: string[]; 8 | lastUpdate: number; 9 | } 10 | /** This is a comment */ 11 | class LinkManagerProcess extends Process { 12 | public memory: LinkManagerMemory; 13 | /** 14 | * This is a test docs 15 | */ 16 | public classPath() { 17 | return "components.processes.room.link-manager"; 18 | } 19 | 20 | /** 21 | * Loop through each sender links, send to the first receiver link that can use energy 22 | * TODO We can have a process for each link: that way the link can track if it's inactive 23 | * for too long and request crane/ figure out what is happening 24 | */ 25 | public run(): number { 26 | if (!this.memory.lastUpdate || (this.memory.lastUpdate < (Game.time - 3000))) { 27 | this.setUp(this.memory.roomName); 28 | this.memory.lastUpdate = Game.time; 29 | } 30 | const neededEnergy = _.chain(this.memory.receiverLinks) 31 | .map(Game.getObjectById) 32 | .filter((s: Link) => s && s.energy < (s.energyCapacity / 4)).value() as Link[]; 33 | 34 | for (const id of this.memory.senderLinks) { 35 | const obj = Game.getObjectById(id) as Link; 36 | if (!obj || (obj.cooldown > 0)) { 37 | continue; 38 | } 39 | if (obj.energy >= (obj.energyCapacity * 0.9)) { 40 | const target = neededEnergy.pop(); 41 | if (target) 42 | obj.transferEnergy(target); 43 | } 44 | } 45 | return 0; 46 | } 47 | 48 | /** 49 | * Setup our links network. Right now, we're using a few heuristics to 50 | * determine which link is sending energy, and which one is receiving it. 51 | * 52 | * We have two types of links: sender and receiver. 53 | * 54 | * Receiver link: links next to storage, or close to a controller (within 55 | * 4 square of a controller -- such that another creep and withdraw energy 56 | * from it and is still within range of the controller). 57 | * 58 | * Sender link: For now, miners or couriers will deposit their energy to 59 | * the link, and sender link are any link not a receiver link. 60 | */ 61 | private setUp(roomName: string) { 62 | this.memory.roomName = roomName; 63 | const senderLinks: string[] = []; 64 | const receiverLinks: string[] = []; 65 | const room = Game.rooms[roomName]; 66 | const links = room.find(FIND_MY_STRUCTURES, 67 | { filter: (s: Structure) => s.structureType === STRUCTURE_LINK }) as Link[]; 68 | for (const link of links) { 69 | if (link.pos.inRangeTo(room.controller!.pos, 4) || 70 | link.pos.inRangeTo(room.storage!.pos, 2)) { 71 | receiverLinks.push(link.id); 72 | } else 73 | senderLinks.push(link.id); 74 | } 75 | this.memory.senderLinks = senderLinks; 76 | this.memory.receiverLinks = receiverLinks; 77 | 78 | // Check and setup the crane process if necessary 79 | this.setupCrane(receiverLinks); 80 | } 81 | 82 | private setupCrane(linkIDs: string[]) { 83 | const links = _.map(linkIDs, Game.getObjectById) as Link[]; 84 | for (const link of links) { 85 | const storage = link.room.storage!; 86 | const hasNoStructure = function(p: RoomPosition): boolean { 87 | return !_.some(p.lookFor(LOOK_STRUCTURES), (s: Structure) => (s.structureType != STRUCTURE_ROAD)); 88 | } 89 | const nextToStorage = (pos: RoomPosition) => pos.isNearTo(storage.pos); 90 | if (link.pos.inRangeTo(link.room.storage!.pos, 2)) { 91 | const pos = _.filter(link.pos.adjacentPositions(), 92 | (p: RoomPosition) => 93 | Game.map.getTerrainAt(p) !== "wall" && 94 | hasNoStructure(p) && nextToStorage(p)); 95 | CraneProcess.start(this.memory.roomName, 96 | { x: pos[0].x, y: pos[0].y }, 97 | link.id, 98 | storage.id, 99 | this.pid); 100 | } 101 | } 102 | } 103 | 104 | public static start(roomName: string, colonyPID: number) { 105 | const p = new LinkManagerProcess(0, colonyPID); 106 | p.kernel.addProcess(p); 107 | p.setUp(roomName); 108 | 109 | return p.pid; 110 | } 111 | } 112 | 113 | export = LinkManagerProcess; 114 | -------------------------------------------------------------------------------- /src/components/processes/room/colony.ts: -------------------------------------------------------------------------------- 1 | import { 2 | addProcess, getProcessById, killProcess, 3 | processTable, sleepProcess, storeProcessTable, 4 | } from "../../kernel/kernel/kernel"; 5 | import Process = require("../../kernel/kernel/process"); 6 | import MiningProcess = require("../mining/mining"); 7 | import DefenseProcess = require("./defense"); 8 | import LibrarianProcess = require("./librarian"); 9 | import LinkManagerProcess = require("./link-manager"); 10 | import MaintainerProcess = require("./maintainer"); 11 | import SpawnProcess = require("./spawn"); 12 | import StarterProcess = require("./starter"); 13 | import UpgraderProcess = require("./upgrader"); 14 | // import BuilderPlannerProcess = require("./building-planner"); 15 | class ColonyProcess extends Process { 16 | public static start(roomName: string) { 17 | const p = new ColonyProcess(0, 0); 18 | addProcess(p); 19 | storeProcessTable(); 20 | 21 | p.memory.roomName = roomName; 22 | console.log("New room started:" + roomName); 23 | 24 | } 25 | 26 | public classPath() { 27 | return "components.processes.room.colony"; 28 | } 29 | 30 | public getRoomName() { 31 | return this.memory.roomName; 32 | } 33 | 34 | public psInfo() { 35 | return ("ColonyProcess " + this.getRoomName()); 36 | } 37 | 38 | public run(): number { 39 | const memory = this.memory; 40 | const room = Game.rooms[memory.roomName]; 41 | 42 | const spawnPID = memory.spawnPID; 43 | if (!spawnPID || !getProcessById(spawnPID)) { 44 | memory.spawnPID = this.launchSpawnProcess(room.name); 45 | } 46 | if (room.controller!.level >= 4 && room.storage && room.storage.store.energy && room.storage.store.energy > 10000) { 47 | 48 | const upgraderPID = memory.upgraderPID; 49 | 50 | if (!upgraderPID || !getProcessById(upgraderPID)) { 51 | console.log("Starting upgrader process for Room:" + room.name); 52 | memory.upgraderPID = UpgraderProcess.start(memory.roomName, this.pid); 53 | } 54 | 55 | const defenderPID = memory.defenderPID; 56 | if (!defenderPID || !getProcessById(defenderPID)) { 57 | console.log("Starting defender process for Room:" + room.name); 58 | memory.defenderPID = DefenseProcess.start(memory.roomName, this.pid); 59 | } 60 | 61 | const maintainerPID = memory.maintainerPID; 62 | if (!maintainerPID || !getProcessById(maintainerPID)) { 63 | console.log("Starting maintainer process for room:" + room.name); 64 | memory.maintainerPID = MaintainerProcess.start(memory.roomName, this.pid); 65 | } 66 | 67 | const linkPID = memory.linkPID; 68 | if (!linkPID || !getProcessById(linkPID)) { 69 | console.log("Starting link process for room:" + room.name); 70 | memory.linkPID = LinkManagerProcess.start(memory.roomName, this.pid); 71 | } 72 | 73 | const librarianPID = memory.librarianPID; 74 | if (!librarianPID || !getProcessById(librarianPID)) { 75 | const p = new LibrarianProcess(0, this.pid); 76 | addProcess(p); 77 | p.memory.roomName = room.name; 78 | memory.librarianPID = p.pid; 79 | } 80 | 81 | let inRoomMiningPid: number[] = memory.miningPIDList || []; 82 | inRoomMiningPid = _.filter(inRoomMiningPid, (pid) => getProcessById(pid)); 83 | if (inRoomMiningPid.length === 0) { 84 | const sources = room.find(FIND_SOURCES) as Source[]; 85 | for (const source of sources) { 86 | const sourceId = source.id; 87 | const roomName = room.name; 88 | const flag = Game.flags[sourceId]; 89 | if (!flag) { 90 | source.pos.createFlag(sourceId, COLOR_YELLOW); 91 | } 92 | 93 | let p = new MiningProcess(0, this.pid); 94 | p = addProcess(p); 95 | p.memory.sourceId = sourceId; 96 | p.memory.spawningRoomName = roomName; 97 | p.memory.flagName = sourceId; 98 | inRoomMiningPid.push(p.pid); 99 | } 100 | memory.miningPIDList = inRoomMiningPid; 101 | this.killStarterProcess(room.name); 102 | } 103 | sleepProcess(this, 100); 104 | } 105 | 106 | return 0; 107 | } 108 | 109 | private killStarterProcess(roomName: string) { 110 | for (const pid in processTable) { 111 | const p = processTable[pid]; 112 | if (p instanceof StarterProcess && p.memory.roomName === roomName) { 113 | killProcess(p.pid); 114 | return; 115 | } 116 | } 117 | } 118 | 119 | private launchSpawnProcess(roomName: string) { 120 | console.log("Starting spawn process for room:" + roomName); 121 | const p = SpawnProcess.start(roomName, this.pid); 122 | p.parentPID = this.pid; 123 | return p.pid; 124 | } 125 | } 126 | 127 | export = ColonyProcess; 128 | -------------------------------------------------------------------------------- /src/components/processes/room/upgrader.ts: -------------------------------------------------------------------------------- 1 | import { addProcess, getProcessById, sleepProcess } from "../../kernel/kernel/kernel"; 2 | import Process = require("../../kernel/kernel/process"); 3 | import { getSpawnProcess } from "../../utils/spawn"; 4 | interface UpgraderMemory { 5 | name: string | undefined; 6 | hasCourier: boolean; 7 | roomName: string; 8 | courierName: string | undefined; 9 | containerID: string | undefined; 10 | isFixingContainer: boolean; 11 | } 12 | class UpgraderProcess extends Process { 13 | public memory: UpgraderMemory; 14 | public static start(roomName: string, parentPID: number) { 15 | const p = new UpgraderProcess(0, parentPID); 16 | addProcess(p); 17 | p.memory.roomName = roomName; 18 | return p.pid; 19 | } 20 | 21 | public classPath() { 22 | return "components.processes.room.upgrader"; 23 | } 24 | public run(): number { 25 | const colonyProcess = getProcessById(this.parentPID); 26 | if (!colonyProcess) 27 | return this.stop(0); 28 | 29 | const room = Game.rooms[this.memory.roomName]; 30 | if (!room.storage || (room.storage.store.energy && room.storage.store.energy < 40000)) { 31 | sleepProcess(this, 1500); 32 | return 0; 33 | } 34 | const memory = this.memory; 35 | const upgraderName = memory.name; 36 | if (upgraderName && Game.creeps[upgraderName]) { 37 | this.runCreep(upgraderName); 38 | } else { 39 | this.spawnCreep(); 40 | } 41 | 42 | if (this.memory.hasCourier) { 43 | const courierName = this.memory.courierName; 44 | if (courierName && Game.creeps[courierName]) 45 | this.runCourier(courierName); 46 | else 47 | this.spawnCourier(); 48 | } 49 | return 0; 50 | } 51 | 52 | public runCreep(creepName: string): number { 53 | const creep = Game.creeps[creepName]; 54 | let storage: StructureStorage | StructureContainer | null = Game.getObjectById(this.memory.containerID!) as StructureStorage | StructureContainer; 55 | const controller = creep.room.controller!; 56 | if (!storage) 57 | storage = this.getEnergySource(); 58 | if (!storage) { 59 | sleepProcess(this, 1000); 60 | console.log("Missing energy source for upgrader in room " + this.memory.roomName); 61 | return 0; 62 | } else { 63 | this.memory.containerID = storage.id; 64 | } 65 | 66 | if (creep.pos.inRangeTo(controller.pos, 3) && 67 | creep.pos.isNearTo(storage.pos)) { 68 | creep.withdraw(storage, RESOURCE_ENERGY); 69 | this.work(creep); 70 | } else { 71 | const pos = _.filter(storage.pos.adjacentPositions(), (pos) => pos.inRangeTo(controller.pos, 3)); 72 | if (pos.length > 0) 73 | creep.moveTo(pos[0]); 74 | else { 75 | console.log(`Upgrader in room ${this.memory.roomName} can't find a spot to upgrade`); 76 | } 77 | } 78 | if (!(storage instanceof StructureStorage)) 79 | this.memory.hasCourier = true; 80 | return 0; 81 | } 82 | 83 | private runCourier(creepName: string): number { 84 | const creep = Game.creeps[creepName]; 85 | const storage: StructureStorage | StructureContainer | null = Game.getObjectById(this.memory.containerID!) as StructureStorage | StructureContainer; 86 | if (!storage) { 87 | return 0; 88 | } 89 | 90 | const room = Game.rooms[this.memory.roomName]; 91 | if (creep.carry.energy === 0) { 92 | creep.moveTo(room.storage!); 93 | creep.withdraw(room.storage!, RESOURCE_ENERGY); 94 | } else { 95 | creep.moveTo(storage); 96 | creep.transfer(storage, RESOURCE_ENERGY); 97 | } 98 | return 0; 99 | 100 | } 101 | public receiveCreep(id: string, creep: Creep) { 102 | if (id === "upgrader") 103 | this.memory.name = creep.name; 104 | if (id === "courier") 105 | this.memory.courierName = creep.name; 106 | } 107 | 108 | private getEnergySource(): StructureContainer | StructureStorage | null { 109 | const room = Game.rooms[this.memory.roomName]; 110 | const storage = room.storage!; 111 | const controller = room.controller!; 112 | if (!storage) 113 | return null; 114 | const pos = _.filter(storage.pos.adjacentPositions(), (pos) => pos.inRangeTo(controller.pos, 3)); 115 | if (pos.length === 0) { 116 | const allContainers = room.find(FIND_STRUCTURES, { filter: (s: Structure) => s.structureType === STRUCTURE_CONTAINER && s.pos.inRangeTo(controller.pos, 3) }) as StructureContainer[]; 117 | if (allContainers.length > 0) { 118 | return allContainers[0]; 119 | } else 120 | return null; 121 | 122 | } else { 123 | return storage; 124 | } 125 | 126 | } 127 | 128 | private work(creep: Creep) { 129 | const container = Game.getObjectById(this.memory.containerID!) as Structure; 130 | if (!this.memory.isFixingContainer) { 131 | if (container.hits < (container.hitsMax / 2)) 132 | this.memory.isFixingContainer = true; 133 | } else { 134 | if (container.hits === container.hitsMax) 135 | this.memory.isFixingContainer = false; 136 | } 137 | if (this.memory.isFixingContainer) 138 | creep.repair(container); 139 | else 140 | creep.upgradeController(creep.room.controller!); 141 | } 142 | private spawnCreep() { 143 | const roomName = this.memory.roomName; 144 | const spawnProcess = getSpawnProcess(this.memory.roomName); 145 | let energy = Game.rooms[roomName].energyCapacityAvailable; 146 | energy = energy - 50; 147 | const multiplier = Math.floor(energy / 250); 148 | if (spawnProcess) { 149 | spawnProcess.spawn("upgrader", { CARRY: 1, WORK: 2 * multiplier, MOVE: multiplier }, 150 | this.pid); 151 | } 152 | } 153 | 154 | private spawnCourier() { 155 | const roomName = this.memory.roomName; 156 | const spawnProcess = getSpawnProcess(this.memory.roomName); 157 | const energy = Game.rooms[roomName].energyCapacityAvailable; 158 | const multiplier = Math.floor(energy / 100); 159 | if (spawnProcess) { 160 | spawnProcess.spawn("courier", { CARRY: multiplier, MOVE: multiplier }, 161 | this.pid); 162 | } 163 | 164 | } 165 | } 166 | 167 | export = UpgraderProcess; 168 | -------------------------------------------------------------------------------- /src/minimist.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | export = function (args, opts) { 3 | if (!opts) opts = {}; 4 | 5 | var flags: any = { bools: {}, strings: {}, unknownFn: null }; 6 | 7 | if (typeof opts['unknown'] === 'function') { 8 | flags.unknownFn = opts['unknown']; 9 | } 10 | 11 | if (typeof opts['boolean'] === 'boolean' && opts['boolean']) { 12 | flags.allBools = true; 13 | } else { 14 | [].concat(opts['boolean']).filter(Boolean).forEach(function (key: any) { 15 | flags.bools[key] = true; 16 | }); 17 | } 18 | 19 | var aliases = {}; 20 | Object.keys(opts.alias || {}).forEach(function (key) { 21 | aliases[key] = [].concat(opts.alias[key]); 22 | aliases[key].forEach(function (x) { 23 | aliases[x] = [key].concat(aliases[key].filter(function (y) { 24 | return x !== y; 25 | })); 26 | }); 27 | }); 28 | 29 | [].concat(opts.string).filter(Boolean).forEach(function (key: any) { 30 | flags.strings[key] = true; 31 | if (aliases[key]) { 32 | flags.strings[aliases[key]] = true; 33 | } 34 | }); 35 | 36 | var defaults = opts['default'] || {}; 37 | 38 | var argv: any = { _: [] }; 39 | Object.keys(flags.bools).forEach(function (key: any) { 40 | setArg(key, defaults[key] === undefined ? false : defaults[key]); 41 | }); 42 | 43 | var notFlags = []; 44 | 45 | if (args.indexOf('--') !== -1) { 46 | notFlags = args.slice(args.indexOf('--') + 1); 47 | args = args.slice(0, args.indexOf('--')); 48 | } 49 | 50 | function argDefined(key, arg) { 51 | return (flags.allBools && /^--[^=]+$/.test(arg)) || 52 | flags.strings[key] || flags.bools[key] || aliases[key]; 53 | } 54 | 55 | function setArg(key, val, arg?: any) { 56 | if (arg && flags.unknownFn && !argDefined(key, arg)) { 57 | if (flags.unknownFn(arg) === false) return; 58 | } 59 | 60 | var value = !flags.strings[key] && isNumber(val) 61 | ? Number(val) : val 62 | ; 63 | setKey(argv, key.split('.'), value); 64 | 65 | (aliases[key] || []).forEach(function (x) { 66 | setKey(argv, x.split('.'), value); 67 | }); 68 | } 69 | 70 | function setKey(obj, keys, value) { 71 | var o = obj; 72 | keys.slice(0, -1).forEach(function (key) { 73 | if (o[key] === undefined) o[key] = {}; 74 | o = o[key]; 75 | }); 76 | 77 | var key = keys[keys.length - 1]; 78 | if (o[key] === undefined || flags.bools[key] || typeof o[key] === 'boolean') { 79 | o[key] = value; 80 | } 81 | else if (Array.isArray(o[key])) { 82 | o[key].push(value); 83 | } 84 | else { 85 | o[key] = [o[key], value]; 86 | } 87 | } 88 | 89 | function aliasIsBoolean(key) { 90 | return aliases[key].some(function (x) { 91 | return flags.bools[x]; 92 | }); 93 | } 94 | 95 | for (var i = 0; i < args.length; i++) { 96 | var arg = args[i]; 97 | 98 | if (/^--.+=/.test(arg)) { 99 | // Using [\s\S] instead of . because js doesn't support the 100 | // 'dotall' regex modifier. See: 101 | // http://stackoverflow.com/a/1068308/13216 102 | var m = arg.match(/^--([^=]+)=([\s\S]*)$/); 103 | var key = m[1]; 104 | var value = m[2]; 105 | if (flags.bools[key]) { 106 | value = value !== 'false'; 107 | } 108 | setArg(key, value, arg); 109 | } 110 | else if (/^--no-.+/.test(arg)) { 111 | var key = arg.match(/^--no-(.+)/)[1]; 112 | setArg(key, false, arg); 113 | } 114 | else if (/^--.+/.test(arg)) { 115 | var key = arg.match(/^--(.+)/)[1]; 116 | var next = args[i + 1]; 117 | if (next !== undefined && !/^-/.test(next) 118 | && !flags.bools[key] 119 | && !flags.allBools 120 | && (aliases[key] ? !aliasIsBoolean(key) : true)) { 121 | setArg(key, next, arg); 122 | i++; 123 | } 124 | else if (/^(true|false)$/.test(next)) { 125 | setArg(key, next === 'true', arg); 126 | i++; 127 | } 128 | else { 129 | setArg(key, flags.strings[key] ? '' : true, arg); 130 | } 131 | } 132 | else if (/^-[^-]+/.test(arg)) { 133 | var letters = arg.slice(1, -1).split(''); 134 | 135 | var broken = false; 136 | for (var j = 0; j < letters.length; j++) { 137 | var next = arg.slice(j + 2); 138 | 139 | if (next === '-') { 140 | setArg(letters[j], next, arg) 141 | continue; 142 | } 143 | 144 | if (/[A-Za-z]/.test(letters[j]) && /=/.test(next)) { 145 | setArg(letters[j], next.split('=')[1], arg); 146 | broken = true; 147 | break; 148 | } 149 | 150 | if (/[A-Za-z]/.test(letters[j]) 151 | && /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) { 152 | setArg(letters[j], next, arg); 153 | broken = true; 154 | break; 155 | } 156 | 157 | if (letters[j + 1] && letters[j + 1].match(/\W/)) { 158 | setArg(letters[j], arg.slice(j + 2), arg); 159 | broken = true; 160 | break; 161 | } 162 | else { 163 | setArg(letters[j], flags.strings[letters[j]] ? '' : true, arg); 164 | } 165 | } 166 | 167 | var key = arg.slice(-1)[0]; 168 | if (!broken && key !== '-') { 169 | if (args[i + 1] && !/^(-|--)[^-]/.test(args[i + 1]) 170 | && !flags.bools[key] 171 | && (aliases[key] ? !aliasIsBoolean(key) : true)) { 172 | setArg(key, args[i + 1], arg); 173 | i++; 174 | } 175 | else if (args[i + 1] && /true|false/.test(args[i + 1])) { 176 | setArg(key, args[i + 1] === 'true', arg); 177 | i++; 178 | } 179 | else { 180 | setArg(key, flags.strings[key] ? '' : true, arg); 181 | } 182 | } 183 | } 184 | else { 185 | if (!flags.unknownFn || flags.unknownFn(arg) !== false) { 186 | argv._.push( 187 | flags.strings['_'] || !isNumber(arg) ? arg : Number(arg) 188 | ); 189 | } 190 | if (opts.stopEarly) { 191 | argv._.push.apply(argv._, args.slice(i + 1)); 192 | break; 193 | } 194 | } 195 | } 196 | 197 | Object.keys(defaults).forEach(function (key) { 198 | if (!hasKey(argv, key.split('.'))) { 199 | setKey(argv, key.split('.'), defaults[key]); 200 | 201 | (aliases[key] || []).forEach(function (x) { 202 | setKey(argv, x.split('.'), defaults[key]); 203 | }); 204 | } 205 | }); 206 | 207 | if (opts['--']) { 208 | argv['--'] = new Array(); 209 | notFlags.forEach(function (key) { 210 | argv['--'].push(key); 211 | }); 212 | } 213 | else { 214 | notFlags.forEach(function (key) { 215 | argv._.push(key); 216 | }); 217 | } 218 | 219 | return argv; 220 | }; 221 | 222 | function hasKey(obj, keys) { 223 | var o = obj; 224 | keys.slice(0, -1).forEach(function (key) { 225 | o = (o[key] || {}); 226 | }); 227 | 228 | var key = keys[keys.length - 1]; 229 | return key in o; 230 | } 231 | 232 | function isNumber(x) { 233 | if (typeof x === 'number') return true; 234 | if (/^0x[0-9a-f]+$/i.test(x)) return true; 235 | return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x); 236 | } 237 | 238 | -------------------------------------------------------------------------------- /src/components/processes/mining/mining.ts: -------------------------------------------------------------------------------- 1 | import Process = require("../../kernel/kernel/process"); 2 | import MinerCreep = require("./miner-creep"); 3 | import MinerWithLinkCreep = require("./miner-with-link-creep"); 4 | import CourierCreep = require("./courier"); 5 | import { addProcess, getProcessById } from "../../kernel/kernel/kernel"; 6 | import { getSpawnProcess } from "../../utils/spawn"; 7 | import { OvermindMemory } from "../memory/overmind"; 8 | interface MiningMemory extends OvermindMemory { 9 | minerPid: number | null; 10 | courierPidList: number[]; 11 | sourceId: string; 12 | courierCount: number; 13 | miningSpot: any; 14 | lastCourierCountChange: number; 15 | flagName: string; 16 | lastLowContainerUsage: number; 17 | lowContainerUsageStreak: number; 18 | } 19 | 20 | class MiningProcess extends Process { 21 | /* Memory has: 22 | * roomName 23 | * miner pid 24 | * courier pid 25 | * source ID: sourceId 26 | */ 27 | public memory: MiningMemory; 28 | public classPath() { 29 | return "components.processes.mining.mining"; 30 | } 31 | 32 | public minerDies(_: number) { 33 | this.memory.minerPid = null; 34 | } 35 | 36 | public setup(roomName: string, sourceId: string) { 37 | this.memory.spawningRoomName = roomName; 38 | this.memory.sourceId = sourceId; 39 | this.memory.courierCount = this.memory.courierCount || 1; 40 | this.memory.courierPidList = this.memory.courierPidList || []; 41 | } 42 | public courierDies(courierPid: number) { 43 | let memory = this.memory; 44 | memory.courierPidList = _.filter(memory.courierPidList, pid => pid !== courierPid); 45 | } 46 | 47 | public receiveCreep(id: string, creep: Creep): number { 48 | let creepName = creep.name; 49 | if (id === "miner") { 50 | 51 | const [x, y, roomName] = this.memory.miningSpot; 52 | const pos = new RoomPosition(x, y, roomName); 53 | const hasStorageOrLink = function (pos: RoomPosition) { 54 | return _.some(pos.lookFor(LOOK_STRUCTURES), 55 | (s: Structure) => 56 | s.structureType === STRUCTURE_STORAGE || 57 | s.structureType === STRUCTURE_LINK); 58 | } 59 | 60 | // If there is a link or storage to deposit the energy, we don't have to spawn 61 | // courier and instead just deposit any mined energy to it directly 62 | 63 | if (_.some(pos.adjacentPositions(), hasStorageOrLink)) { 64 | const posWithDeposit = _.find(pos.adjacentPositions(), hasStorageOrLink); 65 | const link = _.find(posWithDeposit.lookFor(LOOK_STRUCTURES), 66 | (s: Structure) => s.structureType === STRUCTURE_STORAGE || 67 | s.structureType === STRUCTURE_LINK) as Structure; 68 | let p = new MinerWithLinkCreep(0, this.pid); 69 | p = addProcess(p); 70 | p.setUp(creepName, this.memory.sourceId, link.id, this.memory.miningSpot); 71 | this.memory.minerPid = p.pid; 72 | } else { 73 | let p = new MinerCreep(0, this.pid); 74 | p = addProcess(p); 75 | p.setUp(creepName, this.memory.sourceId); 76 | this.memory.minerPid = p.pid; 77 | p.memory.miningSpot = this.getMiningSpot(); 78 | } 79 | } 80 | 81 | if (id === "courier") { 82 | let p = new CourierCreep(0, this.pid); 83 | p = addProcess(p); 84 | // TODO: allows different receiver object here 85 | const storage = Game.rooms[this.memory.spawningRoomName].storage 86 | if (storage) 87 | p.setUp(creepName, storage.id); 88 | else 89 | console.log(`Creep ${creepName} does not have a target for deposit`); 90 | p.parentPID = this.pid; 91 | this.memory.courierPidList.push(p.pid); 92 | } 93 | 94 | return 0; 95 | } 96 | 97 | public getMinerCreep() { 98 | if (this.memory.minerPid) { 99 | let p = getProcessById(this.memory.minerPid) as MinerCreep; 100 | if (!p || p instanceof MinerWithLinkCreep) 101 | return null; 102 | return p.getMinerCreep(); 103 | } 104 | return null; 105 | } 106 | 107 | public needMoreCourier(): number { 108 | let lastCourierIncrease = this.memory.lastCourierCountChange = this.memory.lastCourierCountChange || (Game.time - 1501); 109 | 110 | if (lastCourierIncrease > (Game.time - 1501)) 111 | return -1; 112 | if (this.memory.courierCount === 3) { 113 | let source = Game.getObjectById(this.memory.sourceId); 114 | console.log("Mining at source " + this.memory.sourceId + 115 | " is requiring too many couriers. Room:" + source.pos.roomName); 116 | return -1; 117 | } 118 | this.memory.courierCount += 1; 119 | this.memory.lastCourierCountChange = Game.time; 120 | return 0; 121 | } 122 | 123 | public lowContainerUsage(): number { 124 | let lastTick = this.memory.lastLowContainerUsage = this.memory.lastLowContainerUsage || Game.time; 125 | this.memory.lowContainerUsageStreak = this.memory.lowContainerUsageStreak || 0; 126 | if (lastTick === (Game.time - 1)) { 127 | this.memory.lowContainerUsageStreak += 1; 128 | } else 129 | this.memory.lowContainerUsageStreak = 0; 130 | 131 | if ((this.memory.lowContainerUsageStreak > 500) && (this.memory.courierCount > 1)) { 132 | 133 | this.memory.lastCourierCountChange = this.memory.lastCourierCountChange || (Game.time - 1501); 134 | if (this.memory.lastCourierCountChange > (Game.time - 1501)) 135 | return -1; 136 | this.memory.lastCourierCountChange = Game.time; 137 | this.memory.courierCount -= 1; 138 | 139 | } 140 | 141 | this.memory.lastLowContainerUsage = Game.time; 142 | 143 | return 0; 144 | } 145 | 146 | public run(): number { 147 | this.memory.courierCount = this.memory.courierCount || 1; 148 | this.memory.courierPidList = this.memory.courierPidList || []; 149 | let memory = this.memory; 150 | 151 | if (!memory.flagName) { 152 | let source = Game.getObjectById(memory.sourceId); 153 | if (!source) { 154 | console.log("PID: " + this.pid + 155 | " Error: no vision of source and no flag for source: " + memory.sourceId); 156 | return 0; 157 | } 158 | let result = source.pos.createFlag(source.id, COLOR_YELLOW); 159 | if (_.isString(result)) { 160 | memory.flagName = result; 161 | } else { 162 | if (result !== ERR_NAME_EXISTS) { 163 | console.log("Some how we can't create flag:" + source.id); 164 | return 0; 165 | } else 166 | memory.flagName = source.id; 167 | } 168 | } 169 | if (!memory.miningSpot) { 170 | memory.miningSpot = this.getMiningSpot(); 171 | 172 | } 173 | const [x, y, roomName] = this.memory.miningSpot; 174 | const miningPos = new RoomPosition(x, y, roomName); 175 | let storage = Game.rooms[this.memory.spawningRoomName].storage; 176 | 177 | if (storage && miningPos.isNearTo(storage.pos)) { 178 | this.memory.courierCount = 0; 179 | } 180 | 181 | if (!memory.minerPid) { 182 | this.spawnCreep("miner", { WORK: 6, MOVE: 6, CARRY: 1 }, 90); 183 | } else if (memory.courierPidList.length < memory.courierCount) { 184 | this.spawnCreep("courier", { MOVE: 10, CARRY: 10 }); 185 | } 186 | 187 | //this.invaderCheck(); 188 | return 0; 189 | } 190 | 191 | public psInfo() { 192 | return ("Mining Process " + this.memory.spawningRoomName + " " + this.memory.flagName); 193 | } 194 | 195 | protected spawnCreep(creepID: string, bodyParts: bodyMap, priority?: number) { 196 | // TODO: Check and throw error when there is no roomName 197 | let spawnProcess = getSpawnProcess(this.memory.spawningRoomName); 198 | 199 | if (spawnProcess) { 200 | spawnProcess.spawn(creepID, bodyParts, this.pid, priority); 201 | } 202 | } 203 | 204 | private getMiningSpot(): any { 205 | if (!this.memory.miningSpot) { 206 | let source = Game.getObjectById(this.memory.sourceId); 207 | if (!source) { 208 | source = Game.flags[this.memory.flagName]; 209 | } 210 | let storage = Game.rooms[this.memory.spawningRoomName].storage; 211 | if (!storage) { 212 | return; 213 | } 214 | let pathResult = PathFinder.search(storage.pos, { pos: source.pos, range: 1 }); 215 | let path = pathResult.path; 216 | let pos = path[path.length - 1]; 217 | this.memory.miningSpot = [pos.x, pos.y, pos.roomName]; 218 | } 219 | return this.memory.miningSpot; 220 | } 221 | 222 | } 223 | 224 | export = MiningProcess; 225 | --------------------------------------------------------------------------------