implicit item locking

This commit is contained in:
2026-06-11 22:35:29 +02:00
parent 69b35d2bfc
commit 54a6056b77
11 changed files with 171 additions and 14 deletions

View File

@@ -59,6 +59,7 @@ Simulation::Simulation(GameConfig config, unsigned int seed)
m_shipSystem->spawn(id, it->second.level, pos, /*isEnemy=*/false, layout,
moduleLevels);
},
[this](const std::string& itemId) -> bool { return isItemUnlocked(itemId); },
m_rng);
m_shipSystem = std::make_unique<ShipSystem>(m_config, m_admin);
m_aiSystem = std::make_unique<AiSystem>();
@@ -86,6 +87,7 @@ Simulation::Simulation(GameConfig config, unsigned int seed)
m_moduleSchematicLevels[def.id] = state;
}
recomputeUnlocked();
placeInitialStructures();
registerForEvents();
}
@@ -147,6 +149,7 @@ void Simulation::reset(unsigned int seed)
m_shipSystem->spawn(id, it->second.level, pos, /*isEnemy=*/false, layout,
moduleLevels);
},
[this](const std::string& itemId) -> bool { return isItemUnlocked(itemId); },
m_rng);
m_shipSystem = std::make_unique<ShipSystem>(m_config, m_admin);
m_aiSystem = std::make_unique<AiSystem>();
@@ -174,6 +177,7 @@ void Simulation::reset(unsigned int seed)
m_moduleSchematicLevels[def.id] = state;
}
recomputeUnlocked();
placeInitialStructures();
}
@@ -544,6 +548,83 @@ void Simulation::awardSchematicDrop(int destroyedStationLevel)
evt.wasNewUnlock = wasNew;
evt.isModuleSchematic = isModule;
m_schematicDropEvents.push_back(evt);
recomputeUnlocked();
}
// ---------------------------------------------------------------------------
// Implicit unlock computation (REQ-LOCK-IMPLICIT)
// ---------------------------------------------------------------------------
void Simulation::recomputeUnlocked()
{
m_unlockedItemIds.clear();
m_unlockedRecipeIds.clear();
for (const ShipDef& def : m_config.ships.ships)
{
if (!isSchematicUnlocked(def.id)) { continue; }
for (const RecipeIngredient& mat : def.schematic.materials)
{
m_unlockedItemIds.insert(mat.item);
}
}
for (const ModuleDef& def : m_config.modules.modules)
{
if (!isModuleSchematicUnlocked(def.id)) { continue; }
for (const RecipeIngredient& mat : def.materials)
{
m_unlockedItemIds.insert(mat.item);
}
}
bool changed = true;
while (changed)
{
changed = false;
for (const RecipeDef& recipe : m_config.recipes.recipes)
{
if (recipe.building != BuildingType::Miner
&& recipe.building != BuildingType::Smelter
&& recipe.building != BuildingType::Assembler)
{
continue;
}
bool producesUnlocked = false;
for (const RecipeOutput& out : recipe.outputs)
{
if (m_unlockedItemIds.count(out.item) > 0)
{
producesUnlocked = true;
break;
}
}
if (!producesUnlocked) { continue; }
if (recipe.building == BuildingType::Miner
|| recipe.building == BuildingType::Assembler)
{
m_unlockedRecipeIds.insert(recipe.id);
}
for (const RecipeIngredient& ing : recipe.inputs)
{
if (m_unlockedItemIds.insert(ing.item).second)
{
changed = true;
}
}
}
}
}
bool Simulation::isRecipeUnlocked(const std::string& recipeId) const
{
return m_unlockedRecipeIds.count(recipeId) > 0;
}
bool Simulation::isItemUnlocked(const std::string& itemId) const
{
return m_unlockedItemIds.count(itemId) > 0;
}
// ---------------------------------------------------------------------------