|
|
|
|
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++) {
|
|
|
|
|
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.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}
|
|
|
|
|
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];
|
|
|
|
|
spawn.room.visual.text(
|
|
|
|
|
'🛠️' + spawningCreep.memory.role,
|
|
|
|
|
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, (creep) => creep.memory.role === roleName);
|
|
|
|
|
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}
|
|
|
|
|
if (roleName === 'harvester') {
|
|
|
|
|
for (let source of spawn.room.find(FIND_SOURCES)) {
|
|
|
|
|
let spots = getHarvestingSpots(source)
|
|
|
|
|
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 ROLES.harvester.bodies) {
|
|
|
|
|
if (getBodyCost(b) <= (spawn.room.memory.emergency ? spawn.room.energyAvailable : spawn.room.energyCapacityAvailable)) {
|
|
|
|
|
body = b
|
|
|
|
|
memory.source = source.id
|
|
|
|
|
} else {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (roleCreeps.length < 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 && (!prio || role.prio * (roleCreeps.length + 1) < prio)) {
|
|
|
|
|
newCreep = [body, newName, {memory}]
|
|
|
|
|
prio = role.prio * (roleCreeps.length + 1)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (newCreep) {
|
|
|
|
|
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 (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});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|