From fb07ab70fcb152b18133674b2374638535f2950c Mon Sep 17 00:00:00 2001 From: Douwe Ravers Date: Fri, 10 Jul 2026 14:17:00 +0200 Subject: [PATCH] Moved spawning to room, multiple miners working. --- douwco_hivemind/include/Entity/Room.hpp | 18 +- douwco_hivemind/include/Structures/Spawn.hpp | 8 +- douwco_hivemind/src/Creeps/Worker.cpp | 35 ++-- douwco_hivemind/src/Entity/Room.cpp | 169 ++++++++++++++++--- douwco_hivemind/src/Structures/Spawn.cpp | 102 ----------- 5 files changed, 183 insertions(+), 149 deletions(-) diff --git a/douwco_hivemind/include/Entity/Room.hpp b/douwco_hivemind/include/Entity/Room.hpp index 170082a..95fc3a9 100644 --- a/douwco_hivemind/include/Entity/Room.hpp +++ b/douwco_hivemind/include/Entity/Room.hpp @@ -1,17 +1,23 @@ #ifndef DOUWCO_HIVEMIND_ROOM_HPP #define DOUWCO_HIVEMIND_ROOM_HPP +#include "Constants.hpp" #include #include namespace DouwcoHivemind { class Room { - -protected: - Screeps::Room room; +public: + Screeps::Room roomJs; JSON memory; - std::vector sources = {}; - std::vector sourceContainers = {}; + + std::vector sourceIds = {}; + std::vector sourceContainerIds = {}; + std::vector SpawnIds = {}; + std::vector screepNames = {}; + +private: + int minerIterator; public: Room(Screeps::Room rm); @@ -20,6 +26,8 @@ public: void loop(); protected: + void manageScreeps(); + void manageStructures(); void placeContainers(); }; } // namespace DouwcoHivemind diff --git a/douwco_hivemind/include/Structures/Spawn.hpp b/douwco_hivemind/include/Structures/Spawn.hpp index 450aba8..4904fd4 100644 --- a/douwco_hivemind/include/Structures/Spawn.hpp +++ b/douwco_hivemind/include/Structures/Spawn.hpp @@ -9,15 +9,13 @@ namespace DouwcoHivemind { class Spawn : public StructureBase { - private: - Screeps::StructureSpawn spawn; + public: + Screeps::StructureSpawn spawnJs; public: - Spawn(Screeps::StructureSpawn spwn) : spawn(spwn), + Spawn(Screeps::StructureSpawn spwn) : spawnJs(spwn), StructureBase() {} ~Spawn() {} - - void loop() override; }; } diff --git a/douwco_hivemind/src/Creeps/Worker.cpp b/douwco_hivemind/src/Creeps/Worker.cpp index 886bd41..331c147 100644 --- a/douwco_hivemind/src/Creeps/Worker.cpp +++ b/douwco_hivemind/src/Creeps/Worker.cpp @@ -36,9 +36,7 @@ DouwcoHivemind::Worker::~Worker() { memory["harvesting"] = harvesting; } void DouwcoHivemind::Worker::loop() { if (harvesting) { - JS::console.log(std::string("worker: harvesting")); if (creep.store().getFreeCapacity(Screeps::RESOURCE_ENERGY) == 0) { - JS::console.log(std::string("worker: harvesting full")); harvesting = false; targetId.clear(); } else { @@ -55,20 +53,15 @@ void DouwcoHivemind::Worker::loop() { } void DouwcoHivemind::Worker::getEnergy() { - JS::console.log(std::string("worker: get energy")); if (targetId.empty()) { - JS::console.log(std::string("worker: No target search energy")); searchEnergySource(); } else { - JS::console.log(std::string("worker: has target with energy")); auto target = getRoomObjectTarget(); if (!target) return; if (isNearTo(target->pos(), 1)) { - JS::console.log(std::string("worker: collect energy")); extractEnergyFromTarget(); } else { - JS::console.log(std::string("worker: go to energy")); moveToTarget(1); } } @@ -95,6 +88,10 @@ void DouwcoHivemind::Worker::searchEnergySource() { .value_or(0); if (availableEnergy == 0) continue; + if (container->pos().inRangeTo(creep.pos(), 3)) { + targetId = container->id(); + return; + } if (fullestContents < availableEnergy) { fullestContents = availableEnergy; containerID = container->id(); @@ -103,6 +100,11 @@ void DouwcoHivemind::Worker::searchEnergySource() { } } + // If no storage go for the containers + if (!containerID.empty()) { + targetId = containerID; + } + // Search for loose resources auto resourceObjects = creep.room().find(Screeps::FIND_DROPPED_RESOURCES); if (resourceObjects.size() > 0) { @@ -113,6 +115,10 @@ void DouwcoHivemind::Worker::searchEnergySource() { if (resource->resourceType() != Screeps::RESOURCE_ENERGY) continue; int amount = resource->amount(); + if (resource->pos().inRangeTo(creep.pos(), 3)) { + targetId = resource->id(); + return; + } if (amount < 100) continue; if (amount > highestAmount) { @@ -137,6 +143,10 @@ void DouwcoHivemind::Worker::searchEnergySource() { continue; int amount = ruin->store().getUsedCapacity(Screeps::RESOURCE_ENERGY).value_or(0); + if (ruin->pos().inRangeTo(creep.pos(), 3) && amount > 0) { + targetId = ruin->id(); + return; + } if (amount > highestAmount) { highestAmount = amount; ruinID = ruin->id(); @@ -160,6 +170,10 @@ void DouwcoHivemind::Worker::searchEnergySource() { int amount = tombstone->store() .getUsedCapacity(Screeps::RESOURCE_ENERGY) .value_or(0); + if (tombstone->pos().inRangeTo(creep.pos(), 3) && amount > 0) { + targetId = tombstone->id(); + return; + } if (amount > highestAmount) { highestAmount = amount; TombstoneID = tombstone->id(); @@ -171,13 +185,8 @@ void DouwcoHivemind::Worker::searchEnergySource() { } } - // If still nothing found take the earlier found container. - if (!containerID.empty()) { - targetId = containerID; - } - // If still nothing found, there is no target and search should start again. - targetId = std::string(); + targetId.clear(); } void DouwcoHivemind::Worker::extractEnergyFromTarget() { diff --git a/douwco_hivemind/src/Entity/Room.cpp b/douwco_hivemind/src/Entity/Room.cpp index 2506a05..d0b68c0 100644 --- a/douwco_hivemind/src/Entity/Room.cpp +++ b/douwco_hivemind/src/Entity/Room.cpp @@ -1,5 +1,6 @@ #include "Entity/Room.hpp" +#include "Engine.hpp" #include "Screeps/Constants.hpp" #include "Screeps/Game.hpp" #include "Screeps/Room.hpp" @@ -12,39 +13,158 @@ #include "Screeps/StructureController.hpp" #include "Constants.hpp" +#include "Screeps/StructureSpawn.hpp" +#include "Structures/Spawn.hpp" #include -DouwcoHivemind::Room::Room(Screeps::Room rm) : room(rm), memory(rm.memory()) { +DouwcoHivemind::Room::Room(Screeps::Room rm) : roomJs(rm), memory(rm.memory()) { if (memory.contains("sources")) - sources = static_cast>(memory["sources"]); + sourceIds = static_cast>(memory["sources"]); if (memory.contains("sourceContainers")) - sourceContainers = + sourceContainerIds = static_cast>(memory["sourceContainers"]); + minerIterator = memory.contains("minerIterator") + ? static_cast(memory["minerIterator"]) + : 0; } DouwcoHivemind::Room::~Room() { - memory["sources"] = sources; - memory["sourceContainers"] = sourceContainers; - room.setMemory(memory); + memory["sources"] = sourceIds; + memory["sourceContainers"] = sourceContainerIds; + memory["minerIterator"] = minerIterator; + roomJs.setMemory(memory); } void DouwcoHivemind::Room::loop() { - if (sources.size() == 0) { - auto sources_ = room.find(Screeps::FIND_SOURCES); - for (auto &source : sources_) { - sources.push_back(static_cast(source.get())->id()); + manageStructures(); + manageScreeps(); +} + +void DouwcoHivemind::Room::manageStructures() { placeContainers(); } + +void DouwcoHivemind::Room::manageScreeps() { + // Get energy data + int energyAvailable = roomJs.energyAvailable(); + int energyCapacityAvailable = roomJs.energyCapacityAvailable(); + + // Calculate needed creep roles + int required_upgraders = 1; + int required_suppliers = 2; + int required_maintainers = 1; + int required_builders = + roomJs.find(Screeps::FIND_MY_CONSTRUCTION_SITES).size() > 0 ? 1 : 0; + int required_miners = sourceIds.size(); + + // Count existing roles + int existing_upgraders = 0; + int existing_suppliers = 0; + int existing_maintainers = 0; + int existing_builders = 0; + int existing_miners = 0; + + for (auto &creep : Engine::getInstance()->Creeps) { + CreepRole role = creep.second->role; + + if (role == CreepRole::SUPPLIER) + existing_suppliers++; + else if (role == CreepRole::UPGRADER) + existing_upgraders++; + else if (role == CreepRole::MAINTAINER) + existing_maintainers++; + else if (role == CreepRole::BUILDER) + existing_builders++; + else if (role == CreepRole::MINER) + existing_miners++; + } + + // Check if max energy used + if (energyAvailable < energyCapacityAvailable && 0 < existing_suppliers) + return; + + // Set creep properties + std::string name; + JSON opts; + CreepRole role = CreepRole::UNEMPLOYED; + if (required_miners > existing_miners) { + role = CreepRole::MINER; + opts["memory"]["sourceId"] = sourceIds[minerIterator]; + minerIterator = (minerIterator + 1) % sourceIds.size(); + name = "Miner: "; + } else if (required_suppliers > existing_suppliers) { + role = CreepRole::SUPPLIER; + name = "Supplier: "; + } else if (required_upgraders > existing_upgraders) { + role = CreepRole::UPGRADER; + name = "Upgrader: "; + } else if (required_builders > existing_builders) { + role = CreepRole::BUILDER; + name = "Builder: "; + } else if (required_maintainers > existing_maintainers) { + role = CreepRole::MAINTAINER; + name = "Maintainer: "; + } else + return; + + opts["memory"]["role"] = role; + + // Build creep body + std::vector body; + // Miner body with up to 5 work (10 en/s) bits for 3000 source mining in 300 + // tick regen. + if (role == CreepRole::MINER) { + body.push_back("move"); + body.push_back("work"); + for (int i = 0; i < (energyAvailable - 150) / 100 && i < 5; i++) { + body.push_back("work"); } } - placeContainers(); + // Supplier body with only move and carry to move energy around + else if (role == SUPPLIER) { + for (int i = 0; i < energyAvailable / 100; i++) { + body.push_back("move"); + body.push_back("carry"); + } + } + // Worker body with balanced parts. + else { + for (int i = 0; i < energyAvailable / 200; i++) { + body.push_back("work"); + body.push_back("carry"); + body.push_back("move"); + } + } + + // If no spawns stored yet + if (SpawnIds.size() == 0) { + auto spawnStructures = roomJs.find(Screeps::FIND_MY_SPAWNS); + for (auto &spawnStructure : spawnStructures) { + SpawnIds.push_back( + static_cast(spawnStructure.get())->id()); + } + } + + // Create creep + auto spawn = static_cast( + Engine::getInstance()->Structures[SpawnIds[0]].get()); + std::string unique_name = name + std::to_string(Screeps::Game.time()); + spawn->spawnJs.spawnCreep(body, unique_name, opts); + screepNames.push_back(unique_name); } void DouwcoHivemind::Room::placeContainers() { + // If no sources stored yet + if (sourceIds.size() == 0) { + auto sources_ = roomJs.find(Screeps::FIND_SOURCES); + for (auto &source : sources_) { + sourceIds.push_back(static_cast(source.get())->id()); + } + } // No containers planned or build, planning now - if (sourceContainers.size() < sources.size()) { - int controller_x = room.controller().value().pos().x(); - int controller_y = room.controller().value().pos().y(); + if (sourceContainerIds.size() < sourceIds.size()) { + int controller_x = roomJs.controller().value().pos().x(); + int controller_y = roomJs.controller().value().pos().y(); - for (auto sourceId : sources) { + for (auto sourceId : sourceIds) { auto roomObj = Screeps::Game.getObjectById(sourceId); int source_x = roomObj->pos().x(); int source_y = roomObj->pos().y(); @@ -58,7 +178,7 @@ void DouwcoHivemind::Room::placeContainers() { continue; int x = source_x + dx; int y = source_y + dy; - int terrainType = room.getTerrain().get(x, y); + int terrainType = roomJs.getTerrain().get(x, y); if (terrainType != Screeps::TERRAIN_MASK_WALL) { int cost = std::abs(x - controller_x) + std::abs(y - controller_y); if (cost < lowest_cost) { @@ -69,30 +189,31 @@ void DouwcoHivemind::Room::placeContainers() { } } } - room.createConstructionSite(best_x, best_y, Screeps::STRUCTURE_CONTAINER); - sourceContainers.push_back("under_construction"); + roomJs.createConstructionSite(best_x, best_y, + Screeps::STRUCTURE_CONTAINER); + sourceContainerIds.push_back("under_construction"); } return; } // Check if construction container is done. - for (auto entry : sourceContainers) { + for (auto entry : sourceContainerIds) { if (entry != "under_construction") continue; - auto structures = room.find(Screeps::FIND_STRUCTURES); + auto structures = roomJs.find(Screeps::FIND_STRUCTURES); int index = 0; for (auto &structure : structures) { auto str = dynamic_cast(structure.get()); if (str->structureType() == Screeps::STRUCTURE_CONTAINER) { - sourceContainers[index] = str->id(); + sourceContainerIds[index] = str->id(); index++; } } return; } // Check if containers still exist - for (int i = 0; i < sourceContainers.size(); i++) { - auto roomObj = Screeps::Game.getObjectById(sourceContainers[i]); + for (int i = 0; i < sourceContainerIds.size(); i++) { + auto roomObj = Screeps::Game.getObjectById(sourceContainerIds[i]); if (!roomObj) - sourceContainers.erase(sourceContainers.begin() + i); + sourceContainerIds.erase(sourceContainerIds.begin() + i); } } diff --git a/douwco_hivemind/src/Structures/Spawn.cpp b/douwco_hivemind/src/Structures/Spawn.cpp index bbc2efb..a9c8ac0 100644 --- a/douwco_hivemind/src/Structures/Spawn.cpp +++ b/douwco_hivemind/src/Structures/Spawn.cpp @@ -1,103 +1 @@ -#include -#include -#include - -#include "Creeps/CreepBase.hpp" -#include "Engine.hpp" #include "Structures/Spawn.hpp" - -void DouwcoHivemind::Spawn::loop() { - // Get energy data - int energyAvailable = spawn.room().energyAvailable(); - int energyCapacityAvailable = spawn.room().energyCapacityAvailable(); - - // Calculate needed creep roles - int required_upgraders = 1; - int required_suppliers = 2; - int required_maintainers = 1; - int required_builders = - spawn.room().find(Screeps::FIND_MY_CONSTRUCTION_SITES).size() > 0 ? 1 : 0; - int required_miners = 1; // spawn.room().memory()["sources"].size(); - - // Count existing roles - int existing_upgraders = 0; - int existing_suppliers = 0; - int existing_maintainers = 0; - int existing_builders = 0; - int existing_miners = 0; - - for (auto &creep : Screeps::Game.creeps()) { - CreepRole role = creep.second.memory()["role"]; - - if (role == CreepRole::SUPPLIER) - existing_suppliers++; - else if (role == CreepRole::UPGRADER) - existing_upgraders++; - else if (role == CreepRole::MAINTAINER) - existing_maintainers++; - else if (role == CreepRole::BUILDER) - existing_builders++; - else if (role == CreepRole::MINER) - existing_miners++; - } - - // Check if max energy used - if (energyAvailable < energyCapacityAvailable && 0 < existing_suppliers) - return; - - // Set creep properties - std::string name; - JSON opts; - CreepRole role = CreepRole::UNEMPLOYED; - if (required_miners > existing_miners) { - role = CreepRole::MINER; - opts["memory"]["sourceId"] = - spawn.room().memory()["sources"][0]; // make logic for more - name = "Miner: "; - } else if (required_suppliers > existing_suppliers) { - role = CreepRole::SUPPLIER; - name = "Supplier: "; - } else if (required_upgraders > existing_upgraders) { - role = CreepRole::UPGRADER; - name = "Upgrader: "; - } else if (required_builders > existing_builders) { - role = CreepRole::BUILDER; - name = "Builder: "; - } else if (required_maintainers > existing_maintainers) { - role = CreepRole::MAINTAINER; - name = "Maintainer: "; - } else - return; - - opts["memory"]["role"] = role; - - // Build creep body - std::vector body; - // Miner body with up to 5 work (10 en/s) bits for 3000 source mining in 300 - // tick regen. - if (role == CreepRole::MINER) { - body.push_back("move"); - body.push_back("work"); - for (int i = 0; i < (energyAvailable - 150) / 100 && i < 5; i++) { - body.push_back("work"); - } - } - // Supplier body with only move and carry to move energy around - else if (role == SUPPLIER) { - for (int i = 0; i < energyAvailable / 100; i++) { - body.push_back("move"); - body.push_back("carry"); - } - } - // Worker body with balanced parts. - else { - for (int i = 0; i < energyAvailable / 200; i++) { - body.push_back("work"); - body.push_back("carry"); - body.push_back("move"); - } - } - - // Create creep - spawn.spawnCreep(body, name + std::to_string(Screeps::Game.time()), opts); -} \ No newline at end of file