diff --git a/src/creeps/builder.js b/src/creeps/builder.js new file mode 100644 index 0000000..4581409 --- /dev/null +++ b/src/creeps/builder.js @@ -0,0 +1,84 @@ +const { sum } = require("lodash"); + +const ROLE_IDENT = "Build"; + +var roleBuilder = { + + ROLE_IDENT: ROLE_IDENT, + + minimum_parts: [WORK, MOVE, CARRY], + recommended_parts: [WORK, MOVE, CARRY, CARRY], + min_cost: sum([BODYPART_COST["work"], BODYPART_COST["move"], BODYPART_COST["carry"]]), + rec_cost: sum([BODYPART_COST["work"], BODYPART_COST["move"], BODYPART_COST["carry"], 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 = "builder-"+postfix; + if (spawn.spawnCreep(this.recommended_parts, creep_name, {dryRun: true}) === OK) { + console.log("roleBuilder: 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("roleBuilder: 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("roleBuilder: Spawn \""+spawn.name+"\" couldn't afford a Builder! D: Result: ", spawn.spawnCreep(this.minimum_parts, creep_name, {dryRun: true})); + throw "Not enough energy!"; + } + + Memory.creeps[creep_name].destination_spot = { + id: null, + structure_pos: null, + goto_pos: null, + }; + Memory.creeps[creep_name].source_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_builder: function(creep) { + if (creep.memory.role === ROLE_IDENT) { + return true; + } + else { + return false; + } + }, + + /** + * Runs the creeps logic as a builder + * @param {Creep} creep + */ + run: function(creep) { + console.log("roleBuilder ["+creep.name+"] run(): running ..."); + }, + +}; diff --git a/src/creeps/harvester.js b/src/creeps/harvester.js index 8dc470d..abe0e2f 100644 --- a/src/creeps/harvester.js +++ b/src/creeps/harvester.js @@ -1,4 +1,6 @@ -const { sum, isNil } = require("lodash"); +const { sum } = require("lodash"); + +const ROLE_IDENT = "Harv"; const STATE_INIT = 0; const STATE_GOING_TO_SOURCE = 1; @@ -8,6 +10,8 @@ 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"]]), @@ -24,11 +28,11 @@ var roleHarvester = { 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": "Harv"}}); + 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": "Harv"}}); + 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})); @@ -62,6 +66,19 @@ var roleHarvester = { 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 @@ -149,7 +166,7 @@ var roleHarvester = { } - console.log("roleHarvester ["+creep.name+"] init_creep(): harvest task has been setup and committed to memory!") + console.log("roleHarvester ["+creep.name+"] init_creep(): harvest task has been setup and committed to memory!"); this.switch_state(creep, STATE_GOING_TO_SOURCE); }, @@ -242,7 +259,7 @@ var roleHarvester = { this.switch_state(creep, STATE_GOING_TO_SOURCE); } else { - // TODO what to do if delivery failed? + // TODO what to do if delivery failed? (e.g. destination is full) } }, }; diff --git a/src/creeps/role_map.js b/src/creeps/role_map.js index dff02ef..3d09ba4 100644 --- a/src/creeps/role_map.js +++ b/src/creeps/role_map.js @@ -1,10 +1,15 @@ var harvester_obj = require('creeps_harvester'); +var builder_obj = require('creeps_builder'); /** Dictionary to map creep roles to their identifier and an object reference */ var roles = { harvester: { - ident: "Harv", - obj: harvester_obj + ident: harvester_obj.ROLE_IDENT, + obj: harvester_obj, + }, + builder: { + ident: builder_obj.ROLE_IDENT, + obj: builder_obj, }, }; diff --git a/src/hivemind/hivemind.js b/src/hivemind/hivemind.js index ad8df40..6360eb6 100644 --- a/src/hivemind/hivemind.js +++ b/src/hivemind/hivemind.js @@ -96,10 +96,19 @@ var hivemind = { for (let name in Game.creeps) { let creep = Game.creeps[name]; - let creep_role = creep.memory.role - //console.log("Hivemind: Running creep \""+name+"|"+creep_role+"\""); + let creep_role = creep.memory.role; + console.log("Hivemind: Running creep \""+name+"|"+creep_role+"\""); let role = _.filter(roles, function(node) {return node.ident === creep_role})[0]; - + if (role === undefined) { + var blk_str = []; + _.each(roles, function(node) { + var harvester_obj = require('creeps_harvester'); + var str = node+": "+node.ident+"|"+Object.keys(harvester_obj); + blk_str.push(str); + }); + console.log("[ERROR] A creep has a role that is unknown. Creep Name: ", name, "Creep Role:", creep_role, "Known Roles: ", blk_str.join(", ")); + throw "Unknown role"; + } role.obj.run(creep); } }, diff --git a/src/overlords/setup_overlord.js b/src/overlords/setup_overlord.js index 0894fb3..62a2e9e 100644 --- a/src/overlords/setup_overlord.js +++ b/src/overlords/setup_overlord.js @@ -1,5 +1,6 @@ var setup_overlord = require('overlords_overlord'); var harvester = require('creeps_harvester'); +var builder = require('creeps_builder'); /** * Overlord that sets up a room given only a single spawn with a minimum energy to build one harvester. @@ -35,7 +36,8 @@ setup_overlord.prototype.run = function () { this.create_harvesters(); break; case STATE_BUILD_SPAWNS: - console.log("SetupOverlord [ERROR] run(): state not implemented yet!"); + console.log("SetupOverlord [WARN] run(): Build spawn state not fully implemented yet!"); + this.create_spawns(); break; default: console.log("SetupOverlord [ERROR] run(): unknown state: "+this.state); @@ -67,7 +69,7 @@ setup_overlord.prototype.init = function() { * Switches to STATE_BUILD_SPAWNS if every source has a harvester assigned. */ setup_overlord.prototype.create_harvesters = function() { - if (this.underlings['creeps'].length === 0 && this.underlings['spawns'].length > 0) { // first harvester needs to be spawned + if (this.underlings['creeps'].length < this.underlings['spawns'].length && this.underlings['spawns'].length > 0) { // first harvester needs to be spawned console.log("SetupOverlord: \""+this.id+"\" is trying to create a harvester ..."); for (let spawn_name of this.underlings['spawns']) { // check every spawn for energy available @@ -81,8 +83,33 @@ setup_overlord.prototype.create_harvesters = function() { } } } + else { + this.switch_state(STATE_BUILD_SPAWNS); + } +} - +/** + * Runs every tick and attempts to create new spawns if the energy is available. If no creep with the builder role is available to this overlord one is created. + */ +setup_overlord.prototype.create_spawns = function() { + let builder_creep = null; + for (let creep_name of this.underlings["creeps"]) { + if (builder.is_builder(Game.creeps[creep_name])) { // todo check if builder + builder_creep = creep_name; + } + } + if (builder_creep !== null) { + + for (let spawn_name of this.underlings['spawns']) { + let spawn = Game.spawns[spawn_name]; + if (spawn.store[RESOURCE_ENERGY] > builder.min_cost) { + console.log("SetupOverlord create_spawns(): got no builder! Creating one ..."); + let new_builder_name = builder.spawn(this.id+"-"+this.underlings['creeps'].length, this.id); + //this.set_creep_destination_spot(new_harvester_name, ); // TODO decide where to put the new spawn + } + } + //if (spawn) {} + } } /**