Simulation.h/.cpp had grown a large block of schematic/unlock state (containers, the implicit-unlock traversal, checksum folding) that has nothing to do with tick orchestration. Split it into its own class so Simulation stays legible as "tick orchestration + subsystem handles". This commit only adds the new UnlockState.h/.cpp (registered in CMakeLists.txt) with the containers, types, and logic moved in verbatim; nothing references it yet, so this is a no-op for behavior. Simulation is wired to use it in the next commit. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
130 lines
5.6 KiB
C++
130 lines
5.6 KiB
C++
#pragma once
|
|
|
|
#include <map>
|
|
#include <set>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "BuildingType.h"
|
|
#include "GameConfig.h"
|
|
#include "SchematicChoiceOption.h"
|
|
|
|
class Hasher;
|
|
|
|
// Owns schematic/unlock bookkeeping for one run: which ship, module, and
|
|
// building schematics are unlocked (REQ-LOCK-EXPLICIT), which assembler recipe
|
|
// schematics have been explicitly granted, and the implicit recipe/item unlock
|
|
// sets derived from that state (REQ-LOCK-IMPLICIT). Reads config the same way
|
|
// BuildingSystem does (a bound const reference to Simulation::m_config, which is
|
|
// safe across restart because that member's storage address never changes —
|
|
// reset() move-assigns into it rather than replacing it).
|
|
//
|
|
// Simulation forwards its isXUnlocked-style public queries here and drives
|
|
// state changes (awarding an unlock group) here; the RNG-touching schematic
|
|
// choice generation itself stays in Simulation (call ordering of m_rng is the
|
|
// determinism backbone and must not move).
|
|
class UnlockState
|
|
{
|
|
public:
|
|
explicit UnlockState(const GameConfig& config);
|
|
|
|
// Builds the granted-id sets and initializes all per-item unlock maps from
|
|
// them (shared by the constructor and Simulation::reset). Ends with
|
|
// recomputeUnlocked().
|
|
void initializeUnlockState();
|
|
|
|
// Ship schematic state query.
|
|
bool isSchematicUnlocked(const std::string& shipId) const;
|
|
|
|
// Module schematic state query.
|
|
bool isModuleSchematicUnlocked(const std::string& moduleId) const;
|
|
|
|
// Implicit recipe/item unlock queries (REQ-LOCK-IMPLICIT).
|
|
bool isRecipeUnlocked(const std::string& recipeId) const;
|
|
bool isItemUnlocked(const std::string& itemId) const;
|
|
|
|
// Building unlock query (REQ-LOCK-BUILDING). True if the building type is not
|
|
// gated by any unlock group, or its granting group has been awarded.
|
|
bool isBuildingUnlocked(BuildingType type) const;
|
|
|
|
// True if the unlock group has already been awarded to the player.
|
|
bool isUnlockGroupAwarded(const std::string& groupId) const;
|
|
|
|
// True if every prerequisite unlock group has been awarded (REQ-LOCK-PREREQ).
|
|
bool prerequisitesSatisfied(const std::vector<std::string>& requiredGroupIds) const;
|
|
|
|
// Builds a schematic choice option for one unlock group (REQ-DEF-SCHEMATIC-DROP).
|
|
SchematicChoiceOption makeUnlockOption(const UnlockGroupDef& group) const;
|
|
|
|
// Awards the unlock group backing `chosen` (REQ-DEF-SCHEMATIC-DROP): marks
|
|
// every granted ship/module/building schematic unlocked, records granted
|
|
// recipe schematics, marks the group as awarded, and recomputes the implicit
|
|
// unlock sets. Mirrors the non-artifact branch of the original
|
|
// Simulation::applySchematicChoice exactly; callers still special-case
|
|
// chosen.isArtifact themselves before calling this.
|
|
void awardUnlockGroup(const SchematicChoiceOption& chosen);
|
|
|
|
// Determinism helper (see Simulation::computeStateChecksum): folds unlock
|
|
// state into the hasher via the same seven calls, in the same order, that
|
|
// used to live at the Simulation::computeStateChecksum call site.
|
|
void appendChecksum(Hasher& hasher) const;
|
|
|
|
private:
|
|
// Schematic unlock state (REQ-DEF-SCHEMATIC-DROP).
|
|
struct SchematicState
|
|
{
|
|
bool unlocked;
|
|
};
|
|
|
|
// Recomputes m_unlockedRecipeIds and m_unlockedItemIds from current schematic state.
|
|
void recomputeUnlocked();
|
|
|
|
// Result of the REQ-LOCK-IMPLICIT traversal.
|
|
struct UnlockedSets
|
|
{
|
|
std::set<std::string> itemIds;
|
|
std::set<std::string> recipeIds;
|
|
};
|
|
|
|
// Pure REQ-LOCK-IMPLICIT traversal given hypothetical explicit-unlock sets.
|
|
UnlockedSets computeUnlockedSets(const std::set<std::string>& unlockedShipSchematicIds,
|
|
const std::set<std::string>& unlockedModuleSchematicIds,
|
|
const std::set<std::string>& unlockedRecipeSchematicIds) const;
|
|
|
|
// Current explicit-unlock id sets, derived from m_schematicLevels / m_moduleSchematicLevels.
|
|
std::set<std::string> getUnlockedShipSchematicIds() const;
|
|
std::set<std::string> getUnlockedModuleSchematicIds() const;
|
|
|
|
// Ids (sorted alphabetically by display name) of the recipes in
|
|
// hypothetical.recipeIds that are not yet in m_unlockedRecipeIds.
|
|
std::vector<std::string> computeNewlyUnlockedRecipeIds(const UnlockedSets& hypothetical) const;
|
|
|
|
// Determinism helpers — fold sub-state into the hasher in deterministic order.
|
|
static void appendSchematicMap(Hasher& hasher,
|
|
const std::map<std::string, SchematicState>& levels);
|
|
static void appendStringSet(Hasher& hasher, const std::set<std::string>& ids);
|
|
|
|
const GameConfig& m_config;
|
|
|
|
std::map<std::string, SchematicState> m_schematicLevels;
|
|
std::map<std::string, SchematicState> m_moduleSchematicLevels;
|
|
std::map<std::string, SchematicState> m_buildingLevels;
|
|
|
|
// Unlock groups awarded so far (REQ-LOCK-EXPLICIT). Group ids.
|
|
std::set<std::string> m_awardedUnlockGroupIds;
|
|
|
|
// Ids granted by some unlock group, per kind — cached from config at init.
|
|
// An item starts locked iff it appears in the corresponding set.
|
|
std::set<std::string> m_grantedShipIds;
|
|
std::set<std::string> m_grantedModuleIds;
|
|
std::set<std::string> m_grantedBuildingIds;
|
|
std::set<std::string> m_grantedRecipeIds;
|
|
|
|
// Explicitly unlocked assembler recipe schematics (REQ-LOCK-EXPLICIT).
|
|
std::set<std::string> m_unlockedRecipeSchematicIds;
|
|
|
|
// Implicit unlock sets derived from schematic state (REQ-LOCK-IMPLICIT).
|
|
std::set<std::string> m_unlockedRecipeIds;
|
|
std::set<std::string> m_unlockedItemIds;
|
|
};
|