From 8240847b3934bb910c2ace1a531b64b2dd2d8e6b Mon Sep 17 00:00:00 2001 From: Tobias Wilken Date: Mon, 18 Apr 2022 03:31:11 +0200 Subject: [PATCH] Reservation, carry, getEnergyFromStorage (#642) - Improve and fix reservation logic. Intended reservered rooms were flagged as unreservered - Reduce code complexity - New carrys more first to the target before accepting transfers. E.g. commodity carry are integrated into the carry network and reached the target to late - Fix getEnergyFromStorage, especially on `misplacedSpawn` - Adapt code to the quest logic from the documentation --- doc/API.md | 8 +- doc/BaseBuilding.md | 11 ++- docker-compose-setup.yml | 2 + docker-compose.yml | 2 + package-lock.json | 2 +- package.json | 2 +- src/brain_nextroom.js | 46 +++++---- src/config.js | 19 ++-- src/diplomacy.js | 12 ++- src/logging.js | 6 ++ src/prototype_creep.js | 4 +- src/prototype_creep_resources.js | 90 ------------------ src/prototype_creep_startup_tasks.js | 6 +- src/prototype_room_external.js | 31 ++++-- src/quests.js | 62 ++++++++++-- src/role_builder.js | 2 - src/role_carry.js | 136 ++++++++++++++++++++++++++- src/role_mineral.js | 48 ++++++++++ src/role_quester.js | 2 +- src/role_reserver.js | 4 +- utils/testConfig.js | 2 +- 21 files changed, 341 insertions(+), 156 deletions(-) diff --git a/doc/API.md b/doc/API.md index 088938b1e..448298bcd 100644 --- a/doc/API.md +++ b/doc/API.md @@ -38,7 +38,7 @@ The sign has the format: "type": "quest", "id": "QUEST_ID", "origin": "ROOM_NAME", - "info": "http://tooangel.github.io/screeps", + "info": "http://tooangel.github.io/screeps" } ``` @@ -48,6 +48,7 @@ To apply for a Quest send a message via terminal transfer to the `origin` room, { "type": "quest", "id": "QUEST_ID", + "action": "apply" } ``` @@ -58,7 +59,6 @@ The actual quest will be send to the room the transfer was initiated from. Quests can be received from the TooAngel NPC and also send to the TooAngel NPC. When quests are solved the reputation increases. When quests are send to the TooAngel NPC the reputation is decreased. -In case quests are requested from the TooAngel NPC, while the reputation is too low, these are not executed and a portion is still reduced as a arrogance (TODO maybe find a better word) fee. ### Quest format @@ -69,7 +69,7 @@ Quests are send via terminal transfer: "type": "quest", "id": "QUEST_ID", "room": "ROOM_NAME, in which the quest needs to be solved", - "type": "TYPE OF QUEST", + "quest": "TYPE OF QUEST", "end": "Game.time when the quest needs to be finished" } ``` @@ -85,6 +85,6 @@ Internally the reputation is increased. { "type": "quest", "id": "QUEST_ID", - "result": "won", + "result": "won" }; ``` \ No newline at end of file diff --git a/doc/BaseBuilding.md b/doc/BaseBuilding.md index b6e27993c..cbf3c040d 100644 --- a/doc/BaseBuilding.md +++ b/doc/BaseBuilding.md @@ -1,6 +1,6 @@ -## Room +# Room -### Setup +## Setup Positions: - `upgrader` creep next to the `controller` @@ -15,3 +15,10 @@ extension, lab, observer, terminal, tower) next to it. Next to `filler` a link, tower and power_spawn is located. `Link`s are placed next to the sources and at the paths to the exits. Layers of walls are placed at the exits, positions within the precalculated paths are replaced by ramparts. + +## Pathing + +Paths are precalculated and cached and reused by most of the creeps. + +Swamps are ignored because roads will be built automatically over time. +The creeps only move on the precalculated paths (to reduce complexity). Instead, blockers are recognized and `structurer` are sent to destroy the structure, `carry` creeps try it as well. \ No newline at end of file diff --git a/docker-compose-setup.yml b/docker-compose-setup.yml index d7f08480a..5656649ca 100644 --- a/docker-compose-setup.yml +++ b/docker-compose-setup.yml @@ -8,6 +8,8 @@ services: command: redis-server --loglevel warning mongo: image: mongo + volumes: + - ./tmp-test-server-database/:/data/db ports: - 27017:27017 command: mongod --quiet --logpath /dev/null diff --git a/docker-compose.yml b/docker-compose.yml index a270b4042..97a1c211d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,6 +8,8 @@ services: command: redis-server --loglevel warning mongo: image: mongo + volumes: + - ./tmp-test-server-database/:/data/db ports: - 27017:27017 command: mongod --quiet --logpath /dev/null diff --git a/package-lock.json b/package-lock.json index 934540bdb..88f5748a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "screeps-bot-tooangel", - "version": "1.4.2", + "version": "1.4.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 990ea658d..2502ea380 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "screeps-bot-tooangel", - "version": "1.4.2", + "version": "1.4.3", "description": "", "main": "src/main.js", "screeps_bot": true, diff --git a/src/brain_nextroom.js b/src/brain_nextroom.js index ed583fec7..32da2892b 100644 --- a/src/brain_nextroom.js +++ b/src/brain_nextroom.js @@ -75,44 +75,58 @@ function getNextRoomValuatedRoomMap(rooms) { return evaluatedRooms; } -brain.handleNextroomer = function() { - if (!Memory.myRooms) { - return; - } - if (Memory.myRooms.length >= Game.gcl.level) { - return; - } - if (Game.time % config.nextRoom.intervalToCheck !== 0) { - return; - } - debugLog('nextroomer', 'handleNextroomer !!!!!!!!!!!!!!!!!!!!!!!'); +/** + * haveEnoughSystemResources + * + * @return {bool} + */ +function haveEnoughSystemResources() { if (config.nextRoom.resourceStats) { debugLog('nextroomer', `stats: ${JSON.stringify(global.stats)}`); const myRoomsLength = Memory.myRooms.length; const cpuPerRoom = global.stats.cpuUsed / myRoomsLength; if (cpuPerRoom > global.stats.cpuIdle) { debugLog('nextroomer', `not enough cpu: ${cpuPerRoom} > ${global.stats.cpuIdle}`); - return; + return false; } const heapPerRoom = global.stats.heapUsed / myRoomsLength; if (heapPerRoom > global.stats.heapFree) { debugLog('nextroomer', `not enough heap: ${heapPerRoom} > ${global.stats.heapFree}`); - return; + return false; } const memoryPerRoom = global.stats.memoryUsed / myRoomsLength; if (memoryPerRoom > global.stats.memoryFree) { debugLog('nextroomer', `not enough heap: ${memoryPerRoom} > ${global.stats.memoryFree}`); - return; + return false; } } else { if (Memory.myRooms.length >= 0) { // config.nextRoom.maxRooms) { - return; + return false; } if ((Memory.myRooms.length + 1) * config.nextRoom.cpuPerRoom >= Game.cpu.limit) { - return; + return false; } } + return true; +} + +brain.handleNextroomer = function() { + if (!Memory.myRooms) { + return; + } + if (Memory.myRooms.length >= Game.gcl.level) { + return; + } + if (Game.time % config.nextRoom.intervalToCheck !== 0) { + return; + } + + debugLog('nextroomer', 'handleNextroom !!!!!!!!!!!!!!!!!!!!!!!'); + if (!haveEnoughSystemResources()) { + return; + } + debugLog('nextroomer', 'handleNextroomer'); diff --git a/src/config.js b/src/config.js index fb0d81a09..017170d79 100644 --- a/src/config.js +++ b/src/config.js @@ -182,7 +182,6 @@ global.config = { }, external: { - distance: 2, defendDistance: 1, checkForReservingInterval: 1499, }, @@ -222,15 +221,15 @@ global.config = { room: { reservedRCL: { - 0: 1, - 1: 1, - 2: 1, - 3: 1, - 4: 1, - 5: 1, - 6: 2, - 7: 2, - 8: 2, + 0: 4, + 1: 4, + 2: 4, + 3: 4, + 4: 4, + 5: 4, + 6: 4, + 7: 8, + 8: 8, }, isHealthyStorageThreshold: 50000, handleNukeAttackInterval: 132, diff --git a/src/diplomacy.js b/src/diplomacy.js index d3ba6bac9..ef3981277 100644 --- a/src/diplomacy.js +++ b/src/diplomacy.js @@ -49,7 +49,7 @@ function checkPlayers() { module.exports.checkPlayers = checkPlayers; const findRoomPairs = function(player) { - for (const roomName of Object.keys(player.rooms).sort((a, b) => 0.5 - Math.random())) { + for (const roomName of Object.keys(player.rooms).sort(() => 0.5 - Math.random())) { debugLog('diplomacy', `findRoomPairs: room ${roomName} data: ${JSON.stringify(global.data.rooms[roomName])}`); const minRCL = ((global.data.rooms[roomName] || {}).controller || {}).level || 8; const range = 7; @@ -123,7 +123,7 @@ function handleRetaliation(player) { debugLog('diplomacy', `handleRetaliation: Can not find a fitting room pair`); return; } - possibleActions.sort((a, b) => 0.5 - Math.random()); + possibleActions.sort(() => 0.5 - Math.random()); debugLog('diplomacy', `Running attach roomPair: ${JSON.stringify(roomPair)} action: ${JSON.stringify(possibleActions[0])}`); player.lastAttacked = Game.time; if (config.autoAttack.notify) { @@ -166,7 +166,9 @@ function addToReputation(name, value) { try { handleRetaliation(player); } catch (e) { + console.log('addToReputation'); console.log(e); + console.log(e.stack); } } } @@ -193,6 +195,12 @@ function initPlayer(name) { } module.exports.initPlayer = initPlayer; +/** + * addRoomToPlayer + * + * @param {object} player + * @param {object} room + */ function addRoomToPlayer(player, room) { if (!player.rooms) { player.rooms = {}; diff --git a/src/logging.js b/src/logging.js index 2d54f21be..11a9938b3 100644 --- a/src/logging.js +++ b/src/logging.js @@ -1,3 +1,9 @@ +/** + * debugLog + * + * @param {string} type + * @param {...string} messages + */ function debugLog(type, ...messages) { if (config.debug[type]) { console.log(`${Game.time} ${messages.join(' ')}`); diff --git a/src/prototype_creep.js b/src/prototype_creep.js index e12e4344e..276a3f4a4 100644 --- a/src/prototype_creep.js +++ b/src/prototype_creep.js @@ -51,14 +51,12 @@ Creep.prototype.mySignController = function() { if (config.quests.enabled && this.memory.role === 'reserver' && Game.rooms[this.memory.base].terminal) { if (Math.random() < config.quests.signControllerPercentage) { const quest = { + type: 'quest', id: Math.floor(Math.random() * 100000), origin: this.memory.base, - end: Math.floor(Game.time / 100) * 100 + config.quests.endTime, - type: 'Quest', info: 'http://tooangel.github.io/screeps', }; text = JSON.stringify(quest); - // Memory.quests[quest.id] = quest; this.room.debugLog('quests', `Attach quest: ${text}`); } } diff --git a/src/prototype_creep_resources.js b/src/prototype_creep_resources.js index 5181a4f7c..59df74984 100644 --- a/src/prototype_creep_resources.js +++ b/src/prototype_creep_resources.js @@ -52,49 +52,6 @@ Creep.prototype.checkCarryEnergyForBringingBackToStorage = function(otherCreep) return offset + this.store.getUsedCapacity() > carryPercentage * this.store.getCapacity(); }; -// return true if helper can't transfer to creep -Creep.prototype.checkHelperNoTransfer = function(creep) { - return creep.memory.base !== this.memory.base; -}; - -Creep.prototype.findCreepWhichCanTransfer = function(creeps) { - for (let i = 0; i < creeps.length; i++) { - const otherCreep = creeps[i]; - if (!Game.creeps[otherCreep.name] || otherCreep.store.getUsedCapacity() < 50 || otherCreep.memory.recycle) { - continue; - } - - if (otherCreep.memory.role === 'carry') { - if (otherCreep.checkHelperNoTransfer(this)) { - continue; - } - if (otherCreep.memory.routing.pathPos < 0) { - continue; - } - return this.checkCarryEnergyForBringingBackToStorage(otherCreep); - } - continue; - } - return false; -}; - -Creep.prototype.checkForTransfer = function(direction) { - if (!direction) { - this.creepLog(`checkForTransfer no direction}`); - return false; - } - - const adjacentPos = this.pos.getAdjacentPosition(direction); - - if (adjacentPos.isBorder(-2)) { - this.creepLog(`checkForTransfer isBorder}`); - return false; - } - - const creeps = adjacentPos.lookFor(LOOK_CREEPS); - return this.findCreepWhichCanTransfer(creeps); -}; - Creep.prototype.pickupWhileMoving = function() { if (this.inBase() && this.memory.routing.pathPos < 2) { return false; @@ -225,53 +182,6 @@ Creep.prototype.pickupEnergy = function() { return this.giveSourcersEnergy(); }; -const checkCreepForTransfer = function(otherCreep, thisCreep) { - if (!Memory.creeps[otherCreep.name]) { - return false; - } - // don't transfer to extractor, fixes full terminal with 80% energy? - if (Memory.creeps[otherCreep.name].role === 'extractor') { - return false; - } - // don't transfer to mineral, fixes full terminal with 80% energy? - if (Memory.creeps[otherCreep.name].role === 'mineral') { - return false; - } - if (!thisCreep.store[RESOURCE_ENERGY] && Memory.creeps[otherCreep.name].role === 'sourcer') { - return false; - } - // Do we want this? - if (Memory.creeps[otherCreep.name].role === 'powertransporter') { - return false; - } - if (otherCreep.store.getFreeCapacity() === 0) { - return false; - } - return true; -}; - -Creep.prototype.transferToCreep = function(direction) { - const adjacentPos = this.pos.getAdjacentPosition(direction); - if (!adjacentPos.isValid()) { - return false; - } - - const creeps = adjacentPos.lookFor('creep'); - for (let i = 0; i < creeps.length; i++) { - const otherCreep = creeps[i]; - if (!checkCreepForTransfer(otherCreep, this) || this.checkHelperNoTransfer(otherCreep)) { - continue; - } - for (const resource of Object.keys(this.store)) { - const returnCode = this.transfer(otherCreep, resource); - if (returnCode === OK) { - return this.store.getUsedCapacity() * 0.5 <= otherCreep.store.getCapacity() - otherCreep.store.getUsedCapacity(); - } - } - } - return false; -}; - const canStoreEnergy = function(object) { const structureTypes = [STRUCTURE_CONTROLLER, STRUCTURE_ROAD, STRUCTURE_WALL, STRUCTURE_RAMPART, STRUCTURE_OBSERVER]; if (structureTypes.indexOf(object.structureType) >= 0) { diff --git a/src/prototype_creep_startup_tasks.js b/src/prototype_creep_startup_tasks.js index e098f6550..73c8eaa1f 100644 --- a/src/prototype_creep_startup_tasks.js +++ b/src/prototype_creep_startup_tasks.js @@ -165,7 +165,11 @@ Creep.prototype.getEnergyFromStorage = function() { return false; } - if (!this.room.memory.misplacedSpawn && this.room.isStruggling()) { + if (this.room.memory.misplacedSpawn) { + return false; + } + + if (this.room.isStruggeling()) { return false; } diff --git a/src/prototype_room_external.js b/src/prototype_room_external.js index bc224bd68..647fd4a8c 100644 --- a/src/prototype_room_external.js +++ b/src/prototype_room_external.js @@ -90,7 +90,7 @@ Room.prototype.checkForQuest = function() { this.log(`checkForQuest no type: ${JSON.stringify(data)}`); return; } - if (data.type !== 'Quest') { + if (data.type !== 'quest') { this.log(`checkForQuest type not quest: ${JSON.stringify(data)}`); return; } @@ -108,9 +108,9 @@ Room.prototype.checkForQuest = function() { continue; } const response = { - type: 'Quest', + type: 'quest', id: data.id, - room: this.name, + action: 'apply', }; this.log(`checkForQuest apply for quest from ${room.name} to ${data.origin} ${JSON.stringify(response)}`); const terminalResponse = room.terminal.send(RESOURCE_ENERGY, 100, data.origin, JSON.stringify(response)); @@ -511,6 +511,7 @@ function isRouteValidForReservedRoom(room, route) { return false; } if (!routeRoom.isMy() && routeRoom.data.state !== 'Reserved') { + room.debugLog('reserver', `Not reserverd ${routeRoom.name} ${JSON.stringify(routeRoom.data.state)} ${JSON.stringify(routeRoom.data.reservation)}`); return false; } } @@ -530,10 +531,10 @@ function filterReservedBy(roomName) { } Room.prototype.handleUnreservedRoom = function() { - this.data.state = 'Unreserved'; if (this.isRoomRecentlyChecked()) { return false; } + this.data.state = 'Unreserved'; this.debugLog('reserver', 'handleUnreservedRoom'); if (this.data.reservation) { @@ -556,14 +557,26 @@ Room.prototype.handleUnreservedRoom = function() { continue; } const distance = Game.map.getRoomLinearDistance(this.name, room.name); - this.debugLog('reserver', `unreserved check linear Distance: ${distance} <= ${config.external.distance} ${this.name} ${room.name}`); - if (distance > config.external.distance) { + /** + * Base reservability on number of spawns, distance and number of sources + * + * sources: 1, distance: 1, spawns: 1 = 1 fine + * sources: 1, distance: 2, spawns: 1 = 0.5 not fine + * sources: 2, distance: 2, spawns: 1 = 1 fine + * sources: 1, distance: 2, spawns: 2 = 1 fine + * + */ + const spawns = room.find(FIND_MY_SPAWNS).length; + const threshold = this.data.sources / distance * spawns; + this.debugLog('reserver', `unreserved check linear Distance: ${threshold} <= ${this.data.sources} ${distance} ${spawns} ${this.name} ${room.name}`); + if (threshold < 1) { continue; } const route = Game.map.findRoute(this.name, room.name); const routeDistance = route.length; - this.debugLog('reserver', `unreserved check route Distance: ${routeDistance} <= ${config.external.distance} ${this.name} ${room.name}`); - if (routeDistance > config.external.distance) { + const routeThreshold = this.data.sources / routeDistance * spawns; + this.debugLog('reserver', `unreserved check route Distance: ${routeThreshold} <= ${this.data.sources} ${routeDistance} ${spawns} ${this.name} ${room.name}`); + if (routeThreshold < 1) { continue; } @@ -574,6 +587,8 @@ Room.prototype.handleUnreservedRoom = function() { const reservedRooms = _.filter(global.data.rooms, filterReservedBy(roomName)); // RCL: target reserved rooms + + // TODO Store `spawnIdle` and base on that const numRooms = config.room.reservedRCL; this.debugLog('reserver', `number checked: ${reservedRooms.length} ${numRooms[room.controller.level]}`); if (reservedRooms.length >= numRooms[room.controller.level]) { diff --git a/src/quests.js b/src/quests.js index 024c01a23..504132826 100644 --- a/src/quests.js +++ b/src/quests.js @@ -2,6 +2,9 @@ const {debugLog} = require('./logging'); +/** + * handleQuests + */ function handleQuests() { Memory.quests = Memory.quests || {}; for (const id of Object.keys(Memory.quests)) { @@ -22,6 +25,12 @@ function handleQuests() { module.exports.handleQuests = handleQuests; +/** + * getQuestBuildConstructionSite + * + * @param {object} data + * @return {object} + */ function getQuestBuildConstructionSite(data) { const quest = {}; quest.room = data.room; @@ -31,6 +40,13 @@ function getQuestBuildConstructionSite(data) { return quest; } +/** + * getQuest + * + * @param {object} transaction + * @param {object} data + * @return {object} + */ function getQuest(transaction, data) { const info = {}; info.id = data.id; @@ -49,14 +65,17 @@ function getQuest(transaction, data) { return info; } - +/** + * haveActiveQuest + * + * @return {bool} + */ function haveActiveQuest() { - debugLog('quests', `haveActiveQuest global.data.activeQuest: ${JSON.stringify(global.data.activeQuest)}`); if (!global.data.activeQuest) { return false; } if (global.data.activeQuest.state === 'applied' && - global.data.activeQuest.tick + 10 < Game.time) { + global.data.activeQuest.tick + 10 < Game.time) { debugLog('quests', 'Applied but too old'); delete global.data.activeQuest; return false; @@ -70,6 +89,12 @@ function haveActiveQuest() { module.exports.haveActiveQuest = haveActiveQuest; +/** + * getQuestFromTransactionDescription + * + * @param {object} description + * @return {bool} + */ function getQuestFromTransactionDescription(description) { let data; try { @@ -83,19 +108,29 @@ function getQuestFromTransactionDescription(description) { return false; } console.log(JSON.stringify(data)); - for (const key of ['type', 'room', 'id']) { + for (const key of ['type', 'action', 'id']) { if (!data[key]) { debugLog('quests', `Incoming transaction no Quest: No ${key}`); return false; } } - if (data.type !== 'Quest') { + if (data.type !== 'quest') { + debugLog('quests', 'Quest transaction: Type not quest'); + return false; + } + if (data.action !== 'apply') { debugLog('quests', 'Quest transaction: Type not quest'); return false; } return data; } +/** + * checkQuestForAcceptance + * + * @param {object} transaction + * @return {bool} + */ function checkQuestForAcceptance(transaction) { Memory.quests = Memory.quests || {}; const data = getQuestFromTransactionDescription(transaction.description); @@ -112,7 +147,7 @@ function checkQuestForAcceptance(transaction) { Memory.quests[data.id] = quest; const response = { - type: 'Accept', + type: 'quest', id: quest.id, room: quest.room, quest: quest.quest, @@ -127,13 +162,24 @@ function checkQuestForAcceptance(transaction) { module.exports.checkQuestForAcceptance = checkQuestForAcceptance; +/** + * checkAppliedQuestForAcceptance + * + * @param {object} transaction + * @return {bool} + */ function checkAppliedQuestForAcceptance(transaction) { try { const response = JSON.parse(transaction.description); if (!response.type) { debugLog('quests', `No type: ${JSON.stringify(response)}`); } - if (response.type !== 'Accept') { + if (response.type !== 'quest') { + debugLog('quests', `Wrong type: ${JSON.stringify(response)}`); + return false; + } + if (response.action) { + debugLog('quests', `Action exist type: ${JSON.stringify(response)}`); return false; } debugLog('quests', `Quest accept transaction: ${JSON.stringify(response)}`); @@ -145,7 +191,9 @@ function checkAppliedQuestForAcceptance(transaction) { global.data.activeQuest.accept = response; debugLog('quests', `activeQuest: ${JSON.stringify(global.data.activeQuest)}`); } catch (e) { + console.log('checkAppliedQuestForAcceptance'); console.log(e); + console.log(e.stack); return false; } } diff --git a/src/role_builder.js b/src/role_builder.js index 149255676..62e763f47 100644 --- a/src/role_builder.js +++ b/src/role_builder.js @@ -22,8 +22,6 @@ roles.builder.action = function(creep) { if (creep.room.memory.misplacedSpawn) { methods.push(Creep.transferEnergy); methods.push(Creep.repairStructure); - } else { - methods.push(Creep.recycleCreep); } methods.push(Creep.upgradeControllerTask); diff --git a/src/role_carry.js b/src/role_carry.js index 0719c2095..f472cf091 100644 --- a/src/role_carry.js +++ b/src/role_carry.js @@ -44,7 +44,13 @@ roles.carry.updateSettings = function(room, creep) { } }; -roles.carry.checkHelperEmptyStorage = function(creep) { +/** + * checkHelperEmptyStorage + * + * @param {object} creep + * @return {void} + */ +function checkHelperEmptyStorage(creep) { // Fix blocked helpers due to empty structure in the room where we get the energy from if (creep.room.name === creep.memory.routing.targetRoom) { const targetStructure = Game.getObjectById(creep.memory.routing.targetId); @@ -61,7 +67,7 @@ roles.carry.checkHelperEmptyStorage = function(creep) { } } } -}; +} /** * checkForUniversalSpawn @@ -124,6 +130,70 @@ const validateDirections = function(creep, directions) { return true; }; + +const checkCreepForTransfer = function(otherCreep, thisCreep) { + if (!otherCreep.my) { + return false; + } + // Don't transfer to carries if they didn't reached the end once + if (otherCreep.memory.role === 'carry' && !otherCreep.data.fullyDeployed) { + return false; + } + + // Only transfer to creeps with the same base + if (otherCreep.memory.base !== thisCreep.memory.base) { + return false; + } + + // don't transfer to extractor, fixes full terminal with 80% energy? + if (otherCreep.memory.role === 'extractor') { + return false; + } + // don't transfer to mineral, fixes full terminal with 80% energy? + if (otherCreep.memory.role === 'mineral') { + return false; + } + if (!thisCreep.store[RESOURCE_ENERGY] && otherCreep.memory.role === 'sourcer') { + return false; + } + // Do we want this? + if (otherCreep.memory.role === 'powertransporter') { + return false; + } + if (otherCreep.store.getFreeCapacity() === 0) { + return false; + } + return true; +}; + +/** + * transferToCreep + * + * @param {object} creep + * @param {object} direction + * @return {bool} + */ +function transferToCreep(creep, direction) { + const adjacentPos = creep.pos.getAdjacentPosition(direction); + if (!adjacentPos.isValid()) { + return false; + } + + const creeps = adjacentPos.lookFor('creep'); + for (const otherCreep of creeps) { + if (!checkCreepForTransfer(otherCreep, creep)) { + continue; + } + for (const resource of Object.keys(creep.store)) { + const returnCode = creep.transfer(otherCreep, resource); + if (returnCode === OK) { + return creep.store.getUsedCapacity() * 0.5 <= otherCreep.store.getCapacity() - otherCreep.store.getUsedCapacity(); + } + } + } + return false; +} + /** * transferToCreeps * @@ -132,7 +202,7 @@ const validateDirections = function(creep, directions) { */ function transferToCreeps(creep, directions) { creep.creepLog('Trying to transfer to creep'); - const transferred = creep.transferToCreep(directions.backwardDirection); + const transferred = transferToCreep(creep, directions.backwardDirection); creep.memory.routing.reverse = !transferred; } @@ -149,6 +219,60 @@ function getMoveToStorage(creep) { return moveToStorage; } +/** + * findCreepWhichCanTransfer + * + * @param {object} creep + * @param {object} adjacentPos + * @return {bool} + */ +function findCreepWhichCanTransfer(creep, adjacentPos) { + const creeps = adjacentPos.lookFor(LOOK_CREEPS); + for (const otherCreep of creeps) { + if (!Game.creeps[otherCreep.name] || otherCreep.store.getUsedCapacity() < 50 || otherCreep.memory.recycle) { + continue; + } + + if (otherCreep.memory.role === 'carry') { + if (creep.memory.base !== otherCreep.memory.base) { + continue; + } + if (otherCreep.memory.routing.pathPos < 0) { + continue; + } + return creep.checkCarryEnergyForBringingBackToStorage(otherCreep); + } + continue; + } + return false; +} + +/** + * checkForTransfer + * + * @param {object} creep + * @param {object} direction + * @return {bool} + */ +function checkForTransfer(creep, direction) { + if (!creep.data.fullyDeployed) { + return false; + } + if (!direction) { + creep.creepLog(`checkForTransfer no direction}`); + return false; + } + + const adjacentPos = creep.pos.getAdjacentPosition(direction); + + if (adjacentPos.isBorder(-2)) { + creep.creepLog(`checkForTransfer isBorder}`); + return false; + } + + return findCreepWhichCanTransfer(creep, adjacentPos); +} + /** * preMoveNotMoveToStorage * @@ -164,7 +288,7 @@ function preMoveNotMoveToStorage(creep, directions) { moveToStorage = creep.pickupEnergy(); moveToStorage = moveToStorage || creep.pickupWhileMoving(); } - const energyFromCreep = creep.checkForTransfer(directions.forwardDirection); + const energyFromCreep = checkForTransfer(creep, directions.forwardDirection); moveToStorage = moveToStorage || energyFromCreep; return moveToStorage; } @@ -174,7 +298,7 @@ roles.carry.preMove = function(creep, directions) { return false; } - roles.carry.checkHelperEmptyStorage(creep); + checkHelperEmptyStorage(creep); let moveToStorage = getMoveToStorage(creep); if (moveToStorage) { @@ -214,6 +338,8 @@ roles.carry.preMove = function(creep, directions) { creep.memory.routing.reverse = moveToStorage; if (moveToStorage) { directions.direction = directions.backwardDirection; + // TODO this makes sure that we first move to the end before other creeps transfer to this + creep.data.fullyDeployed = true; } else { directions.direction = directions.forwardDirection; } diff --git a/src/role_mineral.js b/src/role_mineral.js index 07cad466b..9d5068a95 100644 --- a/src/role_mineral.js +++ b/src/role_mineral.js @@ -538,6 +538,12 @@ const execute = function(creep) { // ---------------------- NEW ------------------------- +/** + * setStateFillTowers + * + * @param {object} creep + * @return {bool} + */ function setStateFillTowers(creep) { const towers = creep.room.findTowers(); const fillableTower = towers.find((tower) => tower.store.getFreeCapacity(RESOURCE_ENERGY) > 0); @@ -553,6 +559,12 @@ function setStateFillTowers(creep) { return true; } +/** + * setStateFillTerminalEnergy + * + * @param {object} creep + * @return {bool} + */ function setStateFillTerminalEnergy(creep) { if (creep.room.terminal.store.energy > config.terminal.minEnergyAmount) { return false; @@ -566,6 +578,12 @@ function setStateFillTerminalEnergy(creep) { return true; } +/** + * setStateGetEnergyFromTerminal + * + * @param {object} creep + * @return {bool} + */ function setStateGetEnergyFromTerminal(creep) { if (creep.room.terminal.store.energy < config.terminal.maxEnergyAmount) { return false; @@ -580,6 +598,12 @@ function setStateGetEnergyFromTerminal(creep) { } +/** + * setStateEmptyCreepStore + * + * @param {object} creep + * @return {bool} + */ function setStateEmptyCreepStore(creep) { if (creep.store.getUsedCapacity() === 0) { return false; @@ -590,6 +614,12 @@ function setStateEmptyCreepStore(creep) { return true; } +/** + * setStateFillLabsWithEnergy + * + * @param {object} creep + * @return {bool} + */ function setStateFillLabsWithEnergy(creep) { const labs = creep.room.findLabs(); const fillableLab = labs.find((lab) => lab.store.getFreeCapacity(RESOURCE_ENERGY) > 0); @@ -605,6 +635,12 @@ function setStateFillLabsWithEnergy(creep) { return true; } +/** + * setStateTransferResourcesToTerminal + * + * @param {object} creep + * @return {bool} + */ function setStateTransferResourcesToTerminal(creep) { if (!Object.keys(creep.room.storage.store).find((resource) => resource !== RESOURCE_ENERGY)) { return false; @@ -618,6 +654,12 @@ function setStateTransferResourcesToTerminal(creep) { return true; } +/** + * setState + * + * @param {object} creep + * @return {bool} + */ function setState(creep) { if (setStateEmptyCreepStore(creep)) { return true; @@ -640,6 +682,12 @@ function setState(creep) { return false; } +/** + * handleState + * + * @param {object} creep + * @return {bool} + */ function handleState(creep) { if (!creep.data.state) { if (!setState(creep)) { diff --git a/src/role_quester.js b/src/role_quester.js index d4f1453cf..afdc95797 100644 --- a/src/role_quester.js +++ b/src/role_quester.js @@ -27,7 +27,7 @@ roles.quester.questWon = function(creep, quest) { creep.log(`Quest won: ${JSON.stringify(quest)}`); const response = { - type: 'Quest', + type: 'quest', id: quest.id, result: 'won', }; diff --git a/src/role_reserver.js b/src/role_reserver.js index 56c9944b0..baa29454d 100644 --- a/src/role_reserver.js +++ b/src/role_reserver.js @@ -17,7 +17,7 @@ roles.reserver.settings = { maxLayoutAmount: 1, }; roles.reserver.updateSettings = function(room, creep) { - room.debugLog('reserver', `role_reserver.updateSettings; targetRoom: ${creep.routing.targetRoom}`); + // room.debugLog('reserver', `role_reserver.updateSettings; targetRoom: ${creep.routing.targetRoom}`); const targetRoom = Game.rooms[creep.routing.targetRoom]; if (targetRoom) { const reservation = targetRoom.controller.reservation; @@ -33,7 +33,7 @@ roles.reserver.updateSettings = function(room, creep) { }; } } - room.debugLog('reserver', `role_reserver.updateSettings - Can not access targetRoom ${targetRoom}`); + // room.debugLog('reserver', `role_reserver.updateSettings - Can not access targetRoom ${targetRoom}`); return { maxLayoutAmount: 1, }; diff --git a/utils/testConfig.js b/utils/testConfig.js index 95c865c2e..31acc043d 100644 --- a/utils/testConfig.js +++ b/utils/testConfig.js @@ -8,7 +8,7 @@ module.exports.tickDuration = 10; // if your machine is slow try increment this module.exports.waitForConnection = 10; -module.exports.playerRoom = 'W7N4'; +module.exports.playerRoom = 'W1N7'; const players = { 'W1N7': {x: 43, y: 35}, 'W8N8': {x: 21, y: 28},