You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
11 KiB
JavaScript
267 lines
11 KiB
JavaScript
const { sum } = require("lodash");
|
|
|
|
const ROLE_IDENT = "Harv";
|
|
|
|
const STATE_INIT = 0;
|
|
const STATE_GOING_TO_SOURCE = 1;
|
|
const STATE_HARVESTING = 2;
|
|
const STATE_GOING_TO_DESTINATION = 3;
|
|
const STATE_DELIVERING = 4;
|
|
|
|
var roleHarvester = {
|
|
|
|
ROLE_IDENT: ROLE_IDENT,
|
|
|
|
minimum_parts: [WORK, MOVE, CARRY],
|
|
recommended_parts: [WORK, MOVE, CARRY],
|
|
min_cost: sum([BODYPART_COST["work"], BODYPART_COST["move"], BODYPART_COST["carry"]]),
|
|
|
|
/**
|
|
* Orders the given spawn to create a creep fitting for this role according to the recommended_parts and if impossible use minimum_parts instead
|
|
* @param {spawn} spawn
|
|
* @param {string} postfix string to postfix to the creep
|
|
* @param {string} owner_id strind id of who shall be entered as owner of the new creep
|
|
*
|
|
* @return {string} name of the new creep
|
|
*/
|
|
spawn: function(spawn, postfix, owner_id) {
|
|
let creep_name = "harvester-"+postfix;
|
|
if (spawn.spawnCreep(this.recommended_parts, creep_name, {dryRun: true}) === OK) {
|
|
console.log("roleHarvester: Spawn "+spawn.name+" is creating "+creep_name+" with recommended parts ...");
|
|
spawn.spawnCreep(this.recommended_parts, creep_name, {memory: {"owner": owner_id, "role": ROLE_IDENT}});
|
|
}
|
|
else if (spawn.spawnCreep(this.minimum_parts, creep_name, {dryRun: true}) === OK) {
|
|
console.log("roleHarvester: Spawn "+spawn.name+" is creating "+creep_name+" with minimum parts ...");
|
|
spawn.spawnCreep(this.minimum_parts, creep_name, {memory: {"owner": owner_id, "role": ROLE_IDENT}});
|
|
}
|
|
else {
|
|
console.log("roleHarvester: Spawn \""+spawn.name+"\" couldn't afford a harvester! D: Result: ", spawn.spawnCreep(this.minimum_parts, creep_name, {dryRun: true}));
|
|
throw "Not enough energy!";
|
|
}
|
|
|
|
Memory.creeps[creep_name].harvest_spot = {
|
|
id: null,
|
|
resource_type: null,
|
|
structure_pos: null,
|
|
goto_pos: null,
|
|
};
|
|
Memory.creeps[creep_name].destination_spot = {
|
|
id: null,
|
|
structure_pos: null,
|
|
goto_pos: null,
|
|
};
|
|
|
|
return creep_name;
|
|
},
|
|
|
|
/**
|
|
* Checks if the creep has all the parts necessary to work its role
|
|
* @param {Creep} creep
|
|
* @return bool that indicates if the creep can fullfill its role
|
|
*/
|
|
can_work: function(creep) {
|
|
if (creep.getActiveBodyparts(MOVE) >= 1 && creep.getActiveBodyparts(WORK) >= 1 && creep.getActiveBodyparts(CARRY) >= 1) {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* Checks if the creep has been set to this role. This does not include a check of their body parts.
|
|
* @param {Creep} creep
|
|
*/
|
|
is_harvester: function(creep) {
|
|
if (creep.memory.role === ROLE_IDENT) {
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Runs the logic and actions of the harvester
|
|
* @param {Creep} creep
|
|
*/
|
|
run: function(creep) {
|
|
if (creep.id === undefined) { // id is undefined if the creep was created this tick, should happen only once
|
|
this.switch_state(creep, STATE_INIT);
|
|
return
|
|
}
|
|
|
|
//console.log("roleHarvester ["+creep.name+"]: run() " + creep + " id:", creep.id);
|
|
|
|
// TODO implement state machine here about what the harvester is up to. Currently it only moves to the nearest source.
|
|
switch (creep.memory.state) {
|
|
case STATE_INIT:
|
|
this.init_creep(creep);
|
|
break;
|
|
case STATE_GOING_TO_SOURCE:
|
|
if (!creep.spawning) {
|
|
this.go_to_source(creep);
|
|
}
|
|
break;
|
|
case STATE_HARVESTING:
|
|
this.harvest(creep);
|
|
break;
|
|
case STATE_GOING_TO_DESTINATION:
|
|
this.go_to_destination(creep);
|
|
break;
|
|
case STATE_DELIVERING:
|
|
this.delivering(creep);
|
|
break;
|
|
default:
|
|
console.log("roleHarvester ["+creep.name+"]: run() unknown state!");
|
|
//this.switch_state(creep, STATE_INIT);
|
|
};
|
|
},
|
|
|
|
/**
|
|
* Switches the state of the creep by editing the memory
|
|
* @param {Creep} creep
|
|
* @param {int} state State constant as given (e.g. STATE_HARVESTING)
|
|
*/
|
|
switch_state: function(creep, state) {
|
|
console.log("roleHarvester ["+creep.name+"]: Changing state to "+state);
|
|
//console.log(creep, creep.memory);
|
|
creep.memory.state = state
|
|
},
|
|
|
|
/**
|
|
* Inits creep and sets the assigned source to be the nearest source.
|
|
* @param {*} creep
|
|
*/
|
|
init_creep: function(creep) { // TODO make source assignment aware of other harvesters to spread them
|
|
if (creep.memory.harvest_spot.id !== null) {
|
|
// harvest spot has already been given (by overlord?). Don't have to decide on my own!
|
|
}
|
|
else {
|
|
let room_sources = creep.room.find(FIND_SOURCES);
|
|
let goals = _.map(room_sources, function(source) {
|
|
return {pos: source.pos, range: 1};
|
|
});
|
|
let nearest_source = PathFinder.search(creep.pos, goals);
|
|
|
|
//console.log("roleHarvester ["+creep.name+"]: init_creep() remembering target position: " + nearest_source.path[nearest_source.path.length-1])
|
|
for (let source of room_sources) {
|
|
if (source.pos.isNearTo(nearest_source.path[nearest_source.path.length-1])) {
|
|
creep.memory.harvest_spot.id = source.id;
|
|
creep.memory.harvest_spot.structure_pos = source.pos;
|
|
creep.memory.harvest_spot.goto_pos = nearest_source.path[nearest_source.path.length-1];
|
|
creep.memory.harvest_spot.resource_type = RESOURCE_ENERGY;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (creep.memory.destination_spot.structure_pos !== null && creep.memory.destination_spot.goto_pos !== null) {
|
|
// destination spot has already been given (by the overlord?). Don't have to decide on my own!
|
|
}
|
|
else if (creep.memory.destination_spot.structure_pos !== null) { // goto_pos === null and we have to find it on our own later
|
|
//
|
|
}
|
|
else {
|
|
console.log("roleHarvester ["+creep.name+"] init_creep(): Don't have a destination_spot and autonomously finding one is not implemented!");
|
|
throw "No Destination spot";
|
|
}
|
|
|
|
|
|
console.log("roleHarvester ["+creep.name+"] init_creep(): harvest task has been setup and committed to memory!");
|
|
|
|
this.switch_state(creep, STATE_GOING_TO_SOURCE);
|
|
},
|
|
|
|
/**
|
|
* Moves the creep to its assigned source. The assigned source is a roomPosition in creep.memory.harvest_target_pos
|
|
* @param {Creep} creep
|
|
*/
|
|
go_to_source: function(creep) {
|
|
if (creep.memory.harvest_spot.goto_pos === null) { // find goto pos, if needed
|
|
let structure_pos = new RoomPosition(creep.memory.harvest_spot.structure_pos.x, creep.memory.harvest_spot.structure_pos.y, creep.memory.hravest_spot.structure_pos.roomName);
|
|
let result = PathFinder.search(creep.pos, {pos: structure_pos, range: 1});
|
|
creep.memory.harvest_spot.goto_pos = result.path[result.path.length-1];
|
|
}
|
|
|
|
let target_pos = new RoomPosition(creep.memory.harvest_spot.goto_pos.x, creep.memory.harvest_spot.goto_pos.y, creep.memory.harvest_spot.goto_pos.roomName);
|
|
if (creep.pos.isEqualTo(target_pos)) {
|
|
console.log("roleHarvester ["+creep.name+"]: go_to_source() arrived at target!");
|
|
this.switch_state(creep, STATE_HARVESTING);
|
|
}
|
|
|
|
//console.log("roleHarvester ["+creep.name+"]: go_to_source() moving creep towards " + target_pos);
|
|
|
|
creep.moveTo(target_pos, {visualizePathStyle: {stroke: '#ffaa00'}});
|
|
},
|
|
|
|
/**
|
|
* Lets the creep harvest its assigned source
|
|
* @param {Creep} creep
|
|
*/
|
|
harvest: function(creep) {
|
|
if (creep.store.getFreeCapacity(creep.memory.harvest_spot.resource_type) > 0) {
|
|
let target = Game.getObjectById(creep.memory.harvest_spot.id);
|
|
let err = creep.harvest(target);
|
|
if (err != OK) {
|
|
console.log("roleHarvester [ERROR]["+creep.name+"] harvest(): Failed to harvest at target "+target.pos+" with error: "+err);
|
|
if (err != ERR_NOT_IN_RANGE) {
|
|
console.log("roleHarvester ["+creep.name+"] harvest(): Failed to harvest because of wrong goto_pos trying to recalculate and switch back to moving ...");
|
|
creep.memory.harvest_spot.structure_pos = target.pos;
|
|
let result = PathFinder.search(creep.pos, {pos: target.pos, range: 1});
|
|
creep.memory.harvest_spot.goto_pos = result.path[result.path.length-1];
|
|
this.switch_state(creep, STATE_GOING_TO_SOURCE);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
this.switch_state(creep, STATE_GOING_TO_DESTINATION);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Goes to the delivery destination of the creep as dictated by destination_spot in its memory
|
|
* @param {Creep} creep
|
|
*/
|
|
go_to_destination: function(creep) {
|
|
if (creep.memory.destination_spot.goto_pos === null) { // find goto pos, if needed
|
|
let structure_pos = new RoomPosition(creep.memory.destination_spot.structure_pos.x, creep.memory.destination_spot.structure_pos.y, creep.memory.destination_spot.structure_pos.roomName);
|
|
let result = PathFinder.search(creep.pos, {pos: structure_pos, range: 1});
|
|
creep.memory.destination_spot.goto_pos = result.path[result.path.length-1];
|
|
}
|
|
|
|
let target_pos = new RoomPosition(creep.memory.destination_spot.goto_pos.x, creep.memory.destination_spot.goto_pos.y, creep.memory.destination_spot.goto_pos.roomName);
|
|
if (creep.pos.isEqualTo(target_pos)) {
|
|
console.log("roleHarvester ["+creep.name+"]: go_to_destination() arrived at target!");
|
|
this.switch_state(creep, STATE_DELIVERING);
|
|
}
|
|
|
|
creep.moveTo(target_pos, {visualizePathStyle: {stroke: '#ffaa00'}});
|
|
},
|
|
|
|
/**
|
|
* Lets the creep store its resources into the destination defined by the memory destination_spot
|
|
* @param {Creep} creep
|
|
*/
|
|
delivering: function(creep) {
|
|
let had_issue = false;
|
|
let storage = Game.getObjectById(creep.memory.destination_spot.id);
|
|
for (const resource_type in creep.store) {
|
|
console.log("roleHarvester ["+creep.name+"] delivering(): "+resource_type);
|
|
let err = creep.transfer(storage, resource_type);
|
|
|
|
if (err != OK) {
|
|
had_issue = true;
|
|
console.log("roleHarvester [ERROR]["+creep.name+"] delivering(): Failed to transfer resources with error: "+err);
|
|
creep.say("ERROR!");
|
|
}
|
|
}
|
|
|
|
if (!had_issue) {
|
|
this.switch_state(creep, STATE_GOING_TO_SOURCE);
|
|
}
|
|
else {
|
|
// TODO what to do if delivery failed? (e.g. destination is full)
|
|
}
|
|
},
|
|
};
|
|
|
|
module.exports = roleHarvester; |