diff --git a/src/prototype_creep.js b/src/prototype_creep.js index 276a3f4a4..2d84813bf 100644 --- a/src/prototype_creep.js +++ b/src/prototype_creep.js @@ -101,9 +101,9 @@ Creep.prototype.checkForHandle = function() { const role = this.memory.role; if (!role) { + this.memory.role = 'scout'; this.log('Creep role not defined for: ' + this.id + ' ' + this.name.split('-')[0].replace(/[0-9]/g, '')); - this.memory.killed = true; - this.suicide(); + Creep.recycleCreep(this); return false; } return true; @@ -116,8 +116,8 @@ Creep.prototype.handle = function() { } try { if (!this.unit()) { - this.log('Unknown role suiciding'); - this.suicide(); + this.log('Unknown role recycling creep'); + Creep.recycleCreep(this); return; } diff --git a/src/prototype_creep_clean.js b/src/prototype_creep_clean.js index 63d3a125f..b9bb3c630 100644 --- a/src/prototype_creep_clean.js +++ b/src/prototype_creep_clean.js @@ -142,8 +142,7 @@ Creep.prototype.cleanSetTargetId = function() { } } this.memory.targetReached = true; - this.memory.killed = true; - this.log('Nothing found, suicide'); - this.suicide(); + this.log('Nothing found, recycling'); + Creep.recycleCreep(this); // return Creep.recycleCreep(this); }; diff --git a/src/prototype_creep_move.js b/src/prototype_creep_move.js index f6a4e8827..9597eabc3 100644 --- a/src/prototype_creep_move.js +++ b/src/prototype_creep_move.js @@ -193,7 +193,7 @@ Creep.prototype.moveCreepCheckRoleAndTarget = function(creep, direction) { if (role === 'upgrader' && (targetRole === 'universal' || targetRole === 'sourcer' || targetRole === 'upgrader')) { this.log('config_creep_move suicide ' + targetRole); - creep.suicide(); + Creep.recycleCreep(creep); return true; } }; diff --git a/src/prototype_creep_routing.js b/src/prototype_creep_routing.js index 34f39787d..59e3a4da4 100644 --- a/src/prototype_creep_routing.js +++ b/src/prototype_creep_routing.js @@ -142,8 +142,8 @@ Creep.prototype.followPath = function(action) { try { path = this.prepareRoutingMemory(); } catch (e) { - this.log(`Suiciding, cannot prepare routing ${e} ${e.stack}`); - this.suicide(); + this.log(`Recycling, cannot prepare routing ${e} ${e.stack}`); + Creep.recycleCreep(this); return true; } if (!path) { diff --git a/src/prototype_creep_startup_tasks.js b/src/prototype_creep_startup_tasks.js index e1b675c78..c67957462 100644 --- a/src/prototype_creep_startup_tasks.js +++ b/src/prototype_creep_startup_tasks.js @@ -98,30 +98,116 @@ Creep.buildRoads = function(creep) { return false; }; +/** + * search the closest spawn + * + * @param {Creep} creep + * @return {null|Spawn} + */ +Creep.searchClosestSpawn = function(creep) { + const spawn = creep.pos.findClosestByRangePropertyFilter(FIND_MY_STRUCTURES, 'structureType', [STRUCTURE_SPAWN]); + if (spawn) { + return spawn; + } + const roomMap = new Map(); + for (const currentSpawnId of Object.keys(Game.spawns)) { + const currentSpawn = Game.spawns[currentSpawnId]; + roomMap.set( + currentSpawn.room.name, + currentSpawn, + ); + } + if (roomMap.size === 0) { + return null; + } + let minDistance = Number.MAX_SAFE_INTEGER; + let closestRoomName = null; + for (const currentRoomName of roomMap.keys()) { + const currentDistance = Game.map.getRoomLinearDistance(creep.room.name, currentRoomName); + if (currentDistance < minDistance) { + minDistance = currentDistance; + closestRoomName = currentRoomName; + } + } + if (!closestRoomName) { + return null; + } + return roomMap.get(closestRoomName); +}; + Creep.recycleCreep = function(creep) { if (creep.memory.role === 'builder') { if (creep.room.buildStructures()) { creep.memory.recycle = false; } } - - let spawn = creep.pos.findClosestByRangePropertyFilter(FIND_MY_STRUCTURES, 'structureType', [STRUCTURE_SPAWN]); - if (!spawn) { - spawn = Game.rooms[creep.memory.base].findPropertyFilter(FIND_MY_STRUCTURES, 'structureType', [STRUCTURE_SPAWN])[0]; + creep.say('recycle'); + let spawn = null; + let recycleData = creep.memory.recycleData; + if (!recycleData) { + recycleData = {}; + creep.memory.recycleData = recycleData; } - if (spawn) { - if (creep.room === spawn.room) { - creep.moveToMy(spawn.pos); - } else { - // TODO make use of the proper routing logic - creep.moveTo(spawn); - } - creep.say('recycle'); + if (recycleData.targetId) { + spawn = Game.getObjectById(recycleData.targetId); const response = spawn.recycleCreep(creep); if (response === OK) { creep.memory.recycle = true; } + return true; + } + let path = recycleData.path; + if (path && path.length) { + for (let i = 0; i < path.length; ++i) { + let roomPositionMemory = path[i]; + path[i] = new RoomPosition(roomPositionMemory.x, roomPositionMemory.y, roomPositionMemory.roomName); + } + const moveResult = creep.moveByPath(path); + if (moveResult === OK) { + recycleData.incompleteCount = 0; + recycleData.path = path = path.shift(); + creep.memory.recycleData = recycleData; + return true; + } + } + let incompleteCount = recycleData.incompleteCount; + if (recycleData.targetId && recycleData.path) { + if (!incompleteCount) { + incompleteCount = 1; + } else { + ++incompleteCount; + } + recycleData.incompleteCount = incompleteCount; + if (incompleteCount <= 25) { + creep.memory.recycleData = recycleData; + return true; + } + } + recycleData.incompleteCount = incompleteCount = 0; + spawn = Creep.searchClosestSpawn(creep); + if (!spawn) { + creep.suicide(); + return true; + } + const targetPosObject = spawn.pos; + const search = PathFinder.search( + creep.pos, + { + pos: targetPosObject, + range: 1, + }, + ); + if (creep.ticksToLive < search.cost) { + creep.suicide(); + return true; + } + recycleData.targetId = spawn.id; + recycleData.path = path = search.path; + const moveResult = creep.moveByPath(path); + if (moveResult === OK) { + recycleData.incompleteCount = 0; } + creep.memory.recycleData = recycleData; return true; }; diff --git a/src/prototype_room_controller.js b/src/prototype_room_controller.js index 981125b5e..ffba801eb 100644 --- a/src/prototype_room_controller.js +++ b/src/prototype_room_controller.js @@ -116,5 +116,5 @@ Room.prototype.clearRoom = function() { _.each(constructionSites, (cs) => cs.remove()); const creeps = this.findMyCreeps(); - _.each(creeps, (cs) => cs.suicide()); + _.each(creeps, (cs) => Creep.recycleCreep(cs)); }; diff --git a/src/role_carry.js b/src/role_carry.js index f472cf091..800bfe6a2 100644 --- a/src/role_carry.js +++ b/src/role_carry.js @@ -55,15 +55,15 @@ function checkHelperEmptyStorage(creep) { if (creep.room.name === creep.memory.routing.targetRoom) { const targetStructure = Game.getObjectById(creep.memory.routing.targetId); if (targetStructure === null) { - creep.suicide(); + Creep.recycleCreep(creep); return; } if (targetStructure.structureType === STRUCTURE_STORAGE) { creep.say('storage'); if (targetStructure.store.energy === 0) { - creep.log('Suiciding the storage I should get the energy from is empty'); - creep.suicide(); + creep.log('Recycling, the storage I should get the energy from is empty'); + Creep.recycleCreep(creep); } } } @@ -398,7 +398,8 @@ roles.carry.action = function(creep) { // End of path, can't harvest, suicide (otherwise the sourcer gets stuck) if (!reverse && creep.body.filter((part) => part.type === WORK).length === 0) { - // creep.log('Suiciding because end of path, no energy, do not want to get in the way of the sourcer (better recycle?)'); + // creep.log('Recycling because end of path, no energy, do not want to get in the way of the sourcer (better recycle?)'); + // no, recycle here will only make it more stuck, fail. creep.memory.killed = true; creep.suicide(); } diff --git a/src/role_claimer.js b/src/role_claimer.js index 3034b6e8d..a6b05f4b5 100644 --- a/src/role_claimer.js +++ b/src/role_claimer.js @@ -22,7 +22,7 @@ roles.claimer.action = function(creep) { const returnCode = creep.claimController(creep.room.controller); if (returnCode === OK) { creep.creepLog('New claimer, in room, claimed'); - creep.suicide(); + Creep.recycleCreep(creep); } return true; }; diff --git a/src/role_extractor.js b/src/role_extractor.js index 552613991..dd492a6de 100644 --- a/src/role_extractor.js +++ b/src/role_extractor.js @@ -38,7 +38,7 @@ function getMineral(creep) { roles.extractor.action = function(creep) { if (!creep.room.terminal) { - creep.suicide(); + Creep.recycleCreep(creep); return true; } const mineral = getMineral(creep); diff --git a/src/role_mineral.js b/src/role_mineral.js index f670bb2c5..16c65f4e7 100644 --- a/src/role_mineral.js +++ b/src/role_mineral.js @@ -251,12 +251,12 @@ function transfer(creep, target, resource) { */ function checkForSuicide(creep) { if (!creep.room.terminal) { - creep.suicide(); + Creep.recycleCreep(creep); return true; } if (creep.ticksToLive < 50 && _.sum(creep.carry) === 0) { // early suicide to not waste minerals - creep.suicide(); + Creep.recycleCreep(creep); return true; } return false; diff --git a/src/role_quester.js b/src/role_quester.js index afdc95797..e4243cd43 100644 --- a/src/role_quester.js +++ b/src/role_quester.js @@ -16,7 +16,7 @@ roles.quester.settings = { roles.quester.questLost = function(creep, quest, reason, value) { creep.log(`Quest lost cs: ${value} ${JSON.stringify(quest)}`); delete Memory.quests[creep.memory.level]; - creep.suicide(); + Creep.recycleCreep(creep); }; roles.quester.questWon = function(creep, quest) { @@ -33,7 +33,7 @@ roles.quester.questWon = function(creep, quest) { }; creep.room.terminal.send(RESOURCE_ENERGY, 100, quest.player.room, JSON.stringify(response)); delete Memory.quests[creep.memory.level]; - creep.suicide(); + Creep.recycleCreep(creep); }; roles.quester.handleBuildConstructionSite = function(creep, quest) { @@ -66,8 +66,8 @@ roles.quester.action = function(creep) { creep.spawnReplacement(); const quest = Memory.quests[creep.memory.level]; if (!quest) { - creep.log(`Quest ${creep.memory.level} not found, suiciding`); - creep.suicide(); + creep.log(`Quest ${creep.memory.level} not found, recycling`); + Creep.recycleCreep(creep); return; } if (quest.quest === 'buildcs') { diff --git a/src/role_signer.js b/src/role_signer.js index 54a287e5e..93b72353a 100644 --- a/src/role_signer.js +++ b/src/role_signer.js @@ -21,7 +21,7 @@ roles.signer.action = function(creep) { // creep.memory.routing = creep.memory.nextTarget.routing; // creep.memory.nextTarget = creep.memory.nextTarget.nextTarget; // } else { - creep.suicide(); + Creep.recycleCreep(creep); // } return true; } else { diff --git a/src/role_sourcer.js b/src/role_sourcer.js index c4152a3bc..48eacc240 100644 --- a/src/role_sourcer.js +++ b/src/role_sourcer.js @@ -109,16 +109,15 @@ function harvest(creep) { } if (returnCode === ERR_NOT_OWNER) { - creep.log('Suiciding, someone else reserved the controller'); - creep.memory.killed = true; - creep.suicide(); + creep.log('Recycling, someone else reserved the controller'); + Creep.recycleCreep(creep); return false; } if (returnCode === ERR_NO_BODYPART) { creep.room.checkRoleToSpawn('defender', 2, undefined, creep.room.name); creep.respawnMe(); - creep.suicide(); + Creep.recycleCreep(creep); return false; } diff --git a/src/role_watcher.js b/src/role_watcher.js index aca6217b8..75c58cfd9 100644 --- a/src/role_watcher.js +++ b/src/role_watcher.js @@ -45,7 +45,7 @@ roles.watcher.action = function(creep) { }); if (creepOfRole.length > 1) { creepOfRole = _.sortBy(creepOfRole, (c) => c.ticksToLive); - creepOfRole[0].suicide(); + creepOfRole[0].recycleCreep(); } } else { creep.moveToMy(pos, near);