screeps-online/main.js
2019-11-29 15:19:38 +01:00

266 lines
12 KiB
JavaScript

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);
}
}
});
}