Initial
This commit is contained in:
commit
35bcd8d435
76
creep.custom.js
Normal file
76
creep.custom.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
var customCreep = function() {
|
||||
StructureSpawn.prototype.spawnCustomCreep = function(role, name, energy, behaviourLevel) {
|
||||
var body_parts = [];
|
||||
|
||||
var body_pre = [];
|
||||
var body_component = [];
|
||||
var body_post = []
|
||||
var body_pre_cost = 0;
|
||||
var body_component_cost = 0;
|
||||
var body_post_cost = 0;
|
||||
|
||||
switch(role) {
|
||||
case 'upgrader':
|
||||
body_component = [WORK, CARRY, CARRY, MOVE];
|
||||
body_component_cost = 250;
|
||||
break;
|
||||
case 'harvester':
|
||||
body_pre = [CARRY, CARRY, MOVE];
|
||||
body_pre_cost = 150;
|
||||
body_component = [WORK];
|
||||
body_component_cost = 100;
|
||||
break;
|
||||
case 'refiller':
|
||||
body_pre = [WORK, MOVE];
|
||||
body_pre_cost = 150;
|
||||
body_component = [CARRY, CARRY, MOVE];
|
||||
body_component_cost = 150;
|
||||
break;
|
||||
case 'wallRepairer':
|
||||
body_component = [WORK, CARRY, CARRY, MOVE, MOVE, MOVE];
|
||||
body_component_cost = 350;
|
||||
break;
|
||||
case 'pickup':
|
||||
body_pre = [WORK, MOVE];
|
||||
body_pre_cost = 150;
|
||||
body_component = [CARRY, CARRY, MOVE];
|
||||
body_component_cost = 150;
|
||||
break;
|
||||
case 'repairer':
|
||||
body_component = [WORK, CARRY, CARRY, MOVE, MOVE];
|
||||
body_component_cost = 300;
|
||||
break;
|
||||
case 'builder':
|
||||
body_component = [WORK, CARRY, CARRY, MOVE];
|
||||
body_component_cost = 250;
|
||||
break;
|
||||
default:
|
||||
body_component = [WORK, CARRY, MOVE];
|
||||
body_component_cost = 200;
|
||||
break;
|
||||
}
|
||||
|
||||
var num_body_part_patches = Math.floor((energy - (body_pre_cost + body_post_cost)) / body_component_cost);
|
||||
|
||||
// Make pre-body
|
||||
for(var part of body_pre) {
|
||||
body_parts.push(part);
|
||||
}
|
||||
|
||||
// Make component body
|
||||
for(var i = 0; i < num_body_part_patches; i++) {
|
||||
for(var part of body_component) {
|
||||
body_parts.push(part);
|
||||
}
|
||||
}
|
||||
|
||||
// Make post-body
|
||||
for(var part of body_post) {
|
||||
body_parts.push(part);
|
||||
}
|
||||
|
||||
return this.spawnCreep(body_parts, name, {memory: {role: role}});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = customCreep;
|
26
energy.harvest.js
Normal file
26
energy.harvest.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
var harvester = require('energy.harvest.roundrobin');
|
||||
|
||||
var do_collect = function(creep, done_state, done_state_message) {
|
||||
var source = null;
|
||||
if(creep.memory.source_id) {
|
||||
source = Game.getObjectById(creep.memory.source_id);
|
||||
} else {
|
||||
source = harvester.get_source(creep);
|
||||
}
|
||||
|
||||
if(creep.store.getFreeCapacity() > 0) {
|
||||
if(creep.harvest(source) == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(source, {visualizePathStyle: {stroke: '#ffaa00'}});
|
||||
}
|
||||
} else {
|
||||
creep.memory.state = done_state;
|
||||
harvester.release_source(creep);
|
||||
creep.say(done_state_message);
|
||||
}
|
||||
}
|
||||
|
||||
var baseHarvester = {
|
||||
do_collect: do_collect,
|
||||
}
|
||||
|
||||
module.exports = baseHarvester;
|
33
energy.harvest.roundrobin.js
Normal file
33
energy.harvest.roundrobin.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
var get_source = function(creep) {
|
||||
var sources = creep.room.find(FIND_SOURCES);
|
||||
var minSource = null;
|
||||
var minSourceCount = null;
|
||||
|
||||
for(let source of sources) {
|
||||
var amount_at_source = Memory.rooms[creep.room.name].sources[source.id] - Memory.rooms[creep.room.name].sources_spots[source.id];
|
||||
if (minSourceCount == null || amount_at_source < minSourceCount) {
|
||||
minSourceCount = amount_at_source;
|
||||
minSource = source;
|
||||
}
|
||||
}
|
||||
|
||||
Memory.rooms[creep.room.name].sources[minSource.id] += 1;
|
||||
creep.memory.source_id = minSource.id;
|
||||
return minSource;
|
||||
}
|
||||
|
||||
var release_source = function(creep) {
|
||||
if(creep.memory.source_id) {
|
||||
if(Memory.rooms[creep.room.name].sources[creep.memory.source_id] > 0){
|
||||
Memory.rooms[creep.room.name].sources[creep.memory.source_id] -= 1;
|
||||
}
|
||||
delete creep.memory.source_id;
|
||||
}
|
||||
}
|
||||
|
||||
var roundRobinHarvester = {
|
||||
get_source: get_source,
|
||||
release_source: release_source
|
||||
}
|
||||
|
||||
module.exports = roundRobinHarvester;
|
30
energy.storage.js
Normal file
30
energy.storage.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Finds the closest container that has something in it
|
||||
var find_container = function(creep) {
|
||||
return creep.pos.findClosestByPath(FIND_STRUCTURES, {
|
||||
filter: (s) => {
|
||||
return (s.structureType == STRUCTURE_CONTAINER ||
|
||||
s.structureType == STRUCTURE_STORAGE) &&
|
||||
s.store.getUsedCapacity(RESOURCE_ENERGY) > 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var do_collect = function(creep, done_state, done_state_message) {
|
||||
var container = find_container(creep);
|
||||
if (container) {
|
||||
if(creep.withdraw(container, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(container, {visualizePathStyle: {stroke: '#ffaa00'}});
|
||||
}
|
||||
}
|
||||
if (creep.store.getFreeCapacity() == 0) {
|
||||
// If we are full with energy, switch to the next state
|
||||
creep.memory.state = done_state;
|
||||
creep.say(done_state_message);
|
||||
}
|
||||
}
|
||||
|
||||
var baseCollector = {
|
||||
do_collect: do_collect,
|
||||
}
|
||||
|
||||
module.exports = baseCollector;
|
43
idle.base.js
Normal file
43
idle.base.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
var do_idle = function(creep) {
|
||||
// No structure needs filling and my charge is full, move to an idle location
|
||||
if (!creep.memory.idlePosition) {
|
||||
var idlePosition;
|
||||
switch (creep.room.name){
|
||||
case "E16N2":
|
||||
min_x = 36;
|
||||
min_y = 7;
|
||||
max_x = 40;
|
||||
max_y = 8;
|
||||
|
||||
idlePosition = new RoomPosition(Math.floor(Math.random() * (max_x - min_x)) + min_x, Math.floor(Math.random() * (max_y - min_y)) + min_y, creep.room.name);
|
||||
break;
|
||||
default:
|
||||
// Calculate a good idle position next to the closest spawn station
|
||||
idlePosition = creep.pos.findClosestByRange(FIND_MY_SPAWNS).pos;
|
||||
idlePosition.x = idlePosition.x - (Math.floor(Math.random() * 4) + 2); // Number between 2 and 4
|
||||
idlePosition.y = idlePosition.y + (Math.floor(Math.random() * 5) - 2); // Number between -2 and 2
|
||||
break;
|
||||
}
|
||||
creep.memory.idlePosition = {'x': idlePosition.x, 'y': idlePosition.y};
|
||||
}
|
||||
|
||||
// If we are not at the idle position, move there.
|
||||
if(!creep.pos.isEqualTo(creep.memory.idlePosition.x, creep.memory.idlePosition.y)) {
|
||||
var result = creep.moveTo(new RoomPosition(creep.memory.idlePosition.x, creep.memory.idlePosition.y, creep.room.name), {visualizePathStyle: {stroke: '#aaaaaa'}});
|
||||
if (result == ERR_NO_PATH) {
|
||||
creep.say('No path');
|
||||
delete creep.memory.idlePosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var clear_idle = function(creep) {
|
||||
delete creep.memory.idlePosition;
|
||||
}
|
||||
|
||||
var baseIdler = {
|
||||
do_idle: do_idle,
|
||||
clear_idle: clear_idle,
|
||||
}
|
||||
|
||||
module.exports = baseIdler;
|
266
main.js
Normal file
266
main.js
Normal file
|
@ -0,0 +1,266 @@
|
|||
var _ = require('lodash');
|
||||
|
||||
var roleBase = require('role.base');
|
||||
var roleIdle = require('role.idle');
|
||||
var roleHarvester = require('role.harvester');
|
||||
var roleHarvesterV2 = require('role.harvester.v2');
|
||||
var roleRefiller = require('role.refiller');
|
||||
var roleUpgrader = require('role.upgrader');
|
||||
var roleBuilder = require('role.builder');
|
||||
var roleRepairer = require('role.repairer');
|
||||
var roleWallRepairer = require('role.wallrepairer');
|
||||
var rolePickup = require('role.pickup');
|
||||
|
||||
/* About behaviour levels:
|
||||
Level -1
|
||||
Special level to make all creeps move to an idle location.
|
||||
|
||||
Level 1
|
||||
The starting level, this can be run from the start of the map.
|
||||
All bots will mine the resources they need, then do their task.
|
||||
|
||||
Level 2
|
||||
This introduces refillers, overhauls harvesters and changes the behaviour of the rest.
|
||||
Harvesters will deposit mined energy into a container or storage unit placed nearby.
|
||||
Refillers will take energy to structures that need them.
|
||||
Other creeps will take energy from the container/storage instead of mining them themselves.
|
||||
|
||||
Requirements: Containers placed next to all free spots of the sources in the room.
|
||||
Harvesters will then place themselves between the container and the source.
|
||||
For example: (S = source, H = harvester, C = container, X = wall, _ = empty)
|
||||
__C__
|
||||
_HHH_
|
||||
CHSXX
|
||||
_HXXX
|
||||
__XXX
|
||||
*/
|
||||
var behaviourLevel = 2;
|
||||
|
||||
require('creep.custom')();
|
||||
|
||||
// Profiler - https://github.com/screepers/screeps-profiler
|
||||
const profiler = require('screeps-profiler');
|
||||
// Monkey-patch in the profiler
|
||||
profiler.enable();
|
||||
|
||||
module.exports.loop = function () {
|
||||
// Wrap my code in the profiler
|
||||
profiler.wrap(function() {
|
||||
|
||||
// Setup variables with in-game objects for use in the script
|
||||
var towers = _.filter(Game.structures, {structureType: STRUCTURE_TOWER});
|
||||
var harvesters = _.filter(Game.creeps, (creep) => creep.memory.role == 'harvester');
|
||||
var refillers = _.filter(Game.creeps, (creep) => creep.memory.role == 'refiller');
|
||||
var builders = _.filter(Game.creeps, (creep) => creep.memory.role == 'builder');
|
||||
var upgraders = _.filter(Game.creeps, (creep) => creep.memory.role == 'upgrader');
|
||||
var repairers = _.filter(Game.creeps, (creep) => creep.memory.role == 'repairer');
|
||||
var wallRepairers = _.filter(Game.creeps, (creep) => creep.memory.role == 'wallRepairer');
|
||||
var pickups = _.filter(Game.creeps, (creep) => creep.memory.role == 'pickup');
|
||||
|
||||
// Cleanup memory
|
||||
for(var name in Memory.creeps) {
|
||||
if(!Game.creeps[name]) {
|
||||
roleBase.clearMemory(name);
|
||||
delete Memory.creeps[name];
|
||||
console.log('Clearing non-existing creep memory:', name);
|
||||
}
|
||||
}
|
||||
|
||||
if(Memory.rooms == undefined) {Memory.rooms = {};}
|
||||
for (var name in Game.rooms) {
|
||||
if(Memory.rooms[name] == undefined) {
|
||||
Memory.rooms[name] = {};
|
||||
}
|
||||
if(Memory.rooms[name].repairs == undefined) {
|
||||
Memory.rooms[name].repairs = []
|
||||
}
|
||||
if(Memory.rooms[name].sources == undefined) {
|
||||
Memory.rooms[name].sources = {};
|
||||
for(let source of Game.rooms[name].find(FIND_SOURCES)) {
|
||||
Memory.rooms[name].sources[source.id] = 0;
|
||||
}
|
||||
}
|
||||
if(Memory.rooms[name].sources_spots == undefined) {
|
||||
Memory.rooms[name].sources_spots = {};
|
||||
for(let source of Game.rooms[name].find(FIND_SOURCES)) {
|
||||
var num_spots = 0;
|
||||
for (let x of [-1, 0, 1]) {
|
||||
for (let y of [-1, 0, 1]) {
|
||||
if(!(x == 0 && y == 0)){
|
||||
var pos = new RoomPosition(source.pos.x + x, source.pos.y + y, source.pos.roomName);
|
||||
if(pos.lookFor(LOOK_TERRAIN) == "plain"){
|
||||
num_spots += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Memory.rooms[name].sources_spots[source.id] = num_spots;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tower auto-repair structures nearby
|
||||
for(var tower_id in towers) {
|
||||
var tower = towers[tower_id];
|
||||
// var closestDamagedStructure = tower.pos.findClosestByRange(FIND_STRUCTURES, {
|
||||
// filter: (structure) => structure.hits < structure.hitsMax
|
||||
// });
|
||||
// if(closestDamagedStructure) {
|
||||
// tower.repair(closestDamagedStructure);
|
||||
// }
|
||||
|
||||
var closestHostile = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS);
|
||||
if(closestHostile) {
|
||||
tower.attack(closestHostile);
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-spawn new creeps
|
||||
var to_spawn = [];
|
||||
|
||||
var gameTime = Game.time.toString();
|
||||
var name_index = gameTime.substring(gameTime.length-4, gameTime.length);
|
||||
|
||||
if(harvesters.length < 2) {
|
||||
to_spawn.push(['harvester', 'Harvey' + name_index, [WORK, CARRY, MOVE]]);
|
||||
}
|
||||
// Refillers only necessary from behaviour level 2
|
||||
if(behaviourLevel >= 2) {
|
||||
if(refillers.length < 2) {
|
||||
to_spawn.push(['refiller', 'Reffy' + name_index, [WORK, CARRY, MOVE]]);
|
||||
}
|
||||
}
|
||||
if(builders.length < 1) {
|
||||
to_spawn.push(['builder', 'Bob' + name_index, [WORK, CARRY, MOVE]]);
|
||||
}
|
||||
if(repairers.length < 2) {
|
||||
to_spawn.push(['repairer', 'Reppy' + name_index, [WORK, CARRY, MOVE]]);
|
||||
}
|
||||
if(upgraders.length < 1) {
|
||||
to_spawn.push(['upgrader', 'Uppy' + name_index, [WORK, CARRY, MOVE]]);
|
||||
}
|
||||
if(wallRepairers.length < 1) {
|
||||
to_spawn.push(['wallRepairer', 'Wally' + name_index, [WORK, CARRY, MOVE]]);
|
||||
}
|
||||
if(pickups.length < 1) {
|
||||
to_spawn.push(['pickup', 'Picky' + name_index, [WORK, CARRY, MOVE]]);
|
||||
}
|
||||
|
||||
if(to_spawn.length > 0) {
|
||||
for(var spawner_id in Game.spawns) {
|
||||
var spawner = Game.spawns[spawner_id];
|
||||
if(!spawner.spawning){
|
||||
var entry = to_spawn.shift();
|
||||
console.log("Spawning " + entry[0]);
|
||||
var spawned = false;
|
||||
var max_available_energy = spawner.store.getCapacity(RESOURCE_ENERGY);
|
||||
for(let extension of _.filter(Game.structures, {structureType: STRUCTURE_EXTENSION, room: spawner.room})) {
|
||||
max_available_energy += extension.store.getCapacity(RESOURCE_ENERGY);
|
||||
}
|
||||
//max_available_energy = 300;
|
||||
|
||||
var result = spawner.spawnCustomCreep(entry[0], entry[1], max_available_energy, behaviourLevel);
|
||||
|
||||
if (result == OK) {
|
||||
spawner.room.visual.text('Spawning ' + entry[1] + ' /w ' + max_available_energy + " energy.", spawner.pos.x + 1, spawner.pos.y, {align: 'left', opacity: 0.8});
|
||||
}
|
||||
|
||||
// If there are no harvesters any more, and there is not enough energy, spawn a basic harvester.
|
||||
if(harvesters.length == 0 && result == ERR_NOT_ENOUGH_ENERGY) {
|
||||
result = spawner.spawnCreep([WORK, CARRY, MOVE], "BasicHarvester", {memory: {role: 'harvester'}});
|
||||
if (result == OK) {
|
||||
spawner.room.visual.text('Spawning BasicHarvester.');
|
||||
}
|
||||
}
|
||||
// If there are no refillers any more, and there is not enough energy, spawn a basic refiller.
|
||||
if(refillers.length == 0 && result == ERR_NOT_ENOUGH_ENERGY) {
|
||||
result = spawner.spawnCreep([WORK, CARRY, MOVE], "BasicRefiller", {memory: {role: 'refiller'}});
|
||||
if (result == OK) {
|
||||
spawner.room.visual.text('Spawning BasicRefiller.');
|
||||
}
|
||||
}
|
||||
|
||||
if (result != OK) {
|
||||
switch (result) {
|
||||
case ERR_BUSY:
|
||||
console.log("Could not spawn " + entry[1] + ", spawner is busy.");
|
||||
break;
|
||||
case ERR_NOT_ENOUGH_ENERGY:
|
||||
console.log("Could not spawn " + entry[1] + ", not enough energy.");
|
||||
break;
|
||||
case ERR_RCL_NOT_ENOUGH:
|
||||
console.log("Could not spawn " + entry[1] + ", RCL not high enough.");
|
||||
break;
|
||||
default:
|
||||
console.log("Could not spawn " + entry[1] + ", error code " + result);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
spawned = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!spawned){
|
||||
console.log("Could not spawn, all spawners are busy or errored.");
|
||||
}
|
||||
}
|
||||
|
||||
// Execute creep ticks
|
||||
for(var name in Game.creeps) {
|
||||
var creep = Game.creeps[name];
|
||||
|
||||
var continue_with_role = roleBase.run(creep, behaviourLevel);
|
||||
|
||||
// If we are at behaviour level -1, move all bots to an idle position
|
||||
if (behaviourLevel == -1) {
|
||||
roleIdle.run(creep, behaviourLevel);
|
||||
} else {
|
||||
// Else, continue with the normal roles
|
||||
if(continue_with_role) {
|
||||
switch(creep.memory.role) {
|
||||
case "harvester":
|
||||
if (behaviourLevel >= 2) {
|
||||
roleHarvesterV2.run(creep, behaviourLevel);
|
||||
} else {
|
||||
roleHarvester.run(creep, behaviourLevel);
|
||||
}
|
||||
break;
|
||||
case "refiller":
|
||||
if (behaviourLevel >= 2) {
|
||||
roleRefiller.run(creep, behaviourLevel);
|
||||
} else {
|
||||
// No defined behaviour for refillers on level 1, just act as a Harvester.
|
||||
roleHarvester.run(creep, behaviourLevel);
|
||||
}
|
||||
break;
|
||||
case "upgrader":
|
||||
roleUpgrader.run(creep, behaviourLevel);
|
||||
break;
|
||||
case "builder":
|
||||
roleBuilder.run(creep, behaviourLevel);
|
||||
break;
|
||||
case "repairer":
|
||||
roleRepairer.run(creep, behaviourLevel);
|
||||
break;
|
||||
case "wallRepairer":
|
||||
roleWallRepairer.run(creep, behaviourLevel);
|
||||
break;
|
||||
case "pickup":
|
||||
rolePickup.run(creep, behaviourLevel);
|
||||
break;
|
||||
default:
|
||||
console.log("Creep with role " + creep.memory.role + " has no defined behaviour.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print used CPU ticks every 10 game ticks
|
||||
if(Game.time % 100 == 0) {
|
||||
if(Game.cpu.limit){
|
||||
console.log("Used " + Game.cpu.getUsed() + " / " + Game.cpu.limit + "(L) / " + Game.cpu.tickLimit + " (B) CPU this tick. Bucket level: " + Game.cpu.bucket);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
40
role.base.js
Normal file
40
role.base.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
var roleBase = {
|
||||
clearMemory: function(creep_name) {
|
||||
var memory = Memory.creeps[creep_name];
|
||||
console.log("Cleaning up memory for (late) creep " + creep_name);
|
||||
|
||||
if(memory.source_id) {
|
||||
for(var room in Game.rooms) {
|
||||
if(Memory.rooms[room].sources[memory.source_id] != undefined){
|
||||
if(Memory.rooms[room].sources[memory.source_id] > 0){
|
||||
Memory.rooms[room].sources[memory.source_id] -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete memory.source_id;
|
||||
}
|
||||
|
||||
if(memory.repairId) {
|
||||
for(var room in Game.rooms) {
|
||||
_.remove(Memory.rooms[room].repairs, (n) => n == memory.repairId);
|
||||
delete memory.repairId;
|
||||
delete memory.repairTarget;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@param {Creep} creep
|
||||
@param {int} behaviourLevel
|
||||
**/
|
||||
run: function(creep, behaviourLevel) {
|
||||
if(creep.ticksToLive <= 2) {
|
||||
creep.say("Halp X.X!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = roleBase;
|
69
role.builder.js
Normal file
69
role.builder.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
var idler = require('idle.base');
|
||||
var harvester = require('energy.harvest');
|
||||
var collector = require('energy.storage');
|
||||
|
||||
var get_targets = function(creep) {
|
||||
return creep.room.find(FIND_CONSTRUCTION_SITES);
|
||||
}
|
||||
|
||||
var roleBuilder = {
|
||||
|
||||
/**
|
||||
@param {Creep} creep
|
||||
@param {int} behaviourLevel
|
||||
**/
|
||||
run: function(creep, behaviourLevel) {
|
||||
|
||||
switch (creep.memory.state) {
|
||||
case "idle":
|
||||
idler.do_idle(creep);
|
||||
if (get_targets(creep).length > 0){
|
||||
// If there are any buildings to construct, switch back to the building state
|
||||
idler.clear_idle(creep);
|
||||
creep.memory.state = "build_structure";
|
||||
creep.say("building");
|
||||
}
|
||||
if (creep.store.getFreeCapacity() > 0) {
|
||||
// If we are not full with energy, switch to the get_energy state
|
||||
idler.clear_idle(creep);
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say('Reloading...');
|
||||
}
|
||||
break;
|
||||
|
||||
case "build_structure":
|
||||
var targets = get_targets(creep);
|
||||
if(targets.length > 0) {
|
||||
if(creep.build(targets[0]) == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(targets[0], {visualizePathStyle: {stroke: '#ffffff'}});
|
||||
}
|
||||
} else {
|
||||
// Else, go idle
|
||||
creep.memory.state = "idle";
|
||||
creep.say('idling');
|
||||
}
|
||||
if (creep.store.getUsedCapacity() == 0) {
|
||||
// If we have no energy, switch to the get_energy state
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say('Reloading...');
|
||||
}
|
||||
break;
|
||||
|
||||
case "get_energy":
|
||||
var energy_source;
|
||||
if(behaviourLevel >= 2) {
|
||||
energy_source = collector;
|
||||
} else {
|
||||
energy_source = harvester;
|
||||
}
|
||||
energy_source.do_collect(creep, "build_structure", "building");
|
||||
break;
|
||||
|
||||
default:
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say("Reloading...");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = roleBuilder;
|
68
role.harvester.js
Normal file
68
role.harvester.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
var idler = require('idle.base');
|
||||
var harvester = require('energy.harvest');
|
||||
|
||||
var get_targets = function(creep) {
|
||||
return creep.room.find(FIND_STRUCTURES, {
|
||||
filter: (structure) => {
|
||||
return (structure.structureType == STRUCTURE_EXTENSION ||
|
||||
structure.structureType == STRUCTURE_SPAWN ||
|
||||
structure.structureType == STRUCTURE_TOWER) &&
|
||||
structure.store.getFreeCapacity(RESOURCE_ENERGY) > 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var roleHarvester = {
|
||||
|
||||
/**
|
||||
@param {Creep} creep
|
||||
@param {int} behaviourLevel
|
||||
**/
|
||||
run: function(creep, behaviourLevel) {
|
||||
switch (creep.memory.state) {
|
||||
case "idle":
|
||||
idler.do_idle(creep);
|
||||
if (get_targets(creep).length > 0){
|
||||
// If there are any buildings to charge, switch back to the charge state
|
||||
idler.clear_idle(creep);
|
||||
creep.memory.state = "charge_structure";
|
||||
creep.say("Charging...");
|
||||
}
|
||||
if (creep.store.getFreeCapacity() > 0) {
|
||||
// If we are not full with energy, switch to the get_energy state
|
||||
idler.clear_idle(creep);
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say('Harvesting...');
|
||||
}
|
||||
break;
|
||||
|
||||
case "charge_structure":
|
||||
var targets = get_targets(creep);
|
||||
if(targets.length > 0) {
|
||||
if(creep.transfer(targets[0], RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(targets[0], {visualizePathStyle: {stroke: '#449900'}});
|
||||
}
|
||||
} else {
|
||||
// Else, go idle
|
||||
creep.memory.state = "idle";
|
||||
creep.say('Idling...');
|
||||
}
|
||||
if (creep.store.getUsedCapacity() == 0) {
|
||||
// If we are not full with energy, switch to the get_energy state
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say('Harvesting...');
|
||||
}
|
||||
break;
|
||||
|
||||
case "get_energy":
|
||||
harvester.do_collect(creep, "charge_structure", "Charging...");
|
||||
break;
|
||||
|
||||
default:
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say('Harvesting...');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = roleHarvester;
|
204
role.harvester.v2.js
Normal file
204
role.harvester.v2.js
Normal file
|
@ -0,0 +1,204 @@
|
|||
var idler = require('idle.base');
|
||||
|
||||
// Finds a new spot for the harvester to mine
|
||||
var find_spot = function(creep) {
|
||||
var sources = creep.room.find(FIND_SOURCES);
|
||||
var possible_spots = {};
|
||||
var num_spots = {};
|
||||
var open_spots = {}
|
||||
|
||||
for(let source of sources) {
|
||||
for (let x of [-1, 0, 1]) {
|
||||
for (let y of [-1, 0, 1]) {
|
||||
if(!(x == 0 && y == 0)){
|
||||
var pos = new RoomPosition(source.pos.x + x, source.pos.y + y, source.pos.roomName);
|
||||
if(pos.lookFor(LOOK_TERRAIN) == "plain"){
|
||||
if(num_spots[source.id] == undefined) {
|
||||
num_spots[source.id] = 0;
|
||||
}
|
||||
num_spots[source.id] += 1;
|
||||
if(pos.lookFor(LOOK_CREEPS).length == 0) {
|
||||
if(possible_spots[source.id] == undefined) {
|
||||
possible_spots[source.id] = [];
|
||||
}
|
||||
possible_spots[source.id].push([pos.x, pos.y, pos.roomName, source.id]);
|
||||
if(open_spots[source.id] == undefined) {
|
||||
open_spots[source.id] = 0;
|
||||
}
|
||||
open_spots[source.id] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var best_source = null;
|
||||
var best_occupied = null;
|
||||
for (let source of sources) {
|
||||
if (num_spots[source.id] != undefined && open_spots[source.id] != undefined){
|
||||
var occupied = num_spots[source.id] - open_spots[source.id];
|
||||
if ((best_occupied == null || occupied < best_occupied) && possible_spots[source.id] != undefined && possible_spots[source.id].length > 0) {
|
||||
best_occupied = occupied;
|
||||
best_source = source;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (possible_spots[best_source.id].length > 0){
|
||||
return possible_spots[best_source.id][0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Finds the container near the current spot of the creep
|
||||
var find_container = function(creep) {
|
||||
if (creep.memory.spot) {
|
||||
for (let x of [-1, 0, 1]) {
|
||||
for (let y of [-1, 0, 1]) {
|
||||
if(!(x == 0 && y == 0)){
|
||||
var pos = new RoomPosition(creep.memory.spot[0] + x, creep.memory.spot[1] + y, creep.memory.spot[2]);
|
||||
var structs = pos.lookFor(LOOK_STRUCTURES);
|
||||
for(let struct of structs) {
|
||||
if (struct.structureType == STRUCTURE_CONTAINER || struct.structureType == STRUCTURE_STORAGE) {
|
||||
return struct.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var roleHarvester = {
|
||||
|
||||
/**
|
||||
@param {Creep} creep
|
||||
@param {int} behaviourLevel
|
||||
**/
|
||||
run: function(creep, behaviourLevel) {
|
||||
switch (creep.memory.state) {
|
||||
case "idle":
|
||||
idler.do_idle(creep);
|
||||
if(creep.memory.idle_time == undefined){
|
||||
creep.memory.idle_time = 0;
|
||||
}
|
||||
creep.memory.idle_time += 1;
|
||||
|
||||
// If we've been idling for a while, check if there is a spot available
|
||||
if (creep.memory.idle_time > 10) {
|
||||
idler.clear_idle(creep);
|
||||
delete creep.memory.idle_time;
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Looking...");
|
||||
}
|
||||
break;
|
||||
|
||||
case "find_spot":
|
||||
// If we don't have a spot yet, find one
|
||||
if (!creep.memory.spot) {
|
||||
creep.memory.spot = find_spot(creep);
|
||||
creep.memory.container = find_container(creep);
|
||||
}
|
||||
// If no spot was found, go back to idling
|
||||
if (!creep.memory.spot) {
|
||||
creep.memory.state = "idle";
|
||||
creep.say("No spot!");
|
||||
} else {
|
||||
creep.memory.state = "walk_to_spot";
|
||||
creep.say("Walking...");
|
||||
}
|
||||
break;
|
||||
|
||||
case "walk_to_spot":
|
||||
if (creep.memory.spot) {
|
||||
if (creep.pos.x != creep.memory.spot[0] || creep.pos.y != creep.memory.spot[1]) {
|
||||
creep.moveTo(creep.memory.spot[0], creep.memory.spot[1], {visualizePathStyle: {stroke: '#0044aa'}})
|
||||
// Check if our spot is still available
|
||||
if ((new RoomPosition(creep.memory.spot[0], creep.memory.spot[1], creep.memory.spot[2])).lookFor(LOOK_CREEPS).length > 0){
|
||||
creep.memory.spot = null;
|
||||
creep.memory.container = null;
|
||||
creep.memory.state = "idle";
|
||||
creep.say("Occupied:(");
|
||||
}
|
||||
} else {
|
||||
// We arrived! Start mining.
|
||||
creep.memory.state = "mine_energy";
|
||||
creep.say("Mining...");
|
||||
}
|
||||
} else {
|
||||
// We don't have a spot
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Looking...");
|
||||
}
|
||||
break;
|
||||
|
||||
case "mine_energy":
|
||||
if (creep.memory.spot) {
|
||||
var source = Game.getObjectById(creep.memory.spot[3]);
|
||||
if (source) {
|
||||
if(creep.store.getFreeCapacity() > 0) {
|
||||
if(creep.harvest(source) == ERR_NOT_IN_RANGE) {
|
||||
// Source is gone?
|
||||
creep.memory.spot = null;
|
||||
creep.memory.container = null;
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Looking...");
|
||||
}
|
||||
} else {
|
||||
// We are full, dump the energy into the container
|
||||
creep.memory.state = "dump_energy";
|
||||
creep.say("Dumping...");
|
||||
}
|
||||
} else {
|
||||
// No source?
|
||||
creep.memory.spot = null;
|
||||
creep.memory.container = null;
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Looking...");
|
||||
}
|
||||
} else {
|
||||
// We don't have a spot
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Looking...");
|
||||
}
|
||||
break;
|
||||
|
||||
case "dump_energy":
|
||||
if (creep.memory.container) {
|
||||
var container = Game.getObjectById(creep.memory.container);
|
||||
if (container) {
|
||||
if (container.store.getFreeCapacity(RESOURCE_ENERGY) > 0 && creep.store.getUsedCapacity() > 0) {
|
||||
creep.transfer(container, RESOURCE_ENERGY);
|
||||
}
|
||||
} else {
|
||||
// No container?
|
||||
creep.memory.spot = null;
|
||||
creep.memory.container = null;
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Looking...");
|
||||
}
|
||||
if (creep.store.getUsedCapacity() == 0) {
|
||||
// Everything dumped, go back to mining
|
||||
creep.memory.state = "mine_energy";
|
||||
creep.say("Mining...");
|
||||
}
|
||||
} else {
|
||||
// No container?
|
||||
creep.memory.spot = null;
|
||||
creep.memory.container = null;
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Looking...");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say('Looking...');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = roleHarvester;
|
14
role.idle.js
Normal file
14
role.idle.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
var idler = require('idle.base');
|
||||
|
||||
var roleIdle = {
|
||||
|
||||
/**
|
||||
@param {Creep} creep
|
||||
@param {int} behaviourLevel
|
||||
**/
|
||||
run: function(creep, behaviourLevel) {
|
||||
idler.do_idle(creep);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = roleIdle;
|
227
role.pickup.js
Normal file
227
role.pickup.js
Normal file
|
@ -0,0 +1,227 @@
|
|||
var idler = require('idle.base');
|
||||
|
||||
// Finds energy laying around on the map
|
||||
var find_energy = function(creep) {
|
||||
if (!creep.memory.spot) {
|
||||
max_energy = 0;
|
||||
max_energy_obj = null;
|
||||
|
||||
for(let x of creep.room.find(FIND_DROPPED_RESOURCES, {filter: (s) => {return s.resourceType == RESOURCE_ENERGY}})){
|
||||
if(x.amount > max_energy) {
|
||||
if(x.pos.lookFor(LOOK_CREEPS).length == 0){
|
||||
max_energy = x.amount;
|
||||
max_energy_obj = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let x of creep.room.find(FIND_TOMBSTONES, {filter: (t) => {return t.store.getUsedCapacity(RESOURCE_ENERGY) > 0}})) {
|
||||
if(x.store.getUsedCapacity(RESOURCE_ENERGY) > max_energy) {
|
||||
if(x.pos.lookFor(LOOK_CREEPS).length == 0){
|
||||
max_energy = x.store.getUsedCapacity(RESOURCE_ENERGY);
|
||||
max_energy_obj = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(max_energy_obj != null){
|
||||
return [max_energy_obj.pos.x, max_energy_obj.pos.y, max_energy_obj.room.name, max_energy_obj.id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finds the container near the current spot of the creep
|
||||
var find_container = function(creep) {
|
||||
var container = creep.pos.findClosestByRange(FIND_STRUCTURES, {
|
||||
filter: (x) => {
|
||||
return (x.structureType == STRUCTURE_CONTAINER || x.structureType == STRUCTURE_STORAGE) && x.store.getFreeCapacity(RESOURCE_ENERGY) > 0;
|
||||
}
|
||||
});
|
||||
if (container) {
|
||||
return container.id;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var rolePickup = {
|
||||
|
||||
/**
|
||||
@param {Creep} creep
|
||||
@param {int} behaviourLevel
|
||||
**/
|
||||
run: function(creep, behaviourLevel) {
|
||||
switch (creep.memory.state) {
|
||||
case "idle":
|
||||
idler.do_idle(creep);
|
||||
if(creep.memory.idle_time == undefined){
|
||||
creep.memory.idle_time = 0;
|
||||
}
|
||||
creep.memory.idle_time += 1;
|
||||
|
||||
// If we've been idling for a while, check if there is a spot available
|
||||
if (creep.memory.idle_time > 5) {
|
||||
delete creep.memory.idle_time;
|
||||
if(creep.store.getUsedCapacity() > 0){
|
||||
creep.memory.state = "walk_to_container";
|
||||
creep.say("Dropping...");
|
||||
} else {
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Looking...");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "find_spot":
|
||||
// If we don't have a spot yet, find one
|
||||
if (!creep.memory.spot) {
|
||||
creep.memory.spot = find_energy(creep);
|
||||
creep.memory.container = find_container(creep);
|
||||
}
|
||||
// If no spot was found, go back to idling
|
||||
if (!creep.memory.spot) {
|
||||
creep.memory.state = "idle";
|
||||
creep.say("No drop!");
|
||||
} else {
|
||||
creep.memory.state = "walk_to_spot";
|
||||
creep.say("Walking...");
|
||||
}
|
||||
break;
|
||||
|
||||
case "walk_to_spot":
|
||||
if (creep.memory.spot) {
|
||||
if(creep.memory.spot[0] == null || creep.memory.spot[1] == null || creep.memory.spot[2] == null){
|
||||
// We don't have a spot
|
||||
creep.memory.spot = null;
|
||||
creep.memory.container = null;
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Looking...");
|
||||
} else {
|
||||
if (creep.pos.x != creep.memory.spot[0] || creep.pos.y != creep.memory.spot[1]) {
|
||||
creep.moveTo(creep.memory.spot[0], creep.memory.spot[1], {visualizePathStyle: {stroke: '#0044aa'}})
|
||||
// Check if our spot is still available
|
||||
if ((new RoomPosition(creep.memory.spot[0], creep.memory.spot[1], creep.memory.spot[2])).lookFor(LOOK_CREEPS).length > 0){
|
||||
creep.memory.spot = null;
|
||||
creep.memory.container = null;
|
||||
creep.memory.state = "idle";
|
||||
creep.say("Occupied:(");
|
||||
}
|
||||
} else {
|
||||
// We arrived! Start grabbing.
|
||||
creep.memory.state = "grab_energy";
|
||||
creep.say("Grabbing...");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We don't have a spot
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Looking...");
|
||||
}
|
||||
break;
|
||||
|
||||
case "walk_to_container":
|
||||
if (creep.memory.spot) {
|
||||
delete creep.memory.spot;
|
||||
}
|
||||
if (creep.memory.container) {
|
||||
|
||||
var container = Game.getObjectById(creep.memory.container);
|
||||
|
||||
if (creep.pos.x != container.pos.x || creep.pos.y != container.pos.y) {
|
||||
creep.moveTo(container, {visualizePathStyle: {stroke: '#0044aa'}});
|
||||
} else {
|
||||
// We arrived! Start dropping.
|
||||
creep.memory.state = "drop_energy";
|
||||
creep.say("Grabbing...");
|
||||
}
|
||||
} else {
|
||||
// We don't have a container
|
||||
creep.memory.container = find_container(creep);
|
||||
if(!creep.memory.container){
|
||||
creep.memory.state = "idle"
|
||||
creep.say("No container:(");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "grab_energy":
|
||||
if (creep.memory.spot) {
|
||||
|
||||
var target = Game.getObjectById(creep.memory.spot[3]);
|
||||
if(target instanceof Tombstone) {
|
||||
creep.withdraw(target, RESOURCE_ENERGY);
|
||||
} else if (target instanceof Resource) {
|
||||
creep.pickup(target);
|
||||
} else {
|
||||
creep.say("Unkn.Tgt.");
|
||||
}
|
||||
|
||||
// If we have more space, look for a new spot
|
||||
if(creep.store.getFreeCapacity > 0) {
|
||||
creep.memory.spot = null;
|
||||
creep.memory.container = null;
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Looking...");
|
||||
// Else, go to drop off
|
||||
} else {
|
||||
// We are full, dump the energy into the container
|
||||
creep.memory.state = "drop_energy";
|
||||
creep.say("Dumping...");
|
||||
}
|
||||
} else {
|
||||
// We don't have a spot
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Looking...");
|
||||
}
|
||||
break;
|
||||
|
||||
case "drop_energy":
|
||||
if (creep.memory.container) {
|
||||
var container = Game.getObjectById(creep.memory.container);
|
||||
if (container) {
|
||||
if (container.store.getFreeCapacity(RESOURCE_ENERGY) > 0 && creep.store.getUsedCapacity() > 0) {
|
||||
if(creep.transfer(container, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(container);
|
||||
}
|
||||
} else if (container.store.getFreeCapacity(RESOURCE_ENERGY) == 0) {
|
||||
// Find new container
|
||||
creep.memory.container = find_container(creep);
|
||||
if(!creep.memory.container){
|
||||
creep.memory.state = "idle"
|
||||
creep.say("No container:(");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No container?
|
||||
creep.memory.container = find_container(creep);
|
||||
if(!creep.memory.container){
|
||||
creep.memory.state = "idle"
|
||||
creep.say("No container:(");
|
||||
}
|
||||
}
|
||||
if (creep.store.getUsedCapacity() == 0) {
|
||||
// Everything dumped, search for new energy
|
||||
creep.memory.spot = null;
|
||||
creep.memory.container = null;
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Grabbing...");
|
||||
}
|
||||
} else {
|
||||
// No container?
|
||||
creep.memory.spot = null;
|
||||
creep.memory.container = null;
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say("Looking...");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
creep.memory.spot = null;
|
||||
creep.memory.container = null;
|
||||
creep.memory.state = "find_spot";
|
||||
creep.say('Looking...');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = rolePickup;
|
78
role.refiller.js
Normal file
78
role.refiller.js
Normal file
|
@ -0,0 +1,78 @@
|
|||
var idler = require('idle.base');
|
||||
var collector = require('energy.storage');
|
||||
|
||||
// Finds the buildings that need energy
|
||||
var find_targets = function(creep) {
|
||||
var ref = creep.pos.findClosestByRange(FIND_STRUCTURES, {
|
||||
filter: (structure) => {
|
||||
return (structure.structureType == STRUCTURE_EXTENSION ||
|
||||
structure.structureType == STRUCTURE_SPAWN ||
|
||||
structure.structureType == STRUCTURE_TOWER) &&
|
||||
structure.store.getFreeCapacity(RESOURCE_ENERGY) > 0;
|
||||
}
|
||||
});
|
||||
|
||||
if (!ref) {
|
||||
ref = creep.pos.findClosestByRange(FIND_STRUCTURES, {
|
||||
filter: (s) => {
|
||||
return (s.structureType == STRUCTURE_STORAGE && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0);
|
||||
}
|
||||
})
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
var roleRefiller = {
|
||||
|
||||
/**
|
||||
@param {Creep} creep
|
||||
@param {int} behaviourLevel
|
||||
**/
|
||||
run: function(creep, behaviourLevel) {
|
||||
switch (creep.memory.state) {
|
||||
case "idle":
|
||||
idler.do_idle(creep);
|
||||
if (find_targets(creep)){
|
||||
// If there are any buildings to charge, switch back to the charge state
|
||||
idler.clear_idle(creep);
|
||||
creep.memory.state = "charge_structure";
|
||||
creep.say("Charging...");
|
||||
}
|
||||
if (creep.store.getFreeCapacity() > 0) {
|
||||
// If we are not full with energy, switch to the get_energy state
|
||||
idler.clear_idle(creep);
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say('Reloading...');
|
||||
}
|
||||
break;
|
||||
|
||||
case "charge_structure":
|
||||
var target = find_targets(creep);
|
||||
if(target) {
|
||||
if(creep.transfer(target, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(target, {visualizePathStyle: {stroke: '#449900'}});
|
||||
}
|
||||
} else {
|
||||
// Else, go idle
|
||||
creep.memory.state = "idle";
|
||||
creep.say('Idling...');
|
||||
}
|
||||
if (creep.store.getUsedCapacity() == 0) {
|
||||
// If we are not full with energy, switch to the get_energy state
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say('Reloading...');
|
||||
}
|
||||
break;
|
||||
|
||||
case "get_energy":
|
||||
collector.do_collect(creep, "charge_structure", "Charging...");
|
||||
break;
|
||||
|
||||
default:
|
||||
creep.memory.state = "idle";
|
||||
creep.say('Idling...');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = roleRefiller;
|
143
role.repairer.js
Normal file
143
role.repairer.js
Normal file
|
@ -0,0 +1,143 @@
|
|||
var idler = require('idle.base');
|
||||
var wallRepairer = require('role.wallrepairer');
|
||||
var harvester = require('energy.harvest');
|
||||
var collector = require('energy.storage');
|
||||
|
||||
var get_target = function(creep) {
|
||||
var result;
|
||||
var repairTarget;
|
||||
|
||||
result = creep.pos.findClosestByRange(FIND_MY_STRUCTURES, {
|
||||
filter: (structure) => structure.hits < structure.hitsMax && structure.hits < 10000 && !Memory.rooms[creep.room.name].repairs.includes(structure.id)
|
||||
});
|
||||
if(result){
|
||||
repairTarget = Math.min(11000, result.hitsMax);
|
||||
}
|
||||
|
||||
if(!result) {
|
||||
result = creep.pos.findClosestByRange(FIND_STRUCTURES, {
|
||||
filter: (structure) => structure.hits < structure.hitsMax && (structure.structureType == STRUCTURE_CONTAINER || structure.structureType == STRUCTURE_STORAGE) && structure.hits < 10000 && !Memory.rooms[creep.room.name].repairs.includes(structure.id)
|
||||
});
|
||||
if(result){
|
||||
repairTarget = Math.min(11000, result.hitsMax);
|
||||
}
|
||||
}
|
||||
|
||||
if(!result) {
|
||||
result = creep.pos.findClosestByRange(FIND_STRUCTURES, {
|
||||
filter: (structure) => structure.hits < structure.hitsMax && structure.structureType != STRUCTURE_WALL && structure.hits < 10000 && !Memory.rooms[creep.room.name].repairs.includes(structure.id)
|
||||
});
|
||||
if(result){
|
||||
repairTarget = Math.min(11000, result.hitsMax);
|
||||
}
|
||||
}
|
||||
|
||||
if(!result) {
|
||||
result = creep.pos.findClosestByRange(FIND_STRUCTURES, {
|
||||
filter: (structure) => structure.hits < structure.hitsMax && (structure.structureType == STRUCTURE_CONTAINER || structure.structureType == STRUCTURE_STORAGE) && !Memory.rooms[creep.room.name].repairs.includes(structure.id)
|
||||
});
|
||||
if(result){
|
||||
repairTarget = result.hitsMax;
|
||||
}
|
||||
}
|
||||
|
||||
if(!result) {
|
||||
result = creep.pos.findClosestByRange(FIND_STRUCTURES, {
|
||||
filter: (structure) => structure.hits < structure.hitsMax && structure.structureType != STRUCTURE_WALL && !Memory.rooms[creep.room.name].repairs.includes(structure.id)
|
||||
});
|
||||
if(result){
|
||||
repairTarget = result.hitsMax;
|
||||
}
|
||||
}
|
||||
|
||||
// If no result can be found, go repair a wall or something
|
||||
if(!result){
|
||||
result = wallRepairer.get_target(creep);
|
||||
repairTarget = -1;
|
||||
}
|
||||
|
||||
if(result){
|
||||
creep.memory.repairTarget = repairTarget;
|
||||
creep.memory.repairId = result.id
|
||||
Memory.rooms[creep.room.name].repairs.push(result.id);
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
var roleRepairer = {
|
||||
|
||||
/**
|
||||
@param {Creep} creep
|
||||
@param {int} behaviourLevel
|
||||
**/
|
||||
run: function(creep, behaviourLevel) {
|
||||
switch (creep.memory.state) {
|
||||
case "idle":
|
||||
idler.do_idle(creep);
|
||||
if (get_target(creep)){
|
||||
// If there are any buildings to repair, switch back to the repair state
|
||||
idler.clear_idle(creep);
|
||||
creep.memory.state = "repair_structure";
|
||||
creep.say("repairing");
|
||||
}
|
||||
if (creep.store.getFreeCapacity() > 0) {
|
||||
// If we are not full with energy, switch to the get_energy state
|
||||
idler.clear_idle(creep);
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say('Reloading...');
|
||||
}
|
||||
break;
|
||||
|
||||
case "repair_structure":
|
||||
if(creep.memory.repairId){
|
||||
var struct = Game.getObjectById(creep.memory.repairId);
|
||||
if (struct.hits >= creep.memory.repairTarget) {
|
||||
_.remove(Memory.rooms[creep.room.name].repairs, (n) => n == creep.memory.repairId);
|
||||
delete creep.memory.repairId;
|
||||
delete creep.memory.repairTarget;
|
||||
}
|
||||
}
|
||||
|
||||
if (!creep.memory.repairId) {
|
||||
creep.memory.repairId = get_target(creep).id;
|
||||
}
|
||||
var closestDamagedStructure = Game.getObjectById(creep.memory.repairId);
|
||||
if(closestDamagedStructure) {
|
||||
if (creep.repair(closestDamagedStructure) == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(closestDamagedStructure, {visualizePathStyle: {stroke: '#FF9999'}});
|
||||
}
|
||||
} else {
|
||||
// Else, go idle
|
||||
creep.memory.state = "idle";
|
||||
creep.say('idling');
|
||||
}
|
||||
if (creep.store.getUsedCapacity() == 0) {
|
||||
// If we are out of energy, get more!
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say('Reloading...');
|
||||
// Forget what we were doing, so we can pick the best repair option when we are done recharging
|
||||
_.remove(Memory.rooms[creep.room.name].repairs, (n) => n == creep.memory.repairId);
|
||||
delete creep.memory.repairId;
|
||||
delete creep.memory.repairTarget;
|
||||
}
|
||||
break;
|
||||
|
||||
case "get_energy":
|
||||
var energy_source;
|
||||
if(behaviourLevel >= 2) {
|
||||
energy_source = collector;
|
||||
} else {
|
||||
energy_source = harvester;
|
||||
}
|
||||
energy_source.do_collect(creep, "repair_structure", "Repairing...");
|
||||
break;
|
||||
|
||||
default:
|
||||
creep.memory.state = "repair_structure";
|
||||
creep.say('repairing');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = roleRepairer;
|
63
role.upgrader.js
Normal file
63
role.upgrader.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
var idler = require('idle.base');
|
||||
var harvester = require('energy.harvest');
|
||||
var collector = require('energy.storage');
|
||||
|
||||
var roleUpgrader = {
|
||||
|
||||
/**
|
||||
@param {Creep} creep
|
||||
@param {int} behaviourLevel
|
||||
**/
|
||||
run: function(creep, behaviourLevel) {
|
||||
switch (creep.memory.state) {
|
||||
case "idle":
|
||||
idler.do_idle(creep);
|
||||
if (creep.room.controller.progress < creep.room.controller.progressTotal){
|
||||
// If there are any buildings to upgrade, switch back to the upgrading state
|
||||
idler.clear_idle(creep);
|
||||
creep.memory.state = "upgrade_structure";
|
||||
creep.say("upgrading");
|
||||
}
|
||||
if (creep.store.getFreeCapacity() > 0) {
|
||||
// If we are not full with energy, switch to the get_energy state
|
||||
idler.clear_idle(creep);
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say('Reloading...');
|
||||
}
|
||||
break;
|
||||
|
||||
case "upgrade_structure":
|
||||
if (creep.room.controller.progress < creep.room.controller.progressTotal){
|
||||
if(creep.upgradeController(creep.room.controller) == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(creep.room.controller, {visualizePathStyle: {stroke: '#ffffff'}});
|
||||
}
|
||||
} else {
|
||||
// Else, go idle
|
||||
creep.memory.state = "idle";
|
||||
creep.say('idling');
|
||||
}
|
||||
if (creep.store.getUsedCapacity() == 0) {
|
||||
// If we have no energy, switch to the get_energy state
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say('Reloading...');
|
||||
}
|
||||
break;
|
||||
|
||||
case "get_energy":
|
||||
var energy_source;
|
||||
if(behaviourLevel >= 2) {
|
||||
energy_source = collector;
|
||||
} else {
|
||||
energy_source = harvester;
|
||||
}
|
||||
energy_source.do_collect(creep, "upgrade_structure", "Upgrading...");
|
||||
break;
|
||||
|
||||
default:
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say("Reloading...");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = roleUpgrader;
|
80
role.wallrepairer.js
Normal file
80
role.wallrepairer.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
var idler = require('idle.base');
|
||||
var harvester = require('energy.harvest');
|
||||
var collector = require('energy.storage');
|
||||
|
||||
var get_target = function(creep) {
|
||||
var walls = creep.room.find(FIND_STRUCTURES, {
|
||||
filter: (s) => s.structureType == STRUCTURE_WALL && s.hits < s.hitsMax
|
||||
});
|
||||
for(var i = 0.0001; i < 1; i += 0.0001) {
|
||||
for(var wall of walls) {
|
||||
if ((wall.hits / wall.hitsMax) < i) {
|
||||
return wall;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var roleRepairer = {
|
||||
|
||||
get_target: get_target,
|
||||
|
||||
/**
|
||||
@param {Creep} creep
|
||||
@param {int} behaviourLevel
|
||||
**/
|
||||
run: function(creep, behaviourLevel) {
|
||||
switch (creep.memory.state) {
|
||||
case "idle":
|
||||
idler.do_idle(creep);
|
||||
if (get_target(creep)){
|
||||
// If there are any buildings to repair, switch back to the repair state
|
||||
idler.clear_idle(creep);
|
||||
creep.memory.state = "repair_structure";
|
||||
creep.say("Repairing...");
|
||||
}
|
||||
if (creep.store.getFreeCapacity() > 0) {
|
||||
// If we are not full with energy, switch to the get_energy state
|
||||
idler.clear_idle(creep);
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say('Reloading...');
|
||||
}
|
||||
break;
|
||||
|
||||
case "repair_structure":
|
||||
var closestDamagedStructure = get_target(creep);
|
||||
if(closestDamagedStructure) {
|
||||
if (creep.repair(closestDamagedStructure) == ERR_NOT_IN_RANGE) {
|
||||
creep.moveTo(closestDamagedStructure, {visualizePathStyle: {stroke: '#FF9999'}});
|
||||
}
|
||||
} else {
|
||||
// Else, go idle
|
||||
creep.memory.state = "idle";
|
||||
creep.say('Idling...');
|
||||
}
|
||||
if (creep.store.getUsedCapacity() == 0) {
|
||||
// If we are out of energy, get more!
|
||||
creep.memory.state = "get_energy";
|
||||
creep.say('Reloading...');
|
||||
}
|
||||
break;
|
||||
|
||||
case "get_energy":
|
||||
var energy_source;
|
||||
if(behaviourLevel >= 2) {
|
||||
energy_source = collector;
|
||||
} else {
|
||||
energy_source = harvester;
|
||||
}
|
||||
energy_source.do_collect(creep, "repair_structure", "Repairing...");
|
||||
break;
|
||||
|
||||
default:
|
||||
creep.memory.state = "repair_structure";
|
||||
creep.say('Repairing...');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = roleRepairer;
|
324
screeps-profiler.js
Normal file
324
screeps-profiler.js
Normal file
|
@ -0,0 +1,324 @@
|
|||
let usedOnStart = 0;
|
||||
let enabled = false;
|
||||
let depth = 0;
|
||||
|
||||
function setupProfiler() {
|
||||
depth = 0; // reset depth, this needs to be done each tick.
|
||||
Game.profiler = {
|
||||
stream(duration, filter) {
|
||||
setupMemory('stream', duration || 10, filter);
|
||||
},
|
||||
email(duration, filter) {
|
||||
setupMemory('email', duration || 100, filter);
|
||||
},
|
||||
profile(duration, filter) {
|
||||
setupMemory('profile', duration || 100, filter);
|
||||
},
|
||||
background(filter) {
|
||||
setupMemory('background', false, filter);
|
||||
},
|
||||
restart() {
|
||||
if (Profiler.isProfiling()) {
|
||||
const filter = Memory.profiler.filter;
|
||||
let duration = false;
|
||||
if (!!Memory.profiler.disableTick) {
|
||||
// Calculate the original duration, profile is enabled on the tick after the first call,
|
||||
// so add 1.
|
||||
duration = Memory.profiler.disableTick - Memory.profiler.enabledTick + 1;
|
||||
}
|
||||
const type = Memory.profiler.type;
|
||||
setupMemory(type, duration, filter);
|
||||
}
|
||||
},
|
||||
reset: resetMemory,
|
||||
output: Profiler.output,
|
||||
};
|
||||
|
||||
overloadCPUCalc();
|
||||
}
|
||||
|
||||
function setupMemory(profileType, duration, filter) {
|
||||
resetMemory();
|
||||
const disableTick = Number.isInteger(duration) ? Game.time + duration : false;
|
||||
if (!Memory.profiler) {
|
||||
Memory.profiler = {
|
||||
map: {},
|
||||
totalTime: 0,
|
||||
enabledTick: Game.time + 1,
|
||||
disableTick,
|
||||
type: profileType,
|
||||
filter,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function resetMemory() {
|
||||
Memory.profiler = null;
|
||||
}
|
||||
|
||||
function overloadCPUCalc() {
|
||||
if (Game.rooms.sim) {
|
||||
usedOnStart = 0; // This needs to be reset, but only in the sim.
|
||||
Game.cpu.getUsed = function getUsed() {
|
||||
return performance.now() - usedOnStart;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function getFilter() {
|
||||
return Memory.profiler.filter;
|
||||
}
|
||||
|
||||
const functionBlackList = [
|
||||
'getUsed', // Let's avoid wrapping this... may lead to recursion issues and should be inexpensive.
|
||||
'constructor', // es6 class constructors need to be called with `new`
|
||||
];
|
||||
|
||||
function wrapFunction(name, originalFunction) {
|
||||
function wrappedFunction() {
|
||||
if (Profiler.isProfiling()) {
|
||||
const nameMatchesFilter = name === getFilter();
|
||||
const start = Game.cpu.getUsed();
|
||||
if (nameMatchesFilter) {
|
||||
depth++;
|
||||
}
|
||||
const result = originalFunction.apply(this, arguments);
|
||||
if (depth > 0 || !getFilter()) {
|
||||
const end = Game.cpu.getUsed();
|
||||
Profiler.record(name, end - start);
|
||||
}
|
||||
if (nameMatchesFilter) {
|
||||
depth--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return originalFunction.apply(this, arguments);
|
||||
}
|
||||
|
||||
wrappedFunction.toString = () =>
|
||||
`// screeps-profiler wrapped function:\n${originalFunction.toString()}`;
|
||||
|
||||
return wrappedFunction;
|
||||
}
|
||||
|
||||
function hookUpPrototypes() {
|
||||
Profiler.prototypes.forEach(proto => {
|
||||
profileObjectFunctions(proto.val, proto.name);
|
||||
});
|
||||
}
|
||||
|
||||
function profileObjectFunctions(object, label) {
|
||||
const objectToWrap = object.prototype ? object.prototype : object;
|
||||
|
||||
Object.getOwnPropertyNames(objectToWrap).forEach(functionName => {
|
||||
const extendedLabel = `${label}.${functionName}`;
|
||||
|
||||
const isBlackListed = functionBlackList.indexOf(functionName) !== -1;
|
||||
if (isBlackListed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const descriptor = Object.getOwnPropertyDescriptor(objectToWrap, functionName);
|
||||
if (!descriptor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hasAccessor = descriptor.get || descriptor.set;
|
||||
if (hasAccessor) {
|
||||
const configurable = descriptor.configurable;
|
||||
if (!configurable) {
|
||||
return;
|
||||
}
|
||||
|
||||
const profileDescriptor = {};
|
||||
|
||||
if (descriptor.get) {
|
||||
const extendedLabelGet = `${extendedLabel}:get`;
|
||||
profileDescriptor.get = profileFunction(descriptor.get, extendedLabelGet);
|
||||
}
|
||||
|
||||
if (descriptor.set) {
|
||||
const extendedLabelSet = `${extendedLabel}:set`;
|
||||
profileDescriptor.set = profileFunction(descriptor.set, extendedLabelSet);
|
||||
}
|
||||
|
||||
Object.defineProperty(objectToWrap, functionName, profileDescriptor);
|
||||
return;
|
||||
}
|
||||
|
||||
const isFunction = typeof descriptor.value === 'function';
|
||||
if (!isFunction) {
|
||||
return;
|
||||
}
|
||||
const originalFunction = objectToWrap[functionName];
|
||||
objectToWrap[functionName] = profileFunction(originalFunction, extendedLabel);
|
||||
});
|
||||
|
||||
return objectToWrap;
|
||||
}
|
||||
|
||||
function profileFunction(fn, functionName) {
|
||||
const fnName = functionName || fn.name;
|
||||
if (!fnName) {
|
||||
console.log('Couldn\'t find a function name for - ', fn);
|
||||
console.log('Will not profile this function.');
|
||||
return fn;
|
||||
}
|
||||
|
||||
return wrapFunction(fnName, fn);
|
||||
}
|
||||
|
||||
const Profiler = {
|
||||
printProfile() {
|
||||
console.log(Profiler.output());
|
||||
},
|
||||
|
||||
emailProfile() {
|
||||
Game.notify(Profiler.output());
|
||||
},
|
||||
|
||||
output(numresults) {
|
||||
const displayresults = !!numresults ? numresults : 20;
|
||||
if (!Memory.profiler || !Memory.profiler.enabledTick) {
|
||||
return 'Profiler not active.';
|
||||
}
|
||||
|
||||
const endTick = Math.min(Memory.profiler.disableTick || Game.time, Game.time);
|
||||
const startTick = Memory.profiler.enabledTick + 1;
|
||||
const elapsedTicks = endTick - startTick;
|
||||
const header = 'calls\t\ttime\t\tavg\t\tfunction';
|
||||
const footer = [
|
||||
`Avg: ${(Memory.profiler.totalTime / elapsedTicks).toFixed(2)}`,
|
||||
`Total: ${Memory.profiler.totalTime.toFixed(2)}`,
|
||||
`Ticks: ${elapsedTicks}`,
|
||||
].join('\t');
|
||||
return [].concat(header, Profiler.lines().slice(0, displayresults), footer).join('\n');
|
||||
},
|
||||
|
||||
lines() {
|
||||
const stats = Object.keys(Memory.profiler.map).map(functionName => {
|
||||
const functionCalls = Memory.profiler.map[functionName];
|
||||
return {
|
||||
name: functionName,
|
||||
calls: functionCalls.calls,
|
||||
totalTime: functionCalls.time,
|
||||
averageTime: functionCalls.time / functionCalls.calls,
|
||||
};
|
||||
}).sort((val1, val2) => {
|
||||
return val2.totalTime - val1.totalTime;
|
||||
});
|
||||
|
||||
const lines = stats.map(data => {
|
||||
return [
|
||||
data.calls,
|
||||
data.totalTime.toFixed(1),
|
||||
data.averageTime.toFixed(3),
|
||||
data.name,
|
||||
].join('\t\t');
|
||||
});
|
||||
|
||||
return lines;
|
||||
},
|
||||
|
||||
prototypes: [
|
||||
{ name: 'Game', val: Game },
|
||||
{ name: 'Room', val: Room },
|
||||
{ name: 'Structure', val: Structure },
|
||||
{ name: 'Spawn', val: Spawn },
|
||||
{ name: 'Creep', val: Creep },
|
||||
{ name: 'RoomPosition', val: RoomPosition },
|
||||
{ name: 'Source', val: Source },
|
||||
{ name: 'Flag', val: Flag },
|
||||
],
|
||||
|
||||
record(functionName, time) {
|
||||
if (!Memory.profiler.map[functionName]) {
|
||||
Memory.profiler.map[functionName] = {
|
||||
time: 0,
|
||||
calls: 0,
|
||||
};
|
||||
}
|
||||
Memory.profiler.map[functionName].calls++;
|
||||
Memory.profiler.map[functionName].time += time;
|
||||
},
|
||||
|
||||
endTick() {
|
||||
if (Game.time >= Memory.profiler.enabledTick) {
|
||||
const cpuUsed = Game.cpu.getUsed();
|
||||
Memory.profiler.totalTime += cpuUsed;
|
||||
Profiler.report();
|
||||
}
|
||||
},
|
||||
|
||||
report() {
|
||||
if (Profiler.shouldPrint()) {
|
||||
Profiler.printProfile();
|
||||
} else if (Profiler.shouldEmail()) {
|
||||
Profiler.emailProfile();
|
||||
}
|
||||
},
|
||||
|
||||
isProfiling() {
|
||||
if (!enabled || !Memory.profiler) {
|
||||
return false;
|
||||
}
|
||||
return !Memory.profiler.disableTick || Game.time <= Memory.profiler.disableTick;
|
||||
},
|
||||
|
||||
type() {
|
||||
return Memory.profiler.type;
|
||||
},
|
||||
|
||||
shouldPrint() {
|
||||
const streaming = Profiler.type() === 'stream';
|
||||
const profiling = Profiler.type() === 'profile';
|
||||
const onEndingTick = Memory.profiler.disableTick === Game.time;
|
||||
return streaming || (profiling && onEndingTick);
|
||||
},
|
||||
|
||||
shouldEmail() {
|
||||
return Profiler.type() === 'email' && Memory.profiler.disableTick === Game.time;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
wrap(callback) {
|
||||
if (enabled) {
|
||||
setupProfiler();
|
||||
}
|
||||
|
||||
if (Profiler.isProfiling()) {
|
||||
usedOnStart = Game.cpu.getUsed();
|
||||
|
||||
// Commented lines are part of an on going experiment to keep the profiler
|
||||
// performant, and measure certain types of overhead.
|
||||
|
||||
// var callbackStart = Game.cpu.getUsed();
|
||||
const returnVal = callback();
|
||||
// var callbackEnd = Game.cpu.getUsed();
|
||||
Profiler.endTick();
|
||||
// var end = Game.cpu.getUsed();
|
||||
|
||||
// var profilerTime = (end - start) - (callbackEnd - callbackStart);
|
||||
// var callbackTime = callbackEnd - callbackStart;
|
||||
// var unaccounted = end - profilerTime - callbackTime;
|
||||
// console.log('total-', end, 'profiler-', profilerTime, 'callbacktime-',
|
||||
// callbackTime, 'start-', start, 'unaccounted', unaccounted);
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
return callback();
|
||||
},
|
||||
|
||||
enable() {
|
||||
enabled = true;
|
||||
hookUpPrototypes();
|
||||
},
|
||||
|
||||
output: Profiler.output,
|
||||
|
||||
registerObject: profileObjectFunctions,
|
||||
registerFN: profileFunction,
|
||||
registerClass: profileObjectFunctions,
|
||||
};
|
Loading…
Reference in a new issue