rename blueprint to schematic

This commit is contained in:
2026-04-26 21:00:55 +02:00
parent 774f5dee28
commit fb83db98ab
27 changed files with 153 additions and 153 deletions

View File

@@ -358,17 +358,17 @@ ShipsConfig ConfigLoader::loadShips(const std::string& path)
def.id = requireString(mt["id"], file, elemPath + ".id");
def.availableFromStart = requireBool(mt["available_from_start"], file, elemPath + ".available_from_start");
// Blueprint
// Schematic
{
const std::string bpPath = elemPath + ".blueprint";
const toml::table& bpTable = requireTable(mt["blueprint"], file, bpPath);
const std::string bpPath = elemPath + ".schematic";
const toml::table& bpTable = requireTable(mt["schematic"], file, bpPath);
toml::table& bpMt = const_cast<toml::table&>(bpTable);
const toml::array& materials = requireArray(bpMt["materials"], file, bpPath + ".materials");
def.blueprint.materials = parseIngredients(materials, file, bpPath + ".materials");
def.blueprint.playerProductionLevel = static_cast<int>(requireInt(
def.schematic.materials = parseIngredients(materials, file, bpPath + ".materials");
def.schematic.playerProductionLevel = static_cast<int>(requireInt(
bpMt["player_production_level"], file, bpPath + ".player_production_level"));
def.blueprint.productionTimeSeconds = requireDouble(
def.schematic.productionTimeSeconds = requireDouble(
bpMt["production_time_seconds"], file, bpPath + ".production_time_seconds");
}

View File

@@ -7,9 +7,9 @@
#include "Formula.h"
#include "RecipesConfig.h" // for RecipeIngredient
// Build materials and initial per-blueprint production level
// (REQ-BLD-SHIPYARD, REQ-DEF-BLUEPRINT-DROP).
struct ShipBlueprint
// Build materials and initial per-schematic production level
// (REQ-BLD-SHIPYARD, REQ-DEF-SCHEMATIC-DROP).
struct ShipSchematic
{
std::vector<RecipeIngredient> materials;
int playerProductionLevel;
@@ -65,7 +65,7 @@ struct ShipDef
std::string id;
bool availableFromStart;
ShipBlueprint blueprint;
ShipSchematic schematic;
ShipThreat threat;
ShipHealth health;
ShipMovement movement;

View File

@@ -1,14 +0,0 @@
#pragma once
#include <string>
// Emitted in tick step 9 (Deaths & loot) when a destroyed enemy-defence-station
// set awards a blueprint (REQ-DEF-BLUEPRINT-DROP). The UI renders a toast
// (REQ-UI-BLUEPRINT-TOAST); wasNewUnlock chooses between the "unlocked" and
// "level -> N" wording.
struct BlueprintDropEvent
{
std::string blueprintId; // matches ShipDef::id in the config.
int newLevel;
bool wasNewUnlock;
};

View File

@@ -9,7 +9,7 @@ SET(HDRS
${CMAKE_CURRENT_SOURCE_DIR}/Port.h
${CMAKE_CURRENT_SOURCE_DIR}/MovementIntent.h
${CMAKE_CURRENT_SOURCE_DIR}/FireEvent.h
${CMAKE_CURRENT_SOURCE_DIR}/BlueprintDropEvent.h
${CMAKE_CURRENT_SOURCE_DIR}/SchematicDropEvent.h
PARENT_SCOPE
)

View File

@@ -0,0 +1,14 @@
#pragma once
#include <string>
// Emitted in tick step 9 (Deaths & loot) when a destroyed enemy-defence-station
// set awards a schematic (REQ-DEF-SCHEMATIC-DROP). The UI renders a toast
// (REQ-UI-SCHEMATIC-TOAST); wasNewUnlock chooses between the "unlocked" and
// "level -> N" wording.
struct SchematicDropEvent
{
std::string schematicId; // matches ShipDef::id in the config.
int newLevel;
bool wasNewUnlock;
};

View File

@@ -111,7 +111,7 @@ void BuildingSystem::initShipyardBuffers(Building& b) const
{
return;
}
for (const RecipeIngredient& ing : def->blueprint.materials)
for (const RecipeIngredient& ing : def->schematic.materials)
{
const ItemType type{ing.item};
b.inputBuffer.counts[type] = 0;
@@ -666,7 +666,7 @@ void BuildingSystem::tickShipyardProduction(Tick currentTick)
// Idle: check if all materials are available to start a new cycle.
bool inputsOk = true;
for (const RecipeIngredient& ing : shipDef->blueprint.materials)
for (const RecipeIngredient& ing : shipDef->schematic.materials)
{
const ItemType type{ing.item};
const std::map<ItemType, int>::const_iterator it =
@@ -684,7 +684,7 @@ void BuildingSystem::tickShipyardProduction(Tick currentTick)
}
// Consume materials and start the production cycle.
for (const RecipeIngredient& ing : shipDef->blueprint.materials)
for (const RecipeIngredient& ing : shipDef->schematic.materials)
{
building.inputBuffer.counts[ItemType{ing.item}] -= ing.amount;
}
@@ -692,7 +692,7 @@ void BuildingSystem::tickShipyardProduction(Tick currentTick)
Production prod;
prod.recipeId = building.recipeId;
prod.completesAt = currentTick
+ secondsToTicks(shipDef->blueprint.productionTimeSeconds);
+ secondsToTicks(shipDef->schematic.productionTimeSeconds);
building.production = std::move(prod);
}
}

View File

@@ -46,7 +46,7 @@ public:
// unknown ids.
int demolish(EntityId id);
// Set the recipe (or blueprint id for shipyard) on a building or queued
// Set the recipe (or schematic id for shipyard) on a building or queued
// construction site. Clears both buffers on an operational building.
void setRecipe(EntityId id, const std::string& recipeId);

View File

@@ -75,7 +75,7 @@ struct Ship
float maxHp;
float speedPerTick; // pre-evaluated from speedFormula / kTickRateHz
int level;
std::string blueprintId;
std::string schematicId;
bool isEnemy = false; // true for enemy-faction ships (used by behavior systems)

View File

@@ -18,11 +18,11 @@ ShipSystem::ShipSystem(const GameConfig& config,
{
}
const ShipDef* ShipSystem::findShipDef(const std::string& blueprintId) const
const ShipDef* ShipSystem::findShipDef(const std::string& schematicId) const
{
for (const ShipDef& def : m_config.ships.ships)
{
if (def.id == blueprintId)
if (def.id == schematicId)
{
return &def;
}
@@ -30,10 +30,10 @@ const ShipDef* ShipSystem::findShipDef(const std::string& blueprintId) const
return nullptr;
}
EntityId ShipSystem::spawn(const std::string& blueprintId, int level, QVector2D position,
EntityId ShipSystem::spawn(const std::string& schematicId, int level, QVector2D position,
bool isEnemy)
{
const ShipDef* def = findShipDef(blueprintId);
const ShipDef* def = findShipDef(schematicId);
assert(def != nullptr);
const double x = static_cast<double>(level);
@@ -48,7 +48,7 @@ EntityId ShipSystem::spawn(const std::string& blueprintId, int level, QVector2D
def->movement.speedFormula.evaluate(x))
/ static_cast<float>(kTickRateHz);
ship.level = level;
ship.blueprintId = blueprintId;
ship.schematicId = schematicId;
ship.isEnemy = isEnemy;
ship.intent = MovementIntent{0, QVector2D(0.0f, 0.0f)};

View File

@@ -19,7 +19,7 @@ public:
std::function<EntityId()> allocateId);
// isEnemy defaults to false; set true for enemy-faction ships (step 7 wave spawning).
EntityId spawn(const std::string& blueprintId, int level, QVector2D position,
EntityId spawn(const std::string& schematicId, int level, QVector2D position,
bool isEnemy = false);
void despawn(EntityId id);
@@ -52,7 +52,7 @@ public:
bool damageShip(EntityId id, float amount);
private:
const ShipDef* findShipDef(const std::string& blueprintId) const;
const ShipDef* findShipDef(const std::string& schematicId) const;
// True if the entity identified by id is alive and within range of ship.
// Searches both the ship list and (for buildings) the supplied BuildingSystem.

View File

@@ -30,9 +30,9 @@ Simulation::Simulation(GameConfig config, unsigned int seed)
[this]() { return allocateId(); },
[this](int amount) { m_buildingBlocksStock += amount; },
[this](const std::string& id, QVector2D pos) {
const std::map<std::string, BlueprintState>::const_iterator it =
m_blueprintLevels.find(id);
if (it == m_blueprintLevels.end() || !it->second.unlocked)
const std::map<std::string, SchematicState>::const_iterator it =
m_schematicLevels.find(id);
if (it == m_schematicLevels.end() || !it->second.unlocked)
{
return;
}
@@ -44,13 +44,13 @@ Simulation::Simulation(GameConfig config, unsigned int seed)
m_waveSystem = std::make_unique<WaveSystem>(m_config, m_rng);
m_combatSystem = std::make_unique<CombatSystem>(m_config);
// Initialize blueprint unlock state.
// Initialize schematic unlock state.
for (const ShipDef& def : m_config.ships.ships)
{
BlueprintState state;
SchematicState state;
state.unlocked = def.availableFromStart;
state.level = def.availableFromStart ? def.blueprint.playerProductionLevel : 0;
m_blueprintLevels[def.id] = state;
state.level = def.availableFromStart ? def.schematic.playerProductionLevel : 0;
m_schematicLevels[def.id] = state;
}
placeInitialStructures();
@@ -82,7 +82,7 @@ void Simulation::reset(unsigned int seed)
m_currentEnemyStationIds[0] = kInvalidEntityId;
m_currentEnemyStationIds[1] = kInvalidEntityId;
m_fireEvents.clear();
m_blueprintDropEvents.clear();
m_schematicDropEvents.clear();
m_beltSystem = BeltSystem(m_config.world.beltSpeedTilesPerSecond);
m_buildingSystem = std::make_unique<BuildingSystem>(
@@ -91,9 +91,9 @@ void Simulation::reset(unsigned int seed)
[this]() { return allocateId(); },
[this](int amount) { m_buildingBlocksStock += amount; },
[this](const std::string& id, QVector2D pos) {
const std::map<std::string, BlueprintState>::const_iterator it =
m_blueprintLevels.find(id);
if (it == m_blueprintLevels.end() || !it->second.unlocked)
const std::map<std::string, SchematicState>::const_iterator it =
m_schematicLevels.find(id);
if (it == m_schematicLevels.end() || !it->second.unlocked)
{
return;
}
@@ -105,13 +105,13 @@ void Simulation::reset(unsigned int seed)
m_waveSystem = std::make_unique<WaveSystem>(m_config, m_rng);
m_combatSystem = std::make_unique<CombatSystem>(m_config);
m_blueprintLevels.clear();
m_schematicLevels.clear();
for (const ShipDef& def : m_config.ships.ships)
{
BlueprintState state;
SchematicState state;
state.unlocked = def.availableFromStart;
state.level = def.availableFromStart ? def.blueprint.playerProductionLevel : 0;
m_blueprintLevels[def.id] = state;
state.level = def.availableFromStart ? def.schematic.playerProductionLevel : 0;
m_schematicLevels[def.id] = state;
}
placeInitialStructures();
@@ -290,7 +290,7 @@ void Simulation::tickDeathsAndLoot()
// Look up scrap drop amount from config.
for (const ShipDef& def : m_config.ships.ships)
{
if (def.id == s->blueprintId && def.loot.scrapDrop > 0)
if (def.id == s->schematicId && def.loot.scrapDrop > 0)
{
const Tick despawnAt = m_currentTick
+ secondsToTicks(m_config.world.scrapDespawnSeconds);
@@ -366,11 +366,11 @@ void Simulation::tickDeathsAndLoot()
{
m_waveSystem->applyPush();
placeEnemyStationSet(m_waveSystem->generation());
awardBlueprintDrop();
awardSchematicDrop();
}
}
void Simulation::awardBlueprintDrop()
void Simulation::awardSchematicDrop()
{
std::vector<std::string> ids;
ids.reserve(m_config.ships.ships.size());
@@ -382,16 +382,16 @@ void Simulation::awardBlueprintDrop()
std::uniform_int_distribution<int> dist(0, static_cast<int>(ids.size()) - 1);
const std::string chosen = ids[static_cast<std::size_t>(dist(m_rng))];
BlueprintState& state = m_blueprintLevels.at(chosen);
SchematicState& state = m_schematicLevels.at(chosen);
const bool wasNew = !state.unlocked;
state.unlocked = true;
state.level += 1;
BlueprintDropEvent evt;
evt.blueprintId = chosen;
SchematicDropEvent evt;
evt.schematicId = chosen;
evt.newLevel = state.level;
evt.wasNewUnlock = wasNew;
m_blueprintDropEvents.push_back(evt);
m_schematicDropEvents.push_back(evt);
}
// ---------------------------------------------------------------------------
@@ -405,10 +405,10 @@ std::vector<FireEvent> Simulation::drainFireEvents()
return result;
}
std::vector<BlueprintDropEvent> Simulation::drainBlueprintDropEvents()
std::vector<SchematicDropEvent> Simulation::drainSchematicDropEvents()
{
std::vector<BlueprintDropEvent> result;
result.swap(m_blueprintDropEvents);
std::vector<SchematicDropEvent> result;
result.swap(m_schematicDropEvents);
return result;
}
@@ -436,22 +436,22 @@ double Simulation::threatLevel() const
return m_waveSystem->threatLevel();
}
int Simulation::blueprintLevel(const std::string& shipId) const
int Simulation::schematicLevel(const std::string& shipId) const
{
const std::map<std::string, BlueprintState>::const_iterator it =
m_blueprintLevels.find(shipId);
if (it == m_blueprintLevels.end())
const std::map<std::string, SchematicState>::const_iterator it =
m_schematicLevels.find(shipId);
if (it == m_schematicLevels.end())
{
return 0;
}
return it->second.level;
}
bool Simulation::isBlueprintUnlocked(const std::string& shipId) const
bool Simulation::isSchematicUnlocked(const std::string& shipId) const
{
const std::map<std::string, BlueprintState>::const_iterator it =
m_blueprintLevels.find(shipId);
if (it == m_blueprintLevels.end())
const std::map<std::string, SchematicState>::const_iterator it =
m_schematicLevels.find(shipId);
if (it == m_schematicLevels.end())
{
return false;
}

View File

@@ -9,7 +9,7 @@
#include <QPoint>
#include "BeltSystem.h"
#include "BlueprintDropEvent.h"
#include "SchematicDropEvent.h"
#include "BuildingType.h"
#include "EntityId.h"
#include "FireEvent.h"
@@ -44,17 +44,17 @@ public:
// internal queue. Call once per rendered frame (REQ-SHP-FIRING-BEAM).
std::vector<FireEvent> drainFireEvents();
// Returns all blueprint drop events since the last drain.
std::vector<BlueprintDropEvent> drainBlueprintDropEvents();
// Returns all schematic drop events since the last drain.
std::vector<SchematicDropEvent> drainSchematicDropEvents();
Tick currentTick() const;
int buildingBlocksStock() const;
bool isGameOver() const;
double threatLevel() const;
// Blueprint state queries.
int blueprintLevel(const std::string& shipId) const;
bool isBlueprintUnlocked(const std::string& shipId) const;
// Schematic state queries.
int schematicLevel(const std::string& shipId) const;
bool isSchematicUnlocked(const std::string& shipId) const;
// Checks affordability, deducts building blocks, and places the building.
// Returns the new entity id, or kInvalidEntityId if blocks are insufficient.
@@ -85,8 +85,8 @@ private:
// Tick step 9: remove dead ships and buildings, drop scrap, handle push.
void tickDeathsAndLoot();
// Award a random blueprint drop (REQ-DEF-BLUEPRINT-DROP) and emit the event.
void awardBlueprintDrop();
// Award a random schematic drop (REQ-DEF-SCHEMATIC-DROP) and emit the event.
void awardSchematicDrop();
GameConfig m_config;
std::mt19937 m_rng;
@@ -102,13 +102,13 @@ private:
EntityId m_playerStation2Id;
EntityId m_currentEnemyStationIds[2];
// Blueprint unlock state (REQ-DEF-BLUEPRINT-DROP).
struct BlueprintState
// Schematic unlock state (REQ-DEF-SCHEMATIC-DROP).
struct SchematicState
{
bool unlocked;
int level;
};
std::map<std::string, BlueprintState> m_blueprintLevels;
std::map<std::string, SchematicState> m_schematicLevels;
BeltSystem m_beltSystem;
std::unique_ptr<BuildingSystem> m_buildingSystem;
@@ -118,5 +118,5 @@ private:
std::unique_ptr<CombatSystem> m_combatSystem;
std::vector<FireEvent> m_fireEvents;
std::vector<BlueprintDropEvent> m_blueprintDropEvents;
std::vector<SchematicDropEvent> m_schematicDropEvents;
};

View File

@@ -33,7 +33,7 @@ void WaveSystem::tickWaveScheduler(Tick currentTick, ShipSystem& ships,
{
if (currentTick >= entry.spawnAt)
{
ships.spawn(entry.blueprintId, entry.level, entry.position,
ships.spawn(entry.schematicId, entry.level, entry.position,
/*isEnemy=*/true);
}
else
@@ -90,7 +90,7 @@ std::vector<WaveSystem::SpawnEntry> WaveSystem::composeWave(Tick currentTick,
// Build eligible ship list with their costs at the current level.
struct EligibleShip
{
std::string blueprintId;
std::string schematicId;
double cost;
};
std::vector<EligibleShip> eligible;
@@ -100,7 +100,7 @@ std::vector<WaveSystem::SpawnEntry> WaveSystem::composeWave(Tick currentTick,
if (cost > 0.0)
{
EligibleShip es;
es.blueprintId = def.id;
es.schematicId = def.id;
es.cost = cost;
eligible.push_back(es);
}
@@ -151,7 +151,7 @@ std::vector<WaveSystem::SpawnEntry> WaveSystem::composeWave(Tick currentTick,
budget -= chosen.cost;
SpawnEntry entry;
entry.blueprintId = chosen.blueprintId;
entry.schematicId = chosen.schematicId;
entry.level = shipLevel;
entry.spawnAt = 0; // set below after all picks are done
entry.position = QVector2D(xDist(m_rng),

View File

@@ -40,7 +40,7 @@ public:
private:
struct SpawnEntry
{
std::string blueprintId;
std::string schematicId;
int level;
Tick spawnAt;
QVector2D position;

View File

@@ -221,7 +221,7 @@ TEST_CASE("CombatSystem: player station fires at enemy ship in range", "[combat]
}
}
// Find a combat ship blueprint for the enemy.
// Find a combat ship schematic for the enemy.
const ShipDef* combatDef = findCombatShip(sim.config());
REQUIRE(combatDef != nullptr);

View File

@@ -17,11 +17,11 @@ static GameConfig loadConfig()
return ConfigLoader::loadFromDirectory(DOTA_FACTORY_CONFIG_DIR);
}
static const ShipDef* findAvailableBlueprint(const GameConfig& cfg)
static const ShipDef* findAvailableSchematic(const GameConfig& cfg)
{
for (const ShipDef& def : cfg.ships.ships)
{
if (def.availableFromStart && !def.blueprint.materials.empty())
if (def.availableFromStart && !def.schematic.materials.empty())
{
return &def;
}
@@ -59,7 +59,7 @@ static void fillMaterials(Simulation& sim, EntityId yardId, const ShipDef& def)
{
return;
}
for (const RecipeIngredient& ing : def.blueprint.materials)
for (const RecipeIngredient& ing : def.schematic.materials)
{
b.inputBuffer.counts[ItemType{ing.item}] = ing.amount;
}
@@ -75,7 +75,7 @@ TEST_CASE("Shipyard: spawns a player ship after production cycle completes",
{
Simulation sim(loadConfig(), 42);
const ShipDef* def = findAvailableBlueprint(sim.config());
const ShipDef* def = findAvailableSchematic(sim.config());
REQUIRE(def != nullptr);
const BuildingDef* yardDef = findShipyardDef(sim.config());
REQUIRE(yardDef != nullptr);
@@ -93,7 +93,7 @@ TEST_CASE("Shipyard: spawns a player ship after production cycle completes",
REQUIRE(static_cast<int>(sim.ships().allShips().size()) == shipsBefore);
// Tick until the cycle completes.
const Tick cycleTicks = secondsToTicks(def->blueprint.productionTimeSeconds);
const Tick cycleTicks = secondsToTicks(def->schematic.productionTimeSeconds);
for (Tick i = 1; i < cycleTicks; ++i)
{
sim.tick();
@@ -107,7 +107,7 @@ TEST_CASE("Shipyard: spawns a player ship after production cycle completes",
bool foundPlayerShip = false;
for (const Ship& ship : sim.ships().allShips())
{
if (!ship.isEnemy && ship.blueprintId == def->id)
if (!ship.isEnemy && ship.schematicId == def->id)
{
foundPlayerShip = true;
break;
@@ -116,7 +116,7 @@ TEST_CASE("Shipyard: spawns a player ship after production cycle completes",
REQUIRE(foundPlayerShip);
}
TEST_CASE("Shipyard: does not spawn without a blueprint set", "[shipyard]")
TEST_CASE("Shipyard: does not spawn without a schematic set", "[shipyard]")
{
Simulation sim(loadConfig(), 42);
@@ -136,7 +136,7 @@ TEST_CASE("Shipyard: does not spawn with insufficient materials", "[shipyard]")
{
Simulation sim(loadConfig(), 42);
const ShipDef* def = findAvailableBlueprint(sim.config());
const ShipDef* def = findAvailableSchematic(sim.config());
REQUIRE(def != nullptr);
const BuildingDef* yardDef = findShipyardDef(sim.config());
REQUIRE(yardDef != nullptr);
@@ -147,7 +147,7 @@ TEST_CASE("Shipyard: does not spawn with insufficient materials", "[shipyard]")
sim.buildings().setRecipe(yardId, def->id);
// Materials remain at zero (default after setRecipe); no cycle starts.
const Tick cycleTicks = secondsToTicks(def->blueprint.productionTimeSeconds);
const Tick cycleTicks = secondsToTicks(def->schematic.productionTimeSeconds);
for (Tick i = 0; i <= cycleTicks; ++i)
{
sim.tick();
@@ -160,7 +160,7 @@ TEST_CASE("Shipyard: spawns a second ship after materials replenished", "[shipya
{
Simulation sim(loadConfig(), 42);
const ShipDef* def = findAvailableBlueprint(sim.config());
const ShipDef* def = findAvailableSchematic(sim.config());
REQUIRE(def != nullptr);
const BuildingDef* yardDef = findShipyardDef(sim.config());
REQUIRE(yardDef != nullptr);
@@ -168,7 +168,7 @@ TEST_CASE("Shipyard: spawns a second ship after materials replenished", "[shipya
const EntityId yardId = placeShipyard(sim, *yardDef);
sim.buildings().setRecipe(yardId, def->id);
const Tick cycleTicks = secondsToTicks(def->blueprint.productionTimeSeconds);
const Tick cycleTicks = secondsToTicks(def->schematic.productionTimeSeconds);
// First cycle: capture count immediately after the spawn tick.
fillMaterials(sim, yardId, *def);

View File

@@ -61,11 +61,11 @@ TEST_CASE("Simulation::drainFireEvents clears queue on drain", "[simulation]")
REQUIRE(sim.drainFireEvents().empty());
}
TEST_CASE("Simulation::drainBlueprintDropEvents returns empty initially", "[simulation]")
TEST_CASE("Simulation::drainSchematicDropEvents returns empty initially", "[simulation]")
{
Simulation sim(loadConfig());
REQUIRE(sim.drainBlueprintDropEvents().empty());
REQUIRE(sim.drainSchematicDropEvents().empty());
}
// ---------------------------------------------------------------------------

View File

@@ -233,8 +233,8 @@ TEST_CASE("WaveSystem: only eligible ships (cost > 0) appear in waves", "[wave]"
{
if (!s.isEnemy) { continue; }
// salvage_ship and repair_ship have cost_formula = "0" and must not spawn.
REQUIRE(s.blueprintId != "salvage_ship");
REQUIRE(s.blueprintId != "repair_ship");
REQUIRE(s.schematicId != "salvage_ship");
REQUIRE(s.schematicId != "repair_ship");
}
}
@@ -266,7 +266,7 @@ TEST_CASE("WaveSystem: destroying both enemy stations triggers a push", "[wave]"
REQUIRE(enemyCount == 2);
}
TEST_CASE("WaveSystem: push emits exactly one BlueprintDropEvent", "[wave]")
TEST_CASE("WaveSystem: push emits exactly one SchematicDropEvent", "[wave]")
{
Simulation sim(loadConfig(), 42);
@@ -280,11 +280,11 @@ TEST_CASE("WaveSystem: push emits exactly one BlueprintDropEvent", "[wave]")
sim.tick();
const std::vector<BlueprintDropEvent> events = sim.drainBlueprintDropEvents();
const std::vector<SchematicDropEvent> events = sim.drainSchematicDropEvents();
REQUIRE(events.size() == 1);
}
TEST_CASE("WaveSystem: push blueprint drop awards a known ship id", "[wave]")
TEST_CASE("WaveSystem: push schematic drop awards a known ship id", "[wave]")
{
Simulation sim(loadConfig(), 42);
@@ -297,13 +297,13 @@ TEST_CASE("WaveSystem: push blueprint drop awards a known ship id", "[wave]")
});
sim.tick();
const std::vector<BlueprintDropEvent> events = sim.drainBlueprintDropEvents();
const std::vector<SchematicDropEvent> events = sim.drainSchematicDropEvents();
REQUIRE(events.size() == 1);
bool validId = false;
for (const ShipDef& def : sim.config().ships.ships)
{
if (def.id == events[0].blueprintId)
if (def.id == events[0].schematicId)
{
validId = true;
break;

View File

@@ -2,7 +2,7 @@
id = "interceptor"
available_from_start = true
[ship.blueprint]
[ship.schematic]
materials = [{item = "iron_ingot", amount = 3}, {item = "circuit_board", amount = 1}]
player_production_level = 3
production_time_seconds = 10
@@ -29,7 +29,7 @@ scrap_drop = 2
id = "destroyer"
available_from_start = true
[ship.blueprint]
[ship.schematic]
materials = [{item = "iron_ingot", amount = 5}, {item = "circuit_board", amount = 2}]
player_production_level = 5
production_time_seconds = 20
@@ -56,7 +56,7 @@ scrap_drop = 4
id = "salvage_ship"
available_from_start = true
[ship.blueprint]
[ship.schematic]
materials = [{item = "iron_ingot", amount = 4}]
player_production_level = 3
production_time_seconds = 10
@@ -82,7 +82,7 @@ scrap_drop = 2
id = "repair_ship"
available_from_start = false
[ship.blueprint]
[ship.schematic]
materials = [{item = "iron_ingot", amount = 4}, {item = "circuit_board", amount = 2}]
player_production_level = 3
production_time_seconds = 15

View File

@@ -163,17 +163,17 @@ void GameWorldView::onFrame()
}
}
// Drain blueprint drop events → toasts
// Drain schematic drop events → toasts
{
const std::vector<BlueprintDropEvent> drops =
m_sim->drainBlueprintDropEvents();
for (const BlueprintDropEvent& ev : drops)
const std::vector<SchematicDropEvent> drops =
m_sim->drainSchematicDropEvents();
for (const SchematicDropEvent& ev : drops)
{
const QString shipName = toDisplayName(ev.blueprintId);
const QString shipName = toDisplayName(ev.schematicId);
ToastEntry toast;
if (ev.wasNewUnlock)
{
toast.text = "Blueprint unlocked: " + shipName;
toast.text = "Schematic unlocked: " + shipName;
}
else
{

View File

@@ -11,7 +11,7 @@
#include <QTimer>
#include <QVector2D>
#include "BlueprintDropEvent.h"
#include "SchematicDropEvent.h"
#include "BuildingType.h"
#include "EntityId.h"
#include "FireEvent.h"

View File

@@ -187,7 +187,7 @@ void SelectedBuildingPanel::buildSingle(EntityId id)
{
for (const ShipDef& def : m_config->ships.ships)
{
if (m_sim->isBlueprintUnlocked(def.id))
if (m_sim->isSchematicUnlocked(def.id))
{
m_recipeCombo->addItem(
QString::fromStdString(def.id),
@@ -267,7 +267,7 @@ void SelectedBuildingPanel::refreshBuffers(const Building* b)
}
else if (shipDef)
{
for (const RecipeIngredient& mat : shipDef->blueprint.materials)
for (const RecipeIngredient& mat : shipDef->schematic.materials)
{
if (mat.item == entry.first.id) { perCycle = mat.amount; break; }
}
@@ -320,7 +320,7 @@ void SelectedBuildingPanel::refreshBuffers(const Building* b)
{
const double durationSeconds = recipe
? recipe->durationSeconds
: shipDef->blueprint.productionTimeSeconds;
: shipDef->schematic.productionTimeSeconds;
bufText += QString("Cycle: %1 s\n").arg(durationSeconds, 0, 'f', 1);