require('globals') const EMERGENCY_MODE_TIMEOUT = 100 function getHarvestingSpots (source) { let spots = [] let terrain = source.room.getTerrain() 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]) } } } source.room.memory.harvestingSpots[source.id] = spots return spots } function getBodyCost(body) { let cost = 0 for (let part of body) { cost = cost + BODYPART_COST[part] } return cost } module.exports = { tickInit () { for (let room of Object.values(Game.rooms)) { if (!room.memory.harvestingSpots) { room.memory.harvestingSpots = {} } if (!room.memory.spawnIdle) { room.memory.spawnIdle = 0 } if (!room.memory.energyIncreasedAt) { room.memory.energyIncreasedAt = Game.time } 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.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 } } } } }, tick (spawn) { let minRoleCount 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 + ' ' + room, spawn.pos.x + 1, spawn.pos.y, {align: 'left', opacity: 0.8}); } else { let newCreep, prio for (let [roleName, role] of Object.entries(ROLES)) { let roleCreeps = _.filter(Game.creeps, {memory: {role: roleName, colony: spawn.room.name}}); if (minRoleCount === undefined || minRoleCount > roleCreeps.length) { minRoleCount = roleCreeps.length } if (roleCreeps.length > 0 && spawn.room.memory.emergency && spawn.room.energyAvailable < spawn.room.energyCapacityAvailable) { continue } let newName = roleName + Game.time; let body = [] 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 = 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) { continue } for (let harvester of sourceHarvesters) { if (harvester.ticksToLive > harvester.body.length * 3 + source.room.memory.sourcesData[source.id].spawnDistance) { harvestingCapacity += harvester.getActiveBodyparts(WORK) * 2 * 300 } } 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 } else { break } } } } } 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)) { body = b } else { break } } } else { 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( `Next: ${newCreep[1]}`, spawn.pos.x + 1, spawn.pos.y, {align: 'left', opacity: 0.8, size: 0.3}); 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]) } }*/ } }, }