implement ship modules
This commit is contained in:
@@ -11,7 +11,8 @@ BuildingSystem::BuildingSystem(const GameConfig& config,
|
||||
BeltSystem& belts,
|
||||
std::function<EntityId()> allocateId,
|
||||
std::function<void(int)> addBuildingBlocks,
|
||||
std::function<void(const std::string&, QVector2D)> spawnShip,
|
||||
std::function<void(const std::string&, QVector2D,
|
||||
const std::optional<ShipLayoutConfig>&)> spawnShip,
|
||||
std::mt19937& rng)
|
||||
: m_config(config)
|
||||
, m_belts(belts)
|
||||
@@ -63,6 +64,18 @@ const ShipDef* BuildingSystem::findShipDef(const std::string& id) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ModuleDef* BuildingSystem::findModuleDef(const std::string& id) const
|
||||
{
|
||||
for (const ModuleDef& def : m_config.modules.modules)
|
||||
{
|
||||
if (def.id == id)
|
||||
{
|
||||
return &def;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BuildingSystem::initBuffers(Building& b, const RecipeDef& recipe) const
|
||||
{
|
||||
b.inputBuffer.counts.clear();
|
||||
@@ -117,6 +130,23 @@ void BuildingSystem::initShipyardBuffers(Building& b) const
|
||||
b.inputBuffer.counts[type] = 0;
|
||||
b.inputBuffer.caps[type] = 2 * ing.amount;
|
||||
}
|
||||
if (b.shipLayout.has_value())
|
||||
{
|
||||
for (const PlacedModule& pm : b.shipLayout->placedModules)
|
||||
{
|
||||
const ModuleDef* modDef = findModuleDef(pm.moduleId);
|
||||
if (!modDef)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (const RecipeIngredient& ing : modDef->materials)
|
||||
{
|
||||
const ItemType type{ing.item};
|
||||
b.inputBuffer.counts.try_emplace(type, 0);
|
||||
b.inputBuffer.caps[type] += 2 * ing.amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Port> BuildingSystem::computeInputPorts(const Building& b) const
|
||||
@@ -303,6 +333,7 @@ void BuildingSystem::setRecipe(EntityId id, const std::string& recipeId)
|
||||
if (site.id == id)
|
||||
{
|
||||
site.recipeId = recipeId;
|
||||
site.shipLayout = std::nullopt;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -313,6 +344,7 @@ void BuildingSystem::setRecipe(EntityId id, const std::string& recipeId)
|
||||
if (building.id == id)
|
||||
{
|
||||
building.recipeId = recipeId;
|
||||
building.shipLayout = std::nullopt;
|
||||
building.inputBuffer.counts.clear();
|
||||
building.inputBuffer.caps.clear();
|
||||
building.outputBuffer.items.clear();
|
||||
@@ -339,6 +371,39 @@ void BuildingSystem::setRecipe(EntityId id, const std::string& recipeId)
|
||||
}
|
||||
}
|
||||
|
||||
void BuildingSystem::setShipLayout(EntityId id, const ShipLayoutConfig& layout)
|
||||
{
|
||||
for (ConstructionSite& site : m_constructionQueue)
|
||||
{
|
||||
if (site.id == id)
|
||||
{
|
||||
site.shipLayout = layout;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (Building& building : m_buildings)
|
||||
{
|
||||
if (building.id == id)
|
||||
{
|
||||
if (building.production.has_value())
|
||||
{
|
||||
building.production = std::nullopt;
|
||||
}
|
||||
building.shipLayout = layout;
|
||||
building.inputBuffer.counts.clear();
|
||||
building.inputBuffer.caps.clear();
|
||||
building.outputBuffer.items.clear();
|
||||
building.outputBuffer.capacity = 0;
|
||||
if (!building.recipeId.empty() && building.type == BuildingType::Shipyard)
|
||||
{
|
||||
initShipyardBuffers(building);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tick hooks
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -383,6 +448,7 @@ void BuildingSystem::tickConstruction(Tick currentTick)
|
||||
building.hp = 100.0f;
|
||||
building.maxHp = 100.0f;
|
||||
building.recipeId = front.recipeId;
|
||||
building.shipLayout = front.shipLayout;
|
||||
|
||||
for (const QPoint& cell : mask.bodyCells)
|
||||
{
|
||||
@@ -657,22 +723,44 @@ void BuildingSystem::tickShipyardProduction(Tick currentTick)
|
||||
{
|
||||
const Port& p = building.outputPorts[0];
|
||||
const QVector2D spawnPos(p.tile.x() + 0.5f, p.tile.y() + 0.5f);
|
||||
m_spawnShip(building.recipeId, spawnPos);
|
||||
m_spawnShip(building.recipeId, spawnPos, building.shipLayout);
|
||||
}
|
||||
building.production = std::nullopt;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Idle: check if all materials are available to start a new cycle.
|
||||
bool inputsOk = true;
|
||||
// Build combined materials list (base + modules).
|
||||
std::map<std::string, int> requiredMaterials;
|
||||
for (const RecipeIngredient& ing : shipDef->schematic.materials)
|
||||
{
|
||||
const ItemType type{ing.item};
|
||||
requiredMaterials[ing.item] += ing.amount;
|
||||
}
|
||||
if (building.shipLayout.has_value())
|
||||
{
|
||||
for (const PlacedModule& pm : building.shipLayout->placedModules)
|
||||
{
|
||||
const ModuleDef* modDef = findModuleDef(pm.moduleId);
|
||||
if (!modDef)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (const RecipeIngredient& ing : modDef->materials)
|
||||
{
|
||||
requiredMaterials[ing.item] += ing.amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Idle: check if all combined materials are available.
|
||||
bool inputsOk = true;
|
||||
for (const std::pair<const std::string, int>& req : requiredMaterials)
|
||||
{
|
||||
const ItemType type{req.first};
|
||||
const std::map<ItemType, int>::const_iterator it =
|
||||
building.inputBuffer.counts.find(type);
|
||||
const int have = (it != building.inputBuffer.counts.end()) ? it->second : 0;
|
||||
if (have < ing.amount)
|
||||
if (have < req.second)
|
||||
{
|
||||
inputsOk = false;
|
||||
break;
|
||||
@@ -683,16 +771,28 @@ void BuildingSystem::tickShipyardProduction(Tick currentTick)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Consume materials and start the production cycle.
|
||||
for (const RecipeIngredient& ing : shipDef->schematic.materials)
|
||||
// Consume combined materials and start the production cycle.
|
||||
for (const std::pair<const std::string, int>& req : requiredMaterials)
|
||||
{
|
||||
building.inputBuffer.counts[ItemType{ing.item}] -= ing.amount;
|
||||
building.inputBuffer.counts[ItemType{req.first}] -= req.second;
|
||||
}
|
||||
|
||||
double totalTime = shipDef->schematic.productionTimeSeconds;
|
||||
if (building.shipLayout.has_value())
|
||||
{
|
||||
for (const PlacedModule& pm : building.shipLayout->placedModules)
|
||||
{
|
||||
const ModuleDef* modDef = findModuleDef(pm.moduleId);
|
||||
if (modDef)
|
||||
{
|
||||
totalTime += modDef->productionTimeSeconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Production prod;
|
||||
prod.recipeId = building.recipeId;
|
||||
prod.completesAt = currentTick
|
||||
+ secondsToTicks(shipDef->schematic.productionTimeSeconds);
|
||||
prod.completesAt = currentTick + secondsToTicks(totalTime);
|
||||
building.production = std::move(prod);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user