From 493a1e0bad37685654c3de464ffbc7f3cb3351cb Mon Sep 17 00:00:00 2001 From: Arne Schauf Date: Fri, 26 Jan 2024 09:47:02 +0100 Subject: [PATCH] remoting --- default/globals.js | 85 ++++++++++--------- default/main.js | 145 ++++++++++++++++++-------------- default/role.attacker.js | 85 +++++++++++++++++++ default/role.builder.js | 29 +++++-- default/role.filler.js | 58 +++++++++++++ default/role.harvester.js | 13 ++- default/role.hauler.js | 101 ++++++++++++++++++++++ default/role.healer.js | 88 +++++++++++++++++++ default/role.rangedAttacker.js | 90 ++++++++++++++++++++ default/role.remoteHarvester.js | 54 ++++++++++++ default/role.reserver.js | 31 +++++++ default/role.scout.js | 29 ++++++- default/role.transporter.js | 14 ++- default/role.upgrader.js | 7 ++ default/spawn.js | 141 ++++++++++++++++++++++--------- 15 files changed, 812 insertions(+), 158 deletions(-) create mode 100644 default/role.attacker.js create mode 100644 default/role.filler.js create mode 100644 default/role.hauler.js create mode 100644 default/role.healer.js create mode 100644 default/role.rangedAttacker.js create mode 100644 default/role.remoteHarvester.js create mode 100644 default/role.reserver.js diff --git a/default/globals.js b/default/globals.js index 21fa464..94ef0f1 100644 --- a/default/globals.js +++ b/default/globals.js @@ -1,47 +1,50 @@ const roleHarvester = require('./role.harvester') +const roleRemoteHarvester = require('./role.remoteHarvester') const roleTransporter = require('./role.transporter') const roleBuilder = require('./role.builder') const roleUpgrader = require('./role.upgrader') +const roleScout = require('./role.scout') +const roleAttacker = require('./role.attacker') +const roleRangedAttacker = require('./role.rangedAttacker') +const roleHauler = require('./role.hauler') +const roleHealer = require('./role.healer') +const roleFiller = require('./role.filler') +const roleReserver = require('./role.reserver') -global.ROLES = { - harvester: { - prio: 3, - count: 3, - module: roleHarvester, - bodies: [ - [WORK, WORK, CARRY, MOVE], - [WORK, WORK, WORK, WORK, WORK, WORK, CARRY, MOVE], - [WORK, WORK, WORK, WORK, WORK, WORK, CARRY, MOVE, MOVE], - [WORK, WORK, WORK, WORK, WORK, WORK, CARRY, MOVE, MOVE, MOVE], - [WORK, WORK, WORK, WORK, WORK, WORK, CARRY, CARRY, MOVE, MOVE, MOVE], - [WORK, WORK, WORK, WORK, WORK, WORK, CARRY, CARRY, MOVE, MOVE, MOVE, MOVE], - ] - }, - transporter: { - prio: 4, - count: 2, - module: roleTransporter, - bodies: [ - [CARRY, CARRY, MOVE], - [CARRY, CARRY, MOVE, CARRY, CARRY, MOVE], - [CARRY, CARRY, MOVE, CARRY, CARRY, MOVE, CARRY, CARRY, MOVE], - [CARRY, CARRY, MOVE, CARRY, CARRY, MOVE, CARRY, CARRY, MOVE, CARRY, CARRY, MOVE], - ] - }, - builder: { - prio: 5, - count: 2, - maxExpands: 4, - module: roleBuilder, - baseBody: [WORK, CARRY, MOVE, MOVE], - expandBody: [WORK, CARRY, MOVE, MOVE], - }, - upgrader: { - prio: 6, - count: 2, - maxExpands: 4, - module: roleUpgrader, - baseBody: [WORK, CARRY, MOVE], - expandBody: [WORK, WORK, MOVE], - }, +global.roleModules = [ + roleHarvester, + roleRemoteHarvester, + roleBuilder, + roleTransporter, + roleUpgrader, + roleScout, + roleRangedAttacker, + roleHauler, + roleAttacker, + roleHealer, + roleFiller, + roleReserver, +] + +global.ROLES = {} +for (let mod of roleModules) { + ROLES[mod.name] = mod +} + +global.creepIsAttacker = creep => creep.getActiveBodyparts(ATTACK) + creep.getActiveBodyparts(RANGED_ATTACK) > 0 +global.activeRemotes = ['E8S4', 'E8S5', 'E9S5', 'E8S3'] + +global.ALREADY_IN_ROOM = 'alreadyInRoom' +global.MOVING = 'moving' + +global.moveToRoom = function (creep, targetRoom) { + if (creep.pos.roomName === targetRoom) { + return ALREADY_IN_ROOM + } + + const exitDir = Game.map.findExit(creep.room, targetRoom); + const exit = creep.pos.findClosestByRange(exitDir); + creep.moveTo(exit); + creep.say(targetRoom) + return MOVING } diff --git a/default/main.js b/default/main.js index c5daf81..2a3fb40 100644 --- a/default/main.js +++ b/default/main.js @@ -1,7 +1,3 @@ -const roleHarvester = require('role.harvester') -const roleBuilder = require('role.builder') -const roleTransporter = require('role.transporter') -const roleUpgrader = require('role.upgrader') const libLink = require('link') const libSpawn = require('spawn') @@ -24,81 +20,108 @@ module.exports.loop = function () { libLink.tickInit() libSpawn.tickInit() - for (let room of Object.values(Game.rooms)) { - // tickInit - for (let role of Object.values(ROLES)) { - role.idling = 0 - if (role.module.tickInit) { - role.module.tickInit(room) - } + // tickInit + for (let role of roleModules) { + role.idling = 0 + if (role.tickInit) { + role.tickInit() } + } - for (let role of Object.values(ROLES)) { - if (role.module.cleanup) { - role.module.cleanup() - } + for (let role of roleModules) { + if (role.cleanup) { + role.cleanup() } + } - for (let [id, creep] of Object.entries(Memory.refillers)) { - let target = Game.getObjectById(id) - if (!target || target.store.getFreeCapacity(RESOURCE_ENERGY) === 0 || !Game.creeps[creep]) { - delete Memory.refillers[id] - } + for (let [id, creep] of Object.entries(Memory.refillers)) { + let target = Game.getObjectById(id) + if (!target || target.store.getFreeCapacity(RESOURCE_ENERGY) === 0 || !Game.creeps[creep]) { + delete Memory.refillers[id] } + } - let spawn = Game.spawns['Spawn1'] + let spawn = Game.spawns['Spawn1'] - // Run modules - for (let link of spawn.room.find(FIND_STRUCTURES, {filter: s => s.structureType === STRUCTURE_LINK})) { - libLink.tick(link) - } - for (let creep of Object.values(Game.creeps)) { - if (creep.store.getFreeCapacity(RESOURCE_ENERGY) > 0) { - for (let target of creep.pos.findInRange(FIND_TOMBSTONES, 1, {filter: t => t.store[RESOURCE_ENERGY] > 0})) { - creep.withdraw(target, RESOURCE_ENERGY) - } - for (let target of creep.pos.findInRange(FIND_RUINS, 1, {filter: t => t.store[RESOURCE_ENERGY] > 0})) { - creep.withdraw(target, RESOURCE_ENERGY) - } - } - if (!creep.memory.role) { - creep.memory.role = 'harvester' + // Run modules + for (let link of spawn.room.find(FIND_STRUCTURES, {filter: s => s.structureType === STRUCTURE_LINK})) { + libLink.tick(link) + } + for (let creep of Object.values(Game.creeps)) { + if (creep.store.getFreeCapacity(RESOURCE_ENERGY) > 0) { + for (let target of creep.pos.findInRange(FIND_TOMBSTONES, 1, {filter: t => t.store[RESOURCE_ENERGY] > 0})) { + creep.withdraw(target, RESOURCE_ENERGY) } - if (ROLES[creep.memory.role].module.tick(creep) === 'idle') { - ROLES[creep.memory.role].idling++ + for (let target of creep.pos.findInRange(FIND_RUINS, 1, {filter: t => t.store[RESOURCE_ENERGY] > 0})) { + creep.withdraw(target, RESOURCE_ENERGY) } } + if (!creep.memory.role) { + creep.memory.role = 'harvester' + } + if (ROLES[creep.memory.role].tick(creep) === 'idle') { + ROLES[creep.memory.role].idling++ + } + } - libSpawn.tick(spawn) + libSpawn.tick(spawn) - let towers = spawn.room.find(FIND_STRUCTURES, {filter: structure => structure.structureType === STRUCTURE_TOWER}) - for (let tower of towers) { - // var closestDamagedStructure = tower.pos.findClosestByRange(FIND_STRUCTURES, { - // filter: (structure) => structure.hits < structure.hitsMax - // }); - // if(closestDamagedStructure) { - // tower.repair(closestDamagedStructure); - // } + let towers = spawn.room.find(FIND_STRUCTURES, {filter: structure => structure.structureType === STRUCTURE_TOWER}) + for (let tower of towers) { + // var closestDamagedStructure = tower.pos.findClosestByRange(FIND_STRUCTURES, { + // filter: (structure) => structure.hits < structure.hitsMax + // }); + // if(closestDamagedStructure) { + // tower.repair(closestDamagedStructure); + // } - let closestHostile = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS); - if (closestHostile) { - tower.attack(closestHostile); - } + let closestHostile = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS); + if (closestHostile) { + tower.attack(closestHostile); } + } - // for (let [role, values] of Object.entries(ROLES)) { - // if (values.idling > 0) { - // console.log(`${values.idling} ${role}s idling`) - // } - // } + // for (let [role, values] of Object.entries(ROLES)) { + // if (values.idling > 0) { + // console.log(`${values.idling} ${role}s idling`) + // } + // } - spawn.room.visual.text( - `${Game.cpu.getUsed().toFixed(1)} / ${Game.cpu.tickLimit} (${Game.cpu.bucket})`, - 1, 1, - {align: 'left', opacity: 0.8}); - } + spawn.room.visual.text( + `${Game.cpu.getUsed().toFixed(1)} / ${Game.cpu.tickLimit} (${Game.cpu.bucket})`, + 1, 1, + {align: 'left', opacity: 0.8}); if (Game.cpu.generatePixel && Game.cpu.bucket === 10000) { Game.cpu.generatePixel() } + + /* + PathFinder.search( + new RoomPosition(11, 7, 'E8S4'), + new RoomPosition(8, 11, 'E9S4'), + {roomCallback: roomName => { + let room = Game.rooms[roomName]; + // In this example `room` will always exist, but since + // PathFinder supports searches which span multiple rooms + // you should be careful! + if (!room) return; + let costs = new PathFinder.CostMatrix; + + room.find(FIND_STRUCTURES).forEach(function(struct) { + if (struct.structureType === STRUCTURE_ROAD) { + // Favor roads over plain tiles + costs.set(struct.pos.x, struct.pos.y, 1); + } else if (struct.structureType !== STRUCTURE_CONTAINER && + (struct.structureType !== STRUCTURE_RAMPART || + !struct.my)) { + // Can't walk through non-walkable buildings + costs.set(struct.pos.x, struct.pos.y, 0xff); + } + }); + + return costs; + }} + ).path.forEach(el => new RoomVisual(el.roomName).circle(el)) + */ } diff --git a/default/role.attacker.js b/default/role.attacker.js new file mode 100644 index 0000000..f6b1ba3 --- /dev/null +++ b/default/role.attacker.js @@ -0,0 +1,85 @@ +module.exports = { + name: 'attacker', + prio: 10, + tickInit () { + for (let room of Object.values(Game.rooms)) { + if (!room.memory.attacker) { + room.memory.attacker = {} + } + if (room.find(FIND_STRUCTURES, {filter: s => s.structureType === STRUCTURE_TOWER}).length > 0) { + room.memory.attacker.targetCount = 0 + continue + } + room.memory.attacker.targetCount = Math.min(room.find(FIND_HOSTILE_CREEPS).length, 2) + } + }, + nextSpawn (spawn, roleCreeps) { + for (let room of Object.values(Game.rooms)) { + if (_.filter(roleCreeps, {memory: {room: room.name}}).length < room.memory.attacker.targetCount) { + return [ + [ATTACK, MOVE, ATTACK, MOVE, ATTACK, MOVE, ATTACK, MOVE, ATTACK, MOVE, ATTACK, MOVE], + {room: room.name} + ] + } + } + }, + tick (creep) { + let room = Game.rooms[creep.memory.room] + let targetRoomName = creep.memory.room + if (targetRoomName !== creep.pos.roomName + && (_.filter(Game.creeps, {memory: {role: 'healer', room: targetRoomName}, spawning: false}).length < Memory.rooms[targetRoomName].healer.targetCount + || _.filter(Game.creeps, {memory: {role: 'attacker', room: targetRoomName}, spawning: false}).length < Memory.rooms[targetRoomName].attacker.targetCount + || _.filter(Game.creeps, {memory: {role: 'rangedAttacker', room: targetRoomName}, spawning: false}).length < Memory.rooms[targetRoomName].rangedAttacker.targetCount) + ) { + if (creep.ticksToLive < 1200) { + creep.moveTo(creep.pos.findClosestByPath(FIND_MY_SPAWNS)) + } + else { + creep.moveTo(creep.pos.findClosestByPath(FIND_FLAGS, { + filter: el => el.name.startsWith('gather'), + visualizePathStyle: {stroke: '#0017ff'} + })) + } + return + } + if (!room || targetRoomName !== creep.pos.roomName) { + creep.moveTo(new RoomPosition(25, 25, creep.memory.room)) + return + } + if (creep.pos.x <= 1) { + creep.move(RIGHT) + } else if (creep.pos.y <= 1) { + creep.move(BOTTOM) + } else if (creep.pos.x >= 48) { + creep.move(LEFT) + } else if (creep.pos.y >= 48) { + creep.move(TOP) + } + + let targetCreep + if (creep.memory.lastTarget) { + targetCreep = Game.getObjectById(creep.memory.lastTarget) + if (targetCreep && targetCreep.pos.roomName !== targetRoomName) { + delete creep.memory.lastTarget + targetCreep = undefined + } + } + + if (targetCreep && !creepIsAttacker(targetCreep)) { + let closeAttackers = creep.pos.findInRange(FIND_HOSTILE_CREEPS, 3, {filter: c => c.getActiveBodyparts(ATTACK) > 0 && c.pos.roomName === targetRoomName}) + if (closeAttackers.length > 0) { + targetCreep = closeAttackers[0] + } + } + + if (!targetCreep) { + targetCreep = creep.pos.findClosestByRange(FIND_HOSTILE_CREEPS, {filter: c => (creepIsAttacker(c) || c.getActiveBodyparts(CARRY) >= 2) && c.pos.roomName === targetRoomName}) + } + if (targetCreep) { + creep.memory.lastTarget = targetCreep.id + if (creep.attack(targetCreep) === ERR_NOT_IN_RANGE) { + creep.moveTo(targetCreep.pos) + } + } + }, +} diff --git a/default/role.builder.js b/default/role.builder.js index a6cd15a..11b4f5c 100644 --- a/default/role.builder.js +++ b/default/role.builder.js @@ -3,6 +3,12 @@ let idling = 0 let maxWallHits = 0 module.exports = { + name: 'builder', + prio: 5, + count: 1, + maxExpands: 4, + baseBody: [WORK, CARRY, MOVE, MOVE], + expandBody: [WORK, CARRY, MOVE, MOVE], idling, maxWallHits, cleanup () { @@ -18,16 +24,21 @@ module.exports = { } } }, - tickInit (room) { - let walls = room.find(FIND_STRUCTURES, { - filter: structure => (structure.structureType === STRUCTURE_WALL || structure.structureType === STRUCTURE_RAMPART) - }) - let wallAvgHits = 0 - if (walls.length > 0) { - wallAvgHits = walls.reduce((total, el) => total + el.hits, 0) - wallAvgHits = wallAvgHits / walls.length + tickInit () { + for (let room of Object.values(Game.rooms)) { + if (room.find(FIND_STRUCTURES, {filter: s => s.structureType === STRUCTURE_SPAWN}).length === 0) { + continue + } + let walls = room.find(FIND_STRUCTURES, { + filter: structure => (structure.structureType === STRUCTURE_WALL || structure.structureType === STRUCTURE_RAMPART) + }) + let wallAvgHits = 0 + if (walls.length > 0) { + wallAvgHits = walls.reduce((total, el) => total + el.hits, 0) + wallAvgHits = wallAvgHits / walls.length + } + maxWallHits = Math.min(wallAvgHits, 200000) } - maxWallHits = Math.min(wallAvgHits, 200000) }, tick (creep) { let harvest = common.harvestEnergy(creep) diff --git a/default/role.filler.js b/default/role.filler.js new file mode 100644 index 0000000..b275b35 --- /dev/null +++ b/default/role.filler.js @@ -0,0 +1,58 @@ +const common = require('common') + +module.exports = { + name: 'filler', + prio: 4, + count: 2, + bodies: [ + [CARRY, CARRY, MOVE], + [CARRY, CARRY, MOVE, CARRY, CARRY, MOVE], + [CARRY, CARRY, MOVE, CARRY, CARRY, MOVE, CARRY, CARRY, MOVE], + [CARRY, CARRY, MOVE, CARRY, CARRY, MOVE, CARRY, CARRY, MOVE, CARRY, CARRY, MOVE], + ], + tick (creep) { + if (creep.store.getFreeCapacity(RESOURCE_ENERGY) === 0) { + creep.memory.loading = false + } + else if (creep.store[RESOURCE_ENERGY] === 0) { + creep.memory.loading = true + } + + if (creep.memory.loading) { + let target = creep.pos.findClosestByPath(FIND_STRUCTURES, { + filter: s => { + return (s.structureType === STRUCTURE_STORAGE || s.structureType === STRUCTURE_CONTAINER) + && s.store[RESOURCE_ENERGY] > Math.min(creep.store.getFreeCapacity(RESOURCE_ENERGY), 100) + } + }) + if (target) { + if (creep.withdraw(target, RESOURCE_ENERGY) === ERR_NOT_IN_RANGE) { + creep.moveTo(target, {visualizePathStyle: {stroke: '#f7e180'}}) + } + } else { + creep.moveTo(creep.pos.findClosestByRange(FIND_FLAGS, {filter: flag => flag.name.startsWith('idle')}), {visualizePathStyle: {stroke: '#ff0000'}}); + return 'idle' + } + } + else { + let target = creep.pos.findClosestByPath(FIND_STRUCTURES, { + filter: s => ( + s.structureType === STRUCTURE_EXTENSION + || s.structureType === STRUCTURE_SPAWN + ) + && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0 + }) + if (!target && creep.room.storage && creep.room.storage.store[RESOURCE_ENERGY] > 1e5) { + target = creep.room.storage.pos.findClosestByRange(FIND_STRUCTURES, {filter: s => s.structureType === STRUCTURE_LINK}) + } + if (target) { + if (creep.transfer(target, RESOURCE_ENERGY) === ERR_NOT_IN_RANGE) { + creep.moveTo(target, {visualizePathStyle: {stroke: '#00ff0f'}}); + } + } else { + creep.moveTo(creep.pos.findClosestByRange(FIND_FLAGS, {filter: flag => flag.name.startsWith('idle')}), {visualizePathStyle: {stroke: '#ff0000'}}); + return 'idle' + } + } + } +}; diff --git a/default/role.harvester.js b/default/role.harvester.js index 84d9858..4c90bea 100644 --- a/default/role.harvester.js +++ b/default/role.harvester.js @@ -1,8 +1,17 @@ let common = require('common') -let idling = 0 module.exports = { - idling, + name: 'harvester', + prio: 3, + count: 3, + bodies: [ + [WORK, WORK, CARRY, MOVE], + [WORK, WORK, WORK, WORK, WORK, CARRY, MOVE], + [WORK, WORK, WORK, WORK, WORK, CARRY, MOVE, MOVE], + [WORK, WORK, WORK, WORK, WORK, CARRY, MOVE, MOVE, MOVE], + [WORK, WORK, WORK, WORK, WORK, CARRY, CARRY, MOVE, MOVE, MOVE], + [WORK, WORK, WORK, WORK, WORK, CARRY, CARRY, MOVE, MOVE, MOVE, MOVE], + ], tick (creep) { let dropped = creep.pos.findInRange(FIND_DROPPED_RESOURCES, 1); if (dropped.length > 0) { diff --git a/default/role.hauler.js b/default/role.hauler.js new file mode 100644 index 0000000..73dce7c --- /dev/null +++ b/default/role.hauler.js @@ -0,0 +1,101 @@ +module.exports = { + name: 'hauler', + prio: 11, + tickInit () { + for (let room of Object.values(Game.rooms)) { + if (!room.memory.hauler) { + room.memory.hauler = {} + } + let harvesters = room.find(FIND_MY_CREEPS, {filter: c => c.memory.role === 'remoteHarvester' && c.memory.room === room.name}) + let filledContainers = room.find(FIND_STRUCTURES, {filter: s => s.structureType === STRUCTURE_CONTAINER && s.store[RESOURCE_ENERGY] > 0}) + if (room.find(FIND_STRUCTURES, {filter: s => s.structureType === STRUCTURE_TOWER || s.structureType === STRUCTURE_SPAWN}).length > 0 + || (filledContainers.length === 0 && harvesters.length === 0) + || room.find(FIND_HOSTILE_CREEPS, {filter: c => creepIsAttacker(c)}).length > 0 + ) { + room.memory.hauler.targetCount = 0 + continue + } + room.memory.hauler.targetCount = Math.max(filledContainers.length, harvesters.length) * 6 + } + }, + nextSpawn (spawn, roleCreeps) { + for (let room of Object.values(Game.rooms)) { + if (_.filter(roleCreeps, {memory: {room: room.name}}).length < room.memory.hauler.targetCount) { + return [ + [CARRY, MOVE, CARRY, MOVE, CARRY, MOVE, CARRY, MOVE], + {room: room.name} + ] + } + } + }, + tick (creep) { + let targetRoom = Game.rooms[creep.memory.room] + let hostileCreeps = [1] + if (targetRoom) { + hostileCreeps = targetRoom.find(FIND_HOSTILE_CREEPS, {filter: c => creepIsAttacker(c)}) + } + if (creep.store.getFreeCapacity(RESOURCE_ENERGY) > 0 && hostileCreeps.length === 0) { + if (moveToRoom(creep, creep.memory.room) === MOVING) { + return + } + + let dropped = creep.pos.findInRange(FIND_DROPPED_RESOURCES, 1); + if (dropped.length > 0) { + creep.pickup(dropped[0]) + } + + dropped = creep.pos.findClosestByPath(FIND_DROPPED_RESOURCES, {filter: r => r.amount >= 100}); + if (dropped) { + if (creep.pickup(dropped) === ERR_NOT_IN_RANGE) { + creep.moveTo(dropped) + return + } + } + + let target = creep.pos.findClosestByPath(FIND_TOMBSTONES, { + filter: (structure) => structure.store[RESOURCE_ENERGY] > 0 + }) + if (!target) { + target = creep.pos.findClosestByPath(FIND_RUINS, { + filter: (structure) => structure.store[RESOURCE_ENERGY] > 0 + }) + } + if (!target) { + target = creep.pos.findClosestByPath(FIND_STRUCTURES, { + filter: s => { + return s.structureType === STRUCTURE_CONTAINER + } + }) + } + if (target) { + if (creep.withdraw(target, RESOURCE_ENERGY) === ERR_NOT_IN_RANGE) { + creep.moveTo(target, {visualizePathStyle: {stroke: '#f7e180'}}) + } + } else { + if (!target) { + target = creep.pos.findClosestByRange(FIND_MY_CREEPS, { + filter: s => { + return s.store[RESOURCE_ENERGY] >= s.store.getCapacity(RESOURCE_ENERGY) * 0.5 + && s.memory.role === 'remoteHarvester' + } + }) + } + if (target) { + if (creep.pos.getRangeTo(target) > 1) { + creep.moveTo(target, {visualizePathStyle: {stroke: '#f7e180'}}) + } + } + } + } else if (creep.store[RESOURCE_ENERGY] > 0) { + let storage = Game.rooms[creep.memory.colony].storage + if (creep.transfer(storage, RESOURCE_ENERGY) === ERR_NOT_IN_RANGE) { + creep.moveTo(storage) + } + } else if (moveToRoom(creep,creep.memory.colony) === MOVING) { + return + } else { + creep.moveTo(creep.pos.findClosestByRange(FIND_FLAGS, {filter: flag => flag.name.startsWith('idle')}), {visualizePathStyle: {stroke: '#ff0000'}}); + return 'idle' + } + }, +} diff --git a/default/role.healer.js b/default/role.healer.js new file mode 100644 index 0000000..ddd9b1f --- /dev/null +++ b/default/role.healer.js @@ -0,0 +1,88 @@ +module.exports = { + name: 'healer', + prio: 10, + tickInit () { + for (let room of Object.values(Game.rooms)) { + if (!room.memory.healer) { + room.memory.healer = {} + } + if (room.find(FIND_STRUCTURES, {filter: s => s.structureType === STRUCTURE_TOWER}).length > 0) { + room.memory.healer.targetCount = 0 + continue + } + room.memory.healer.targetCount = Math.min(room.find(FIND_HOSTILE_CREEPS).length, 1) + } + }, + nextSpawn (spawn, roleCreeps) { + for (let room of Object.values(Game.rooms)) { + if (_.filter(roleCreeps, {memory: {room: room.name}}).length < room.memory.healer.targetCount) { + return [ + [MOVE, MOVE, MOVE, MOVE, HEAL, HEAL, HEAL, HEAL], + {room: room.name} + ] + } + } + }, + tick (creep) { + let room = Game.rooms[creep.memory.room] + let targetRoomName = creep.memory.room + if (creep.memory.room !== creep.pos.roomName + && (_.filter(Game.creeps, {memory: {role: 'healer', room: targetRoomName}, spawning: false}).length < Memory.rooms[targetRoomName].healer.targetCount + || _.filter(Game.creeps, {memory: {role: 'attacker', room: targetRoomName}, spawning: false}).length < Memory.rooms[targetRoomName].attacker.targetCount + || _.filter(Game.creeps, {memory: {role: 'rangedAttacker', room: targetRoomName}, spawning: false}).length < Memory.rooms[targetRoomName].rangedAttacker.targetCount) + ) { + creep.moveTo(creep.pos.findClosestByPath(FIND_FLAGS, {filter: el => el.name.startsWith('gather'), visualizePathStyle: {stroke: '#0017ff'}})) + return + } + if (!room || creep.memory.room !== creep.pos.roomName) { + creep.moveTo(new RoomPosition(25, 25, creep.memory.room)) + return + } + if (creep.pos.x <= 2) { + creep.move(RIGHT) + } else if (creep.pos.y <= 2) { + creep.move(BOTTOM) + } else if (creep.pos.x >= 47) { + creep.move(LEFT) + } else if (creep.pos.y >= 47) { + creep.move(TOP) + } + + let targetCreep + if (creep.memory.lastTarget) { + targetCreep = Game.getObjectById(creep.memory.lastTarget) + } + + let closeAttackers = creep.pos.findInRange(FIND_HOSTILE_CREEPS, 4, {filter: c => c.getActiveBodyparts(ATTACK) > 0 && c.pos.roomName === targetRoomName}) + if (closeAttackers.length > 0) { + creep.moveByPath(PathFinder.search(creep.pos, closeAttackers.map(el => {return {pos: el.pos, range: 3}}), {flee: true, maxRooms: 1}).path) + } + + if (creep.hits < creep.hitsMax) { + creep.heal(creep) + return + } + + let healTargets = creep.pos.findInRange(FIND_MY_CREEPS, 1, {filter: c => c.hits < c.hitsMax && c.pos.roomName === targetRoomName}) + if (healTargets.length > 0) { + creep.heal(healTargets[0]) + return + } + + let rangedHealTarget = creep.pos.findClosestByRange(FIND_MY_CREEPS, {filter: c => c.hits < c.hitsMax && c.pos.roomName === targetRoomName}) + if (rangedHealTarget) { + creep.rangedHeal(rangedHealTarget) + creep.moveTo(rangedHealTarget, {visualizePathStyle: {stroke: '#00ff0f'}}) + return + } + + let possibleTarget = creep.pos.findClosestByPath(FIND_MY_CREEPS, {filter: c => creepIsAttacker(c) && c.pos.roomName === targetRoomName}) + let range = creep.pos.getRangeTo(possibleTarget) + if (range === 1) { + creep.moveByPath(PathFinder.search(creep.pos, {pos: possibleTarget.pos, range: 2}, {flee: true, maxRooms: 1}).path) + } + else if (range > 3) { + creep.moveTo(possibleTarget, {visualizePathStyle: {stroke: '#00ff0f'}}) + } + }, +} diff --git a/default/role.rangedAttacker.js b/default/role.rangedAttacker.js new file mode 100644 index 0000000..8b2f187 --- /dev/null +++ b/default/role.rangedAttacker.js @@ -0,0 +1,90 @@ +module.exports = { + name: 'rangedAttacker', + prio: 10, + tickInit () { + for (let room of Object.values(Game.rooms)) { + if (!room.memory.rangedAttacker) { + room.memory.rangedAttacker = {} + } + if (room.find(FIND_STRUCTURES, {filter: s => s.structureType === STRUCTURE_TOWER}).length > 0) { + room.memory.rangedAttacker.targetCount = 0 + continue + } + room.memory.rangedAttacker.targetCount = Math.min(room.find(FIND_HOSTILE_CREEPS).length, 2) + } + }, + nextSpawn (spawn, roleCreeps) { + for (let [roomName, roomMemory] of Object.entries(Memory.rooms)) { + if (_.filter(roleCreeps, {memory: {room: roomName}}).length < roomMemory.rangedAttacker.targetCount) { + return [ + [RANGED_ATTACK, MOVE, RANGED_ATTACK, MOVE, RANGED_ATTACK, MOVE, RANGED_ATTACK, MOVE, RANGED_ATTACK, MOVE], + {room: roomName} + ] + } + } + }, + tick (creep) { + let room = Game.rooms[creep.memory.room] + let targetRoomName = creep.memory.room + if (creep.memory.colony === creep.pos.roomName + && (_.filter(Game.creeps, {memory: {role: 'healer', room: targetRoomName}, spawning: false}).length < Memory.rooms[targetRoomName].healer.targetCount + || _.filter(Game.creeps, {memory: {role: 'attacker', room: targetRoomName}, spawning: false}).length < Memory.rooms[targetRoomName].attacker.targetCount + || _.filter(Game.creeps, {memory: {role: 'rangedAttacker', room: targetRoomName}, spawning: false}).length < Memory.rooms[targetRoomName].rangedAttacker.targetCount) + ) { + if (creep.ticksToLive < 1200) { + creep.moveTo(creep.pos.findClosestByPath(FIND_MY_SPAWNS)) + } else { + creep.moveTo(creep.pos.findClosestByPath(FIND_FLAGS, { + filter: el => el.name.startsWith('gather'), + visualizePathStyle: {stroke: '#0017ff'} + })) + } + return + } + if (!room || targetRoomName !== creep.pos.roomName) { + creep.moveTo(new RoomPosition(25, 25, creep.memory.room)) + return + } + + if (creep.pos.x <= 2) { + creep.move(RIGHT) + } else if (creep.pos.y <= 2) { + creep.move(BOTTOM) + } else if (creep.pos.x >= 47) { + creep.move(LEFT) + } else if (creep.pos.y >= 47) { + creep.move(TOP) + } + + let targetCreep + if (creep.memory.lastTarget) { + targetCreep = Game.getObjectById(creep.memory.lastTarget) + } + + let closeAttackers = creep.pos.findInRange(FIND_HOSTILE_CREEPS, 3, {filter: c => creepIsAttacker(c)}) + if (closeAttackers.length > 0) { + creep.moveByPath(PathFinder.search(creep.pos, closeAttackers.map(el => {return {pos: el.pos, range: 2}}), {flee: true, maxRooms: 1}).path) + targetCreep = closeAttackers[0] + } + + if (!targetCreep) { + targetCreep = creep.pos.findClosestByRange(FIND_HOSTILE_CREEPS, {filter: c => creepIsAttacker(c) || c.getActiveBodyparts(CARRY) >= 2}) + } + if (targetCreep) { + let targetIsAttacker = creepIsAttacker(targetCreep) + creep.memory.lastTarget = targetCreep.id + let range = creep.pos.getRangeTo(targetCreep.pos) + if (range <= 3) { + creep.rangedAttack(targetCreep) + } + else { + let driveByTargets = creep.pos.findInRange(FIND_HOSTILE_CREEPS, 3, {filter: c => creepIsAttacker(c) || c.getActiveBodyparts(CARRY) >= 2}) + if (driveByTargets.length > 0) { + creep.rangedAttack(driveByTargets[0]) + } + } + let distanceToKeep = targetIsAttacker ? 3 : 2 + creep.moveByPath(PathFinder.search(creep.pos, [{pos: targetCreep.pos, range: distanceToKeep}], {maxRooms: 1, flee: range < distanceToKeep}).path) + } + }, +} diff --git a/default/role.remoteHarvester.js b/default/role.remoteHarvester.js new file mode 100644 index 0000000..428c351 --- /dev/null +++ b/default/role.remoteHarvester.js @@ -0,0 +1,54 @@ +let common = require('common') + +module.exports = { + name: 'remoteHarvester', + prio: 10, + bodies: [ + [WORK, WORK, WORK, CARRY, MOVE, MOVE, MOVE, MOVE], + [WORK, WORK, WORK, WORK, WORK, WORK, CARRY, MOVE, MOVE, MOVE, MOVE, MOVE, MOVE, MOVE], + [WORK, WORK, WORK, WORK, WORK, WORK, CARRY, CARRY, MOVE, MOVE, MOVE, MOVE, MOVE, MOVE, MOVE, MOVE], + ], + tick (creep) { + let dropped = creep.pos.findInRange(FIND_DROPPED_RESOURCES, 1); + if (dropped.length > 0) { + creep.pickup(dropped[0]) + } + + let repairTargets = creep.pos.findInRange( + FIND_STRUCTURES, + 3, + {filter: s => s.structureType === STRUCTURE_CONTAINER && s.hits + creep.getActiveBodyparts(WORK) * 100 <= s.hitsMax}); + if (repairTargets.length > 0) { + if (creep.store[RESOURCE_ENERGY] >= creep.getActiveBodyparts(WORK) * 10 && creep.repair(repairTargets[0]) === OK) { + return + } + } else { + let targetCreeps = creep.pos.findInRange(FIND_MY_CREEPS, 1, { + filter: tc => tc.store.getFreeCapacity(RESOURCE_ENERGY) && tc.memory.role !== 'remoteHarvester' + }); + if (targetCreeps.length > 0) { + creep.transfer(targetCreeps[0], RESOURCE_ENERGY) + } else { + let targets = creep.pos.findInRange(FIND_STRUCTURES, 1, { + filter: (structure) => structure.store && structure.store.getFreeCapacity(RESOURCE_ENERGY) > 0 + }); + if (targets.length > 0) { + creep.transfer(_.min(targets, el => el.store[RESOURCE_ENERGY]), RESOURCE_ENERGY) + } else { + if (creep.store[RESOURCE_ENERGY] >= creep.getActiveBodyparts(WORK) * 5) { + let buildTargets = creep.pos.findInRange(FIND_MY_CONSTRUCTION_SITES, 1); + if (buildTargets.length > 0 && creep.build(buildTargets[0]) === OK) { + return + } + } + } + } + } + + let target = Game.getObjectById(creep.memory.source) + let actionResult = creep.harvest(target) + if (actionResult === ERR_NOT_IN_RANGE) { + creep.moveTo(target, {visualizePathStyle: {stroke: '#ffaa00'}}); + } + } +}; diff --git a/default/role.reserver.js b/default/role.reserver.js new file mode 100644 index 0000000..a8f7ee4 --- /dev/null +++ b/default/role.reserver.js @@ -0,0 +1,31 @@ +module.exports = { + name: 'reserver', + prio: 20, + nextSpawn (spawn, roleCreeps) { + for (let roomName of activeRemotes) { + let room = Game.rooms[roomName] + if (!room) { + continue + } + if (!room.controller.owner + && _.filter(roleCreeps, {memory: {room: roomName}}).length === 0 && ( + !room.controller.reservation + || (room.controller.reservation.username === 'NativeException' && room.controller.reservation.ticksToEnd < 3000) + )) { + return [ + [CLAIM, CLAIM, MOVE, MOVE], + {room: roomName} + ] + } + } + }, + tick (creep) { + if (moveToRoom(creep, creep.memory.room) === MOVING) { + return + } + let room = Game.rooms[creep.memory.room] + if (creep.reserveController(room.controller) === ERR_NOT_IN_RANGE) { + creep.moveTo(room.controller) + } + }, +} diff --git a/default/role.scout.js b/default/role.scout.js index 6187c06..7a883ce 100644 --- a/default/role.scout.js +++ b/default/role.scout.js @@ -1,5 +1,30 @@ module.exports = { + name: 'scout', + count: 1, + prio: 15, + bodies: [[MOVE]], + nextSpawn (spawn, roleCreeps) { + for (let roomName of activeRemotes) { + if (!Game.rooms[roomName] && _.filter(roleCreeps, {memory: {room: roomName}}).length === 0) { + return [ + [MOVE], + {room: roomName} + ] + } + } + }, tick (creep) { - - } + let room = Game.rooms[creep.memory.room] + if (!room) { + for (let remoteRoom of activeRemotes) { + if (!Game.rooms[remoteRoom]) { + creep.memory.room = remoteRoom + } + } + } + let pos = new RoomPosition(25, 25, creep.memory.room) + if (moveToRoom(creep, creep.memory.room) === ALREADY_IN_ROOM && creep.pos.getRangeTo(pos) > 10) { + creep.moveByPath(PathFinder.search(creep.pos, {pos, range: 10}).path) + } + }, } diff --git a/default/role.transporter.js b/default/role.transporter.js index a5852a3..0559a92 100644 --- a/default/role.transporter.js +++ b/default/role.transporter.js @@ -1,6 +1,15 @@ const common = require('common') module.exports = { + name: 'transporter', + prio: 4, + count: 1, + bodies: [ + [CARRY, CARRY, MOVE], + [CARRY, CARRY, MOVE, CARRY, CARRY, MOVE], + [CARRY, CARRY, MOVE, CARRY, CARRY, MOVE, CARRY, CARRY, MOVE], + [CARRY, CARRY, MOVE, CARRY, CARRY, MOVE, CARRY, CARRY, MOVE, CARRY, CARRY, MOVE], + ], tick (creep) { if (creep.store.getFreeCapacity(RESOURCE_ENERGY) === 0) { creep.memory.loading = false @@ -12,9 +21,8 @@ module.exports = { if (creep.store[RESOURCE_ENERGY] >= 50) { let quickfillTargets = creep.pos.findInRange(FIND_STRUCTURES, 2, { filter: s => { - return s.store - && s.structureType !== STRUCTURE_CONTAINER - && s.structureType !== STRUCTURE_STORAGE + return (s.structureType === STRUCTURE_SPAWN + || s.structureType === STRUCTURE_EXTENSION) && s.store.getFreeCapacity(RESOURCE_ENERGY) > 0 } }) diff --git a/default/role.upgrader.js b/default/role.upgrader.js index 9239f58..aefd17d 100644 --- a/default/role.upgrader.js +++ b/default/role.upgrader.js @@ -3,6 +3,13 @@ let idling = 0 module.exports = { idling, + name: 'upgrader', + prio: 6, + count: 1, + getCount: colonyRoom => colonyRoom.storage ? Math.ceil(colonyRoom.storage.store[RESOURCE_ENERGY] / 100000) : 1, + maxExpands: 4, + baseBody: [WORK, CARRY, MOVE], + expandBody: [WORK, WORK, MOVE], tick (creep) { if (creep.store.getFreeCapacity(RESOURCE_ENERGY) > 0) { let dropped = creep.pos.findInRange(FIND_DROPPED_RESOURCES, 1); diff --git a/default/spawn.js b/default/spawn.js index e54b741..cb0ad75 100644 --- a/default/spawn.js +++ b/default/spawn.js @@ -3,13 +3,10 @@ require('globals') const EMERGENCY_MODE_TIMEOUT = 100 function getHarvestingSpots (source) { - if (source.room.memory.harvestingSpots[source.id]) { - return source.room.memory.harvestingSpots[source.id] - } let spots = [] let terrain = source.room.getTerrain() - for (let x = source.pos.x; x <= source.pos.x + 1; x++) { - for (let y = source.pos.y; y <= source.pos.y + 1; y++) { + for (let x = source.pos.x - 1; x <= source.pos.x + 1; x++) { + for (let y = source.pos.y - 1; y <= source.pos.y + 1; y++) { if (terrain.get(x, y) !== TERRAIN_MASK_WALL) { spots.push([x, y]) } @@ -42,13 +39,25 @@ module.exports = { if (!room.memory.lastEnergy) { room.memory.lastEnergy = 0 } + if (!room.memory.energyStructuresPriority || Game.time % 100 === 0) { + room.memory.energyStructuresPriority = _.sortBy( + room.find( + FIND_MY_STRUCTURES, + {filter: s => s.structureType === STRUCTURE_EXTENSION || s.structureType === STRUCTURE_SPAWN} + ).map(el => {return {structure: el, range: el.pos.getRangeTo(room.storage)}}), + 'range' + ).map(el => el.structure.id) + } if (!room.memory.sourcesData) { room.memory.sourcesData = {} } for (let source of room.find(FIND_SOURCES)) { - if (!room.memory.sourcesData[source.id]) { - room.memory.sourcesData[source.id] = {spawnDistance: 0} + if (!room.memory.harvestingSpots[source.id] || Game.time % 10 === 0) { + room.memory.harvestingSpots[source.id] = getHarvestingSpots(source) + } + if (!room.memory.sourcesData[source.id] || Game.time % 10 === 0) { + room.memory.sourcesData[source.id] = {spawnDistance: 0, energyCapacity: source.energyCapacity} let spawn = source.pos.findClosestByPath(FIND_MY_SPAWNS) if (spawn) { room.memory.sourcesData[source.id].spawnDistance = source.pos.findPathTo(spawn.pos, {ignoreCreeps: true}).length @@ -62,8 +71,9 @@ module.exports = { if (spawn.spawning) { spawn.room.memory.spawnIdle = 0 let spawningCreep = Game.creeps[spawn.spawning.name]; + let room = spawningCreep.memory.room || '' spawn.room.visual.text( - '🛠️' + spawningCreep.memory.role, + '🛠️' + spawningCreep.memory.role + ' ' + room, spawn.pos.x + 1, spawn.pos.y, {align: 'left', opacity: 0.8}); @@ -71,7 +81,7 @@ module.exports = { else { let newCreep, prio for (let [roleName, role] of Object.entries(ROLES)) { - let roleCreeps = _.filter(Game.creeps, (creep) => creep.memory.role === roleName); + let roleCreeps = _.filter(Game.creeps, {memory: {role: roleName, colony: spawn.room.name}}); if (minRoleCount === undefined || minRoleCount > roleCreeps.length) { minRoleCount = roleCreeps.length } @@ -80,10 +90,16 @@ module.exports = { } let newName = roleName + Game.time; let body = [] - let memory = {role: roleName} - if (roleName === 'harvester') { + let memory = {role: roleName, colony: spawn.room.name} + if (role.nextSpawn) { + let nextSpawn = role.nextSpawn(spawn, roleCreeps) + if (nextSpawn) { + [body, memory] = nextSpawn + } + } + else if (roleName === 'harvester') { for (let source of spawn.room.find(FIND_SOURCES)) { - let spots = getHarvestingSpots(source) + let spots = spawn.room.memory.harvestingSpots[source.id] let harvestingCapacity = 0 let sourceHarvesters = _.filter(Game.creeps, {memory: {role: 'harvester', source: source.id}}) if (sourceHarvesters.length >= spots.length) { @@ -94,8 +110,8 @@ module.exports = { harvestingCapacity += harvester.getActiveBodyparts(WORK) * 2 * 300 } } - if (harvestingCapacity <= source.energyCapacity) { - for (let b of ROLES.harvester.bodies) { + if (harvestingCapacity < source.energyCapacity) { + for (let b of role.bodies) { if (getBodyCost(b) <= (spawn.room.memory.emergency ? spawn.room.energyAvailable : spawn.room.energyCapacityAvailable)) { body = b memory.source = source.id @@ -106,7 +122,41 @@ module.exports = { } } } - else if (roleCreeps.length < role.count && role.idling === 0) { + else if (roleName === 'remoteHarvester') { + for (let roomName of activeRemotes) { + let roomMemory = Memory.rooms[roomName] + if (roomMemory) { + for (let [sourceId, sourceData] of Object.entries(roomMemory.sourcesData)) { + let spots = roomMemory.harvestingSpots[sourceId] + let harvestingCapacity = 0 + let sourceHarvesters = _.filter(Game.creeps, {memory: {role: 'remoteHarvester', source: sourceId}}) + if (sourceHarvesters.length >= spots.length) { + continue + } + for (let harvester of sourceHarvesters) { + if (harvester.ticksToLive > harvester.body.length * 3 + sourceData.spawnDistance) { + harvestingCapacity += harvester.getActiveBodyparts(WORK) * 2 * 300 + } + } + if (harvestingCapacity < sourceData.energyCapacity) { + for (let b of role.bodies) { + if (getBodyCost(b) <= spawn.room.energyCapacityAvailable) { + body = b + memory.source = sourceId + memory.room = roomName + if (_.filter(b, WORK).length * 2 * 300 > sourceData.energyCapacity) { + break + } + } else { + break + } + } + } + } + } + } + } + else if (roleCreeps.length < (role.getCount ? role.getCount(spawn.room) : role.count) && role.idling === 0) { if (Array.isArray(role.bodies)) { for (let b of role.bodies) { if (getBodyCost(b) <= (spawn.room.memory.emergency ? spawn.room.energyAvailable : spawn.room.energyCapacityAvailable)) { @@ -119,15 +169,26 @@ module.exports = { body = role.baseBody while (getBodyCost(body) + getBodyCost(role.expandBody) <= (spawn.room.memory.emergency ? spawn.room.energyAvailable : spawn.room.energyCapacityAvailable)) { body = body.concat(role.expandBody) + if (body.length >= role.baseBody.length + role.expandBody.length * role.maxExpands) { + break + } } } } + memory.role = roleName + memory.colony = spawn.room.name if (body.length && (!prio || role.prio * (roleCreeps.length + 1) < prio)) { newCreep = [body, newName, {memory}] prio = role.prio * (roleCreeps.length + 1) } } + if (spawn.room.memory.lastEnergy !== spawn.room.energyAvailable) { + spawn.room.memory.energyIncreasedAt = Game.time + spawn.room.memory.lastEnergy = spawn.room.energyAvailable + } + spawn.room.memory.emergency = false if (newCreep) { + newCreep[2].energyStructures = spawn.room.memory.energyStructuresPriority.map(el => Game.getObjectById(el)) spawn.spawnCreep(...newCreep) spawn.room.memory.spawnIdle++ spawn.room.visual.text( @@ -135,33 +196,33 @@ module.exports = { spawn.pos.x + 1, spawn.pos.y, {align: 'left', opacity: 0.8, size: 0.3}); - } - if (spawn.room.memory.lastEnergy !== spawn.room.energyAvailable) { - spawn.room.memory.energyIncreasedAt = Game.time - spawn.room.memory.lastEnergy = spawn.room.energyAvailable - } - spawn.room.memory.emergency = false - if (minRoleCount === 0) { - let timeToEmergency = Math.max( - EMERGENCY_MODE_TIMEOUT - spawn.room.memory.spawnIdle, - EMERGENCY_MODE_TIMEOUT - Game.time - spawn.room.memory.energyIncreasedAt - ) - if (timeToEmergency <= 0) { - spawn.room.memory.emergency = true - spawn.room.visual.text( - `Prio${prio} emergency spawn ${newCreep[1]} (${newCreep[0]})`, - spawn.pos.x + 1, - spawn.pos.y, - {align: 'left', opacity: 0.8}); - } else if (timeToEmergency <= 50) { - spawn.room.visual.text( - 'Emergency in ' + (EMERGENCY_MODE_TIMEOUT - spawn.room.memory.spawnIdle), - spawn.pos.x + 1, - spawn.pos.y, - {align: 'left', opacity: 0.8}); + if (minRoleCount === 0) { + let timeToEmergency = Math.max( + EMERGENCY_MODE_TIMEOUT - spawn.room.memory.spawnIdle, + EMERGENCY_MODE_TIMEOUT - (Game.time - spawn.room.memory.energyIncreasedAt) + ) + if (timeToEmergency <= 0) { + spawn.room.memory.emergency = true + spawn.room.visual.text( + `Prio${prio} emergency spawn ${newCreep[1]} (${newCreep[0]})`, + spawn.pos.x + 1, + spawn.pos.y, + {align: 'left', opacity: 0.8}); + } else if (timeToEmergency <= 50) { + spawn.room.visual.text( + 'Emergency in ' + timeToEmergency, + spawn.pos.x + 1, + spawn.pos.y, + {align: 'left', opacity: 0.8}); + } } - } + }/* else { + let renewableCreeps = spawn.pos.findInRange(FIND_MY_CREEPS, 1, {filter: c => c.ticksToLive < 1200}) + if (renewableCreeps.length > 0) { + spawn.renewCreep(renewableCreeps[0]) + } + }*/ } }, }