schematic selection dialog
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
#include "Simulation.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
#include "AiSystem.h"
|
||||
#include "DisplayName.h"
|
||||
#include "BuildingSystem.h"
|
||||
#include "CombatSystem.h"
|
||||
#include "DynamicBodySystem.h"
|
||||
@@ -135,7 +137,7 @@ void Simulation::reset(unsigned int seed)
|
||||
m_currentEnemyStationEntities[0] = entt::null;
|
||||
m_currentEnemyStationEntities[1] = entt::null;
|
||||
m_fireEvents.clear();
|
||||
m_schematicDropEvents.clear();
|
||||
m_pendingSchematicChoices.clear();
|
||||
|
||||
m_admin.clear();
|
||||
m_beltSystem = BeltSystem(m_config.world.beltSpeed_tps);
|
||||
@@ -532,11 +534,11 @@ void Simulation::tickDeathsAndLoot()
|
||||
const int destroyedLevel = m_waveSystem->generation();
|
||||
m_waveSystem->onEnemyStationsDestroyed();
|
||||
placeEnemyStationSet(m_waveSystem->generation());
|
||||
awardSchematicDrop(destroyedLevel);
|
||||
generateSchematicChoices(destroyedLevel);
|
||||
}
|
||||
}
|
||||
|
||||
void Simulation::awardSchematicDrop(int destroyedStationLevel)
|
||||
void Simulation::generateSchematicChoices(int destroyedStationLevel)
|
||||
{
|
||||
enum class DropType { Ship, Module, Recipe };
|
||||
struct PoolEntry { std::string id; DropType type; };
|
||||
@@ -572,32 +574,78 @@ void Simulation::awardSchematicDrop(int destroyedStationLevel)
|
||||
pool.push_back({def.id, DropType::Recipe});
|
||||
}
|
||||
|
||||
std::uniform_int_distribution<int> dist(0, static_cast<int>(pool.size()) - 1);
|
||||
const PoolEntry& chosen = pool[static_cast<std::size_t>(dist(m_rng))];
|
||||
if (pool.empty()) { return; }
|
||||
|
||||
if (chosen.type == DropType::Recipe)
|
||||
const int numChoices = std::min(static_cast<int>(pool.size()), 3);
|
||||
m_pendingSchematicChoices.clear();
|
||||
|
||||
for (int i = 0; i < numChoices; ++i)
|
||||
{
|
||||
m_unlockedRecipeSchematicIds.insert(chosen.id);
|
||||
recomputeUnlocked();
|
||||
std::uniform_int_distribution<int> dist(0, static_cast<int>(pool.size()) - 1 - i);
|
||||
const int roll = dist(m_rng);
|
||||
const std::size_t rollIdx = static_cast<std::size_t>(roll);
|
||||
const std::size_t endIdx = pool.size() - 1 - static_cast<std::size_t>(i);
|
||||
std::swap(pool[rollIdx], pool[endIdx]);
|
||||
const PoolEntry& entry = pool[endIdx];
|
||||
|
||||
SchematicChoiceOption option;
|
||||
option.schematicId = entry.id;
|
||||
|
||||
if (entry.type == DropType::Ship)
|
||||
{
|
||||
option.type = SchematicType::Ship;
|
||||
option.displayName = toDisplayName(entry.id);
|
||||
const SchematicState& state = m_schematicLevels.at(entry.id);
|
||||
option.isNewUnlock = !state.unlocked;
|
||||
option.targetLevel = state.level + 1;
|
||||
}
|
||||
else if (entry.type == DropType::Module)
|
||||
{
|
||||
option.type = SchematicType::Module;
|
||||
option.displayName = toDisplayName(entry.id);
|
||||
const SchematicState& state = m_moduleSchematicLevels.at(entry.id);
|
||||
option.isNewUnlock = !state.unlocked;
|
||||
option.targetLevel = state.level + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
option.type = SchematicType::Recipe;
|
||||
option.isNewUnlock = true;
|
||||
option.targetLevel = 0;
|
||||
for (const RecipeDef& def : m_config.recipes.recipes)
|
||||
{
|
||||
if (def.id == entry.id && !def.outputs.empty())
|
||||
{
|
||||
option.displayName = toDisplayName(def.outputs[0].item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_pendingSchematicChoices.push_back(option);
|
||||
}
|
||||
}
|
||||
|
||||
void Simulation::applySchematicChoice(int choiceIndex)
|
||||
{
|
||||
assert(choiceIndex >= 0 && choiceIndex < static_cast<int>(m_pendingSchematicChoices.size()));
|
||||
const SchematicChoiceOption& chosen = m_pendingSchematicChoices[static_cast<std::size_t>(choiceIndex)];
|
||||
|
||||
if (chosen.type == SchematicType::Recipe)
|
||||
{
|
||||
m_unlockedRecipeSchematicIds.insert(chosen.schematicId);
|
||||
}
|
||||
else
|
||||
{
|
||||
SchematicState& state = (chosen.type == DropType::Module)
|
||||
? m_moduleSchematicLevels.at(chosen.id)
|
||||
: m_schematicLevels.at(chosen.id);
|
||||
const bool wasNew = !state.unlocked;
|
||||
SchematicState& state = (chosen.type == SchematicType::Module)
|
||||
? m_moduleSchematicLevels.at(chosen.schematicId)
|
||||
: m_schematicLevels.at(chosen.schematicId);
|
||||
state.unlocked = true;
|
||||
state.level += 1;
|
||||
|
||||
SchematicDropEvent evt;
|
||||
evt.schematicId = chosen.id;
|
||||
evt.newLevel = state.level;
|
||||
evt.wasNewUnlock = wasNew;
|
||||
evt.isModuleSchematic = (chosen.type == DropType::Module);
|
||||
m_schematicDropEvents.push_back(evt);
|
||||
|
||||
recomputeUnlocked();
|
||||
}
|
||||
|
||||
recomputeUnlocked();
|
||||
m_pendingSchematicChoices.clear();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -704,13 +752,17 @@ std::vector<FireEvent> Simulation::drainFireEvents()
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<SchematicDropEvent> Simulation::drainSchematicDropEvents()
|
||||
const std::vector<SchematicChoiceOption>& Simulation::getPendingSchematicChoices() const
|
||||
{
|
||||
std::vector<SchematicDropEvent> result;
|
||||
result.swap(m_schematicDropEvents);
|
||||
return result;
|
||||
return m_pendingSchematicChoices;
|
||||
}
|
||||
|
||||
bool Simulation::hasSchematicChoicesPending() const
|
||||
{
|
||||
return !m_pendingSchematicChoices.empty();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Accessors
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "BeltSystem.h"
|
||||
#include "EntityAdmin.h"
|
||||
#include "entt/entity/entity.hpp"
|
||||
#include "SchematicDropEvent.h"
|
||||
#include "SchematicChoiceOption.h"
|
||||
#include "BuildingType.h"
|
||||
#include "BuildingId.h"
|
||||
#include "EventHandler.h"
|
||||
@@ -52,8 +52,16 @@ public:
|
||||
// internal queue. Call once per rendered frame (REQ-SHP-FIRING-BEAM).
|
||||
std::vector<FireEvent> drainFireEvents();
|
||||
|
||||
// Returns all schematic drop events since the last drain.
|
||||
std::vector<SchematicDropEvent> drainSchematicDropEvents();
|
||||
// Returns the pending schematic choices (empty if no drop is pending).
|
||||
const std::vector<SchematicChoiceOption>& getPendingSchematicChoices() const;
|
||||
|
||||
// Returns true if there are pending schematic choices waiting for player input.
|
||||
bool hasSchematicChoicesPending() const;
|
||||
|
||||
// Applies the player's chosen schematic from the pending choices.
|
||||
// choiceIndex must be in [0, pendingChoices.size()).
|
||||
// Clears the pending choices after application.
|
||||
void applySchematicChoice(int choiceIndex);
|
||||
|
||||
Tick currentTick() const;
|
||||
int buildingBlocksStock() const;
|
||||
@@ -108,8 +116,8 @@ private:
|
||||
// Tick step 9: remove dead ships and buildings, drop scrap, handle push.
|
||||
void tickDeathsAndLoot();
|
||||
|
||||
// Award a random schematic drop (REQ-DEF-SCHEMATIC-DROP) and emit the event.
|
||||
void awardSchematicDrop(int destroyedStationLevel);
|
||||
// Generate up to 3 schematic choices (REQ-DEF-SCHEMATIC-DROP) for the player.
|
||||
void generateSchematicChoices(int destroyedStationLevel);
|
||||
|
||||
GameConfig m_config;
|
||||
std::mt19937 m_rng;
|
||||
@@ -158,5 +166,5 @@ private:
|
||||
std::unique_ptr<CombatSystem> m_combatSystem;
|
||||
|
||||
std::vector<FireEvent> m_fireEvents;
|
||||
std::vector<SchematicDropEvent> m_schematicDropEvents;
|
||||
std::vector<SchematicChoiceOption> m_pendingSchematicChoices;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user