rename EntityId to BuildingId
This commit is contained in:
@@ -27,7 +27,7 @@ ArenaSimulation::ArenaSimulation(const GameConfig& gameConfig,
|
|||||||
, m_arenaConfig(std::move(arenaConfig))
|
, m_arenaConfig(std::move(arenaConfig))
|
||||||
, m_rng(seed)
|
, m_rng(seed)
|
||||||
, m_currentTick(0)
|
, m_currentTick(0)
|
||||||
, m_nextId(1)
|
, m_nextBuildingId(1)
|
||||||
, m_beltSystem(1.0)
|
, m_beltSystem(1.0)
|
||||||
, m_team1HqEntity(entt::null)
|
, m_team1HqEntity(entt::null)
|
||||||
, m_team2HqEntity(entt::null)
|
, m_team2HqEntity(entt::null)
|
||||||
@@ -38,7 +38,7 @@ ArenaSimulation::ArenaSimulation(const GameConfig& gameConfig,
|
|||||||
m_buildingSystem = std::make_unique<BuildingSystem>(
|
m_buildingSystem = std::make_unique<BuildingSystem>(
|
||||||
m_gameConfig,
|
m_gameConfig,
|
||||||
m_beltSystem,
|
m_beltSystem,
|
||||||
[this]() { return allocateId(); },
|
[this]() { return allocateBuildingId(); },
|
||||||
[](int) {},
|
[](int) {},
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
m_rng);
|
m_rng);
|
||||||
@@ -59,9 +59,9 @@ ArenaSimulation::ArenaSimulation(const GameConfig& gameConfig,
|
|||||||
|
|
||||||
ArenaSimulation::~ArenaSimulation() = default;
|
ArenaSimulation::~ArenaSimulation() = default;
|
||||||
|
|
||||||
EntityId ArenaSimulation::allocateId()
|
BuildingId ArenaSimulation::allocateBuildingId()
|
||||||
{
|
{
|
||||||
return m_nextId++;
|
return m_nextBuildingId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArenaSimulation::placeStructures()
|
void ArenaSimulation::placeStructures()
|
||||||
@@ -89,7 +89,7 @@ void ArenaSimulation::placeStructures()
|
|||||||
anchorY + hqParsed.footprint.height() / 2.0f);
|
anchorY + hqParsed.footprint.height() / 2.0f);
|
||||||
m_team1HqEntity = m_admin.spawnStation(anchor, hqParsed.footprint, absCells,
|
m_team1HqEntity = m_admin.spawnStation(anchor, hqParsed.footprint, absCells,
|
||||||
hp, hp, false);
|
hp, hp, false);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Team 2 HQ — ECS proxy entity, enemy faction (isEnemy=true). No weapon.
|
// Team 2 HQ — ECS proxy entity, enemy faction (isEnemy=true). No weapon.
|
||||||
@@ -108,7 +108,7 @@ void ArenaSimulation::placeStructures()
|
|||||||
}
|
}
|
||||||
m_team2HqEntity = m_admin.spawnStation(anchor, hqParsed.footprint, absCells,
|
m_team2HqEntity = m_admin.spawnStation(anchor, hqParsed.footprint, absCells,
|
||||||
hp, hp, true);
|
hp, hp, true);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto placeArenaStation = [&](const ArenaStationEntry& entry, bool isEnemy)
|
auto placeArenaStation = [&](const ArenaStationEntry& entry, bool isEnemy)
|
||||||
@@ -156,7 +156,7 @@ void ArenaSimulation::placeStructures()
|
|||||||
const entt::entity stationEntity = m_admin.spawnStation(
|
const entt::entity stationEntity = m_admin.spawnStation(
|
||||||
anchor, parsed.footprint, absCells, hp, hp, isEnemy);
|
anchor, parsed.footprint, absCells, hp, hp, isEnemy);
|
||||||
m_admin.addComponent<Weapon>(stationEntity, weapon);
|
m_admin.addComponent<Weapon>(stationEntity, weapon);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const ArenaStationEntry& entry : m_arenaConfig.teams[0].stations)
|
for (const ArenaStationEntry& entry : m_arenaConfig.teams[0].stations)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#include "BeltSystem.h"
|
#include "BeltSystem.h"
|
||||||
#include "EcsComponents.h"
|
#include "EcsComponents.h"
|
||||||
#include "EntityAdmin.h"
|
#include "EntityAdmin.h"
|
||||||
#include "EntityId.h"
|
#include "BuildingId.h"
|
||||||
|
|
||||||
#include "entt/entity/entity.hpp"
|
#include "entt/entity/entity.hpp"
|
||||||
#include "FireEvent.h"
|
#include "FireEvent.h"
|
||||||
@@ -73,7 +73,7 @@ public:
|
|||||||
const EntityAdmin& admin() const;
|
const EntityAdmin& admin() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EntityId allocateId();
|
BuildingId allocateBuildingId();
|
||||||
void placeStructures();
|
void placeStructures();
|
||||||
void spawnShips();
|
void spawnShips();
|
||||||
void tick();
|
void tick();
|
||||||
@@ -85,7 +85,7 @@ private:
|
|||||||
std::mt19937 m_rng;
|
std::mt19937 m_rng;
|
||||||
|
|
||||||
Tick m_currentTick;
|
Tick m_currentTick;
|
||||||
EntityId m_nextId;
|
BuildingId m_nextBuildingId;
|
||||||
|
|
||||||
EntityAdmin m_admin;
|
EntityAdmin m_admin;
|
||||||
BeltSystem m_beltSystem;
|
BeltSystem m_beltSystem;
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
// Ships, stations, scrap, and the HQ proxy use entt::entity instead.
|
// Ships, stations, scrap, and the HQ proxy use entt::entity instead.
|
||||||
// Ids are allocated centrally by the Simulation, strictly increasing, never
|
// Ids are allocated centrally by the Simulation, strictly increasing, never
|
||||||
// reused. 0 is reserved as the invalid id.
|
// reused. 0 is reserved as the invalid id.
|
||||||
using EntityId = long long;
|
using BuildingId = long long;
|
||||||
|
|
||||||
constexpr EntityId kInvalidEntityId = 0;
|
constexpr BuildingId kInvalidBuildingId = 0;
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
SET(HDRS
|
SET(HDRS
|
||||||
${HDRS}
|
${HDRS}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Tick.h
|
${CMAKE_CURRENT_SOURCE_DIR}/Tick.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/EntityId.h
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Rotation.h
|
${CMAKE_CURRENT_SOURCE_DIR}/Rotation.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingType.h
|
${CMAKE_CURRENT_SOURCE_DIR}/BuildingType.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/EntityAdmin.h
|
${CMAKE_CURRENT_SOURCE_DIR}/EntityAdmin.h
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include <QSize>
|
#include <QSize>
|
||||||
#include <QVector2D>
|
#include <QVector2D>
|
||||||
|
|
||||||
#include "EntityId.h"
|
|
||||||
#include "Tick.h"
|
#include "Tick.h"
|
||||||
|
|
||||||
#include "entt/entity/entity.hpp"
|
#include "entt/entity/entity.hpp"
|
||||||
@@ -104,3 +103,4 @@ struct DespawnAt
|
|||||||
|
|
||||||
struct HqProxy { char unused = 0; };
|
struct HqProxy { char unused = 0; };
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include "BuildingType.h"
|
#include "BuildingType.h"
|
||||||
#include "EcsComponents.h"
|
#include "EcsComponents.h"
|
||||||
#include "EntityAdmin.h"
|
#include "EntityAdmin.h"
|
||||||
#include "EntityId.h"
|
#include "BuildingId.h"
|
||||||
#include "MovementIntent.h"
|
#include "MovementIntent.h"
|
||||||
#include "ScrapSystem.h"
|
#include "ScrapSystem.h"
|
||||||
#include "Ship.h"
|
#include "Ship.h"
|
||||||
@@ -329,7 +329,7 @@ void AiSystem::tickScrapCollector(EntityAdmin& admin, ScrapSystem& scraps,
|
|||||||
const float collectRange = cargo.collectionRange;
|
const float collectRange = cargo.collectionRange;
|
||||||
|
|
||||||
// Assign nearest SalvageBay if needed.
|
// Assign nearest SalvageBay if needed.
|
||||||
if (sc.deliveryBay == kInvalidEntityId)
|
if (sc.deliveryBay == kInvalidBuildingId)
|
||||||
{
|
{
|
||||||
const Building* bay = buildings.findNearestBuilding(pos.value,
|
const Building* bay = buildings.findNearestBuilding(pos.value,
|
||||||
BuildingType::SalvageBay);
|
BuildingType::SalvageBay);
|
||||||
@@ -339,10 +339,10 @@ void AiSystem::tickScrapCollector(EntityAdmin& admin, ScrapSystem& scraps,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const EntityId bayId = sc.deliveryBay;
|
const BuildingId bayId = sc.deliveryBay;
|
||||||
|
|
||||||
QVector2D bayPos = pos.value;
|
QVector2D bayPos = pos.value;
|
||||||
if (bayId != kInvalidEntityId)
|
if (bayId != kInvalidBuildingId)
|
||||||
{
|
{
|
||||||
const Building* bay = buildings.findBuilding(bayId);
|
const Building* bay = buildings.findBuilding(bayId);
|
||||||
if (bay)
|
if (bay)
|
||||||
@@ -360,7 +360,7 @@ void AiSystem::tickScrapCollector(EntityAdmin& admin, ScrapSystem& scraps,
|
|||||||
{
|
{
|
||||||
intent = MovementIntent{1, bayPos};
|
intent = MovementIntent{1, bayPos};
|
||||||
}
|
}
|
||||||
if (bayId != kInvalidEntityId
|
if (bayId != kInvalidBuildingId
|
||||||
&& (pos.value - bayPos).length() <= 1.0f)
|
&& (pos.value - bayPos).length() <= 1.0f)
|
||||||
{
|
{
|
||||||
if (buildings.deliverScrapToSalvageBay(bayId))
|
if (buildings.deliverScrapToSalvageBay(bayId))
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
#include <QSize>
|
#include <QSize>
|
||||||
|
|
||||||
#include "BuildingType.h"
|
#include "BuildingType.h"
|
||||||
#include "EntityId.h"
|
#include "BuildingId.h"
|
||||||
|
|
||||||
#include "entt/entity/entity.hpp"
|
#include "entt/entity/entity.hpp"
|
||||||
#include "Item.h"
|
#include "Item.h"
|
||||||
@@ -45,7 +45,7 @@ struct Production
|
|||||||
// Occupies tiles but does not produce.
|
// Occupies tiles but does not produce.
|
||||||
struct ConstructionSite
|
struct ConstructionSite
|
||||||
{
|
{
|
||||||
EntityId id = kInvalidEntityId;
|
BuildingId id = kInvalidBuildingId;
|
||||||
QPoint anchor; // top-left of body bounding box
|
QPoint anchor; // top-left of body bounding box
|
||||||
QSize footprint;
|
QSize footprint;
|
||||||
std::vector<QPoint> bodyCells; // absolute world tile coordinates
|
std::vector<QPoint> bodyCells; // absolute world tile coordinates
|
||||||
@@ -59,7 +59,7 @@ struct ConstructionSite
|
|||||||
// A fully constructed, operational building.
|
// A fully constructed, operational building.
|
||||||
struct Building
|
struct Building
|
||||||
{
|
{
|
||||||
EntityId id = kInvalidEntityId;
|
BuildingId id = kInvalidBuildingId;
|
||||||
QPoint anchor; // top-left of body bounding box
|
QPoint anchor; // top-left of body bounding box
|
||||||
QSize footprint;
|
QSize footprint;
|
||||||
Rotation rotation = Rotation::East;
|
Rotation rotation = Rotation::East;
|
||||||
|
|||||||
@@ -9,14 +9,14 @@
|
|||||||
|
|
||||||
BuildingSystem::BuildingSystem(const GameConfig& config,
|
BuildingSystem::BuildingSystem(const GameConfig& config,
|
||||||
BeltSystem& belts,
|
BeltSystem& belts,
|
||||||
std::function<EntityId()> allocateId,
|
std::function<BuildingId()> allocateBuildingId,
|
||||||
std::function<void(int)> addBuildingBlocks,
|
std::function<void(int)> addBuildingBlocks,
|
||||||
std::function<void(const std::string&, QVector2D,
|
std::function<void(const std::string&, QVector2D,
|
||||||
const std::optional<ShipLayoutConfig>&)> spawnShip,
|
const std::optional<ShipLayoutConfig>&)> spawnShip,
|
||||||
std::mt19937& rng)
|
std::mt19937& rng)
|
||||||
: m_config(config)
|
: m_config(config)
|
||||||
, m_belts(belts)
|
, m_belts(belts)
|
||||||
, m_allocateId(std::move(allocateId))
|
, m_allocateBuildingId(std::move(allocateBuildingId))
|
||||||
, m_addBuildingBlocks(std::move(addBuildingBlocks))
|
, m_addBuildingBlocks(std::move(addBuildingBlocks))
|
||||||
, m_spawnShip(std::move(spawnShip))
|
, m_spawnShip(std::move(spawnShip))
|
||||||
, m_rng(rng)
|
, m_rng(rng)
|
||||||
@@ -227,10 +227,10 @@ std::vector<Item> BuildingSystem::rollReprocessingOutput(const RecipeDef& recipe
|
|||||||
// Placement
|
// Placement
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
EntityId BuildingSystem::place(BuildingType type, QPoint anchor,
|
BuildingId BuildingSystem::place(BuildingType type, QPoint anchor,
|
||||||
Rotation rotation, Tick currentTick)
|
Rotation rotation, Tick currentTick)
|
||||||
{
|
{
|
||||||
const EntityId id = m_allocateId();
|
const BuildingId id = m_allocateBuildingId();
|
||||||
|
|
||||||
const BuildingDef* def = findBuildingDef(type);
|
const BuildingDef* def = findBuildingDef(type);
|
||||||
assert(def != nullptr);
|
assert(def != nullptr);
|
||||||
@@ -269,7 +269,7 @@ EntityId BuildingSystem::place(BuildingType type, QPoint anchor,
|
|||||||
// Demolish
|
// Demolish
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
int BuildingSystem::demolish(EntityId id)
|
int BuildingSystem::demolish(BuildingId id)
|
||||||
{
|
{
|
||||||
// Construction queue?
|
// Construction queue?
|
||||||
for (std::deque<ConstructionSite>::iterator it = m_constructionQueue.begin();
|
for (std::deque<ConstructionSite>::iterator it = m_constructionQueue.begin();
|
||||||
@@ -325,7 +325,7 @@ int BuildingSystem::demolish(EntityId id)
|
|||||||
// Set recipe
|
// Set recipe
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
void BuildingSystem::setRecipe(EntityId id, const std::string& recipeId)
|
void BuildingSystem::setRecipe(BuildingId id, const std::string& recipeId)
|
||||||
{
|
{
|
||||||
// Construction site: store recipe for when building completes.
|
// Construction site: store recipe for when building completes.
|
||||||
for (ConstructionSite& site : m_constructionQueue)
|
for (ConstructionSite& site : m_constructionQueue)
|
||||||
@@ -371,7 +371,7 @@ void BuildingSystem::setRecipe(EntityId id, const std::string& recipeId)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildingSystem::setShipLayout(EntityId id, const ShipLayoutConfig& layout)
|
void BuildingSystem::setShipLayout(BuildingId id, const ShipLayoutConfig& layout)
|
||||||
{
|
{
|
||||||
for (ConstructionSite& site : m_constructionQueue)
|
for (ConstructionSite& site : m_constructionQueue)
|
||||||
{
|
{
|
||||||
@@ -821,7 +821,7 @@ void BuildingSystem::tickBeltPush()
|
|||||||
// Queries
|
// Queries
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
const Building* BuildingSystem::findBuilding(EntityId id) const
|
const Building* BuildingSystem::findBuilding(BuildingId id) const
|
||||||
{
|
{
|
||||||
for (const Building& building : m_buildings)
|
for (const Building& building : m_buildings)
|
||||||
{
|
{
|
||||||
@@ -833,7 +833,7 @@ const Building* BuildingSystem::findBuilding(EntityId id) const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ConstructionSite* BuildingSystem::findSite(EntityId id) const
|
const ConstructionSite* BuildingSystem::findSite(BuildingId id) const
|
||||||
{
|
{
|
||||||
for (const ConstructionSite& site : m_constructionQueue)
|
for (const ConstructionSite& site : m_constructionQueue)
|
||||||
{
|
{
|
||||||
@@ -866,7 +866,7 @@ std::vector<BuildingSystem::BeltTileInfo> BuildingSystem::allBeltTiles() const
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BeltTileInfo info;
|
BeltTileInfo info;
|
||||||
info.id = b.id;
|
info.buildingId = b.id;
|
||||||
info.tile = b.bodyCells.empty() ? b.anchor : b.bodyCells[0];
|
info.tile = b.bodyCells.empty() ? b.anchor : b.bodyCells[0];
|
||||||
info.type = b.type;
|
info.type = b.type;
|
||||||
if (!b.outputPorts.empty())
|
if (!b.outputPorts.empty())
|
||||||
@@ -893,7 +893,7 @@ bool BuildingSystem::isTileOccupied(QPoint tile) const
|
|||||||
return m_tileOccupancy.count({tile.x(), tile.y()}) > 0;
|
return m_tileOccupancy.count({tile.x(), tile.y()}) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<EntityId> BuildingSystem::findRotateInPlaceTarget(
|
std::optional<BuildingId> BuildingSystem::findRotateInPlaceTarget(
|
||||||
BuildingType type, QPoint anchor, Rotation rot) const
|
BuildingType type, QPoint anchor, Rotation rot) const
|
||||||
{
|
{
|
||||||
const BuildingDef* def = findBuildingDef(type);
|
const BuildingDef* def = findBuildingDef(type);
|
||||||
@@ -906,7 +906,7 @@ std::optional<EntityId> BuildingSystem::findRotateInPlaceTarget(
|
|||||||
const QPoint firstAbs = anchor + mask.bodyCells[0];
|
const QPoint firstAbs = anchor + mask.bodyCells[0];
|
||||||
const auto firstIt = m_tileOccupancy.find({firstAbs.x(), firstAbs.y()});
|
const auto firstIt = m_tileOccupancy.find({firstAbs.x(), firstAbs.y()});
|
||||||
if (firstIt == m_tileOccupancy.end()) { return std::nullopt; }
|
if (firstIt == m_tileOccupancy.end()) { return std::nullopt; }
|
||||||
const EntityId candidateId = firstIt->second;
|
const BuildingId candidateId = firstIt->second;
|
||||||
|
|
||||||
for (const QPoint& rel : mask.bodyCells)
|
for (const QPoint& rel : mask.bodyCells)
|
||||||
{
|
{
|
||||||
@@ -937,7 +937,7 @@ std::optional<EntityId> BuildingSystem::findRotateInPlaceTarget(
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildingSystem::rotateInPlace(EntityId id, Rotation newRotation)
|
void BuildingSystem::rotateInPlace(BuildingId id, Rotation newRotation)
|
||||||
{
|
{
|
||||||
// Construction site path — just update rotation; no ports to recompute.
|
// Construction site path — just update rotation; no ports to recompute.
|
||||||
for (ConstructionSite& site : m_constructionQueue)
|
for (ConstructionSite& site : m_constructionQueue)
|
||||||
@@ -1022,7 +1022,7 @@ const Building* BuildingSystem::findNearestBuilding(QVector2D worldPos,
|
|||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuildingSystem::deliverScrapToSalvageBay(EntityId bayId)
|
bool BuildingSystem::deliverScrapToSalvageBay(BuildingId bayId)
|
||||||
{
|
{
|
||||||
Building* bay = nullptr;
|
Building* bay = nullptr;
|
||||||
for (Building& b : m_buildings)
|
for (Building& b : m_buildings)
|
||||||
@@ -1045,11 +1045,11 @@ bool BuildingSystem::deliverScrapToSalvageBay(EntityId bayId)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityId BuildingSystem::placeImmediate(BuildingType type,
|
BuildingId BuildingSystem::placeImmediate(BuildingType type,
|
||||||
const std::vector<std::string>& surfaceMask,
|
const std::vector<std::string>& surfaceMask,
|
||||||
QPoint anchor, Rotation rotation)
|
QPoint anchor, Rotation rotation)
|
||||||
{
|
{
|
||||||
const EntityId id = m_allocateId();
|
const BuildingId id = m_allocateBuildingId();
|
||||||
const ParsedSurfaceMask mask = parseSurfaceMask(surfaceMask, rotation);
|
const ParsedSurfaceMask mask = parseSurfaceMask(surfaceMask, rotation);
|
||||||
|
|
||||||
Building building;
|
Building building;
|
||||||
@@ -1078,7 +1078,7 @@ EntityId BuildingSystem::placeImmediate(BuildingType type,
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuildingSystem::removeBuilding(EntityId id)
|
bool BuildingSystem::removeBuilding(BuildingId id)
|
||||||
{
|
{
|
||||||
for (std::vector<Building>::iterator it = m_buildings.begin();
|
for (std::vector<Building>::iterator it = m_buildings.begin();
|
||||||
it != m_buildings.end();
|
it != m_buildings.end();
|
||||||
@@ -1111,7 +1111,7 @@ void BuildingSystem::forEachBuilding(std::function<void(Building&)> fn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void BuildingSystem::registerTileOccupancy(const std::vector<QPoint>& cells,
|
void BuildingSystem::registerTileOccupancy(const std::vector<QPoint>& cells,
|
||||||
EntityId ownerPlaceholder)
|
BuildingId ownerPlaceholder)
|
||||||
{
|
{
|
||||||
for (const QPoint& cell : cells)
|
for (const QPoint& cell : cells)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#include "BeltSystem.h"
|
#include "BeltSystem.h"
|
||||||
#include "Building.h"
|
#include "Building.h"
|
||||||
#include "BuildingType.h"
|
#include "BuildingType.h"
|
||||||
#include "EntityId.h"
|
#include "BuildingId.h"
|
||||||
#include "GameConfig.h"
|
#include "GameConfig.h"
|
||||||
#include "Rotation.h"
|
#include "Rotation.h"
|
||||||
#include "ModulesConfig.h"
|
#include "ModulesConfig.h"
|
||||||
@@ -32,7 +32,7 @@ class BuildingSystem
|
|||||||
public:
|
public:
|
||||||
BuildingSystem(const GameConfig& config,
|
BuildingSystem(const GameConfig& config,
|
||||||
BeltSystem& belts,
|
BeltSystem& belts,
|
||||||
std::function<EntityId()> allocateId,
|
std::function<BuildingId()> allocateBuildingId,
|
||||||
std::function<void(int)> addBuildingBlocks,
|
std::function<void(int)> addBuildingBlocks,
|
||||||
std::function<void(const std::string&, QVector2D,
|
std::function<void(const std::string&, QVector2D,
|
||||||
const std::optional<ShipLayoutConfig>&)> spawnShip,
|
const std::optional<ShipLayoutConfig>&)> spawnShip,
|
||||||
@@ -41,21 +41,21 @@ public:
|
|||||||
// -- Placement / demolish ------------------------------------------------
|
// -- Placement / demolish ------------------------------------------------
|
||||||
// Returns the new entity id. Belt and Splitter register with BeltSystem
|
// Returns the new entity id. Belt and Splitter register with BeltSystem
|
||||||
// directly; other types enter the construction queue.
|
// directly; other types enter the construction queue.
|
||||||
EntityId place(BuildingType type, QPoint anchor, Rotation rotation,
|
BuildingId place(BuildingType type, QPoint anchor, Rotation rotation,
|
||||||
Tick currentTick);
|
Tick currentTick);
|
||||||
|
|
||||||
// Remove a building or construction site by id. Returns the refund in
|
// Remove a building or construction site by id. Returns the refund in
|
||||||
// building blocks (floor(cost * refundPercentage / 100)). Returns 0 for
|
// building blocks (floor(cost * refundPercentage / 100)). Returns 0 for
|
||||||
// unknown ids.
|
// unknown ids.
|
||||||
int demolish(EntityId id);
|
int demolish(BuildingId id);
|
||||||
|
|
||||||
// Set the recipe (or schematic 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.
|
// construction site. Clears both buffers on an operational building.
|
||||||
void setRecipe(EntityId id, const std::string& recipeId);
|
void setRecipe(BuildingId id, const std::string& recipeId);
|
||||||
|
|
||||||
// Set the module layout for a shipyard. Cancels in-progress production
|
// Set the module layout for a shipyard. Cancels in-progress production
|
||||||
// (materials discarded) and reinitializes input buffers (REQ-BLD-SHIPYARD).
|
// (materials discarded) and reinitializes input buffers (REQ-BLD-SHIPYARD).
|
||||||
void setShipLayout(EntityId id, const ShipLayoutConfig& layout);
|
void setShipLayout(BuildingId id, const ShipLayoutConfig& layout);
|
||||||
|
|
||||||
// -- Tick hooks (called from Simulation::tick in the documented order) ---
|
// -- Tick hooks (called from Simulation::tick in the documented order) ---
|
||||||
void tickConstruction(Tick currentTick);
|
void tickConstruction(Tick currentTick);
|
||||||
@@ -67,15 +67,15 @@ public:
|
|||||||
// -- Queries -------------------------------------------------------------
|
// -- Queries -------------------------------------------------------------
|
||||||
struct BeltTileInfo
|
struct BeltTileInfo
|
||||||
{
|
{
|
||||||
EntityId id;
|
BuildingId buildingId;
|
||||||
QPoint tile;
|
QPoint tile;
|
||||||
BuildingType type; // Belt or Splitter
|
BuildingType type; // Belt or Splitter
|
||||||
Rotation directionA; // Belt: its direction; Splitter: first output
|
Rotation directionA; // Belt: its direction; Splitter: first output
|
||||||
Rotation directionB; // Splitter: second output; Belt: same as directionA
|
Rotation directionB; // Splitter: second output; Belt: same as directionA
|
||||||
};
|
};
|
||||||
|
|
||||||
const Building* findBuilding(EntityId id) const;
|
const Building* findBuilding(BuildingId id) const;
|
||||||
const ConstructionSite* findSite(EntityId id) const;
|
const ConstructionSite* findSite(BuildingId id) const;
|
||||||
std::vector<Building> allBuildings() const;
|
std::vector<Building> allBuildings() const;
|
||||||
std::vector<ConstructionSite> allSites() const;
|
std::vector<ConstructionSite> allSites() const;
|
||||||
std::vector<BeltTileInfo> allBeltTiles() const;
|
std::vector<BeltTileInfo> allBeltTiles() const;
|
||||||
@@ -84,36 +84,36 @@ public:
|
|||||||
// Returns the entity id of the building or construction site whose footprint
|
// Returns the entity id of the building or construction site whose footprint
|
||||||
// exactly coincides with the ghost (type, anchor, rot) and is of the same
|
// exactly coincides with the ghost (type, anchor, rot) and is of the same
|
||||||
// building type. Returns nullopt otherwise.
|
// building type. Returns nullopt otherwise.
|
||||||
std::optional<EntityId> findRotateInPlaceTarget(BuildingType type,
|
std::optional<BuildingId> findRotateInPlaceTarget(BuildingType type,
|
||||||
QPoint anchor,
|
QPoint anchor,
|
||||||
Rotation rot) const;
|
Rotation rot) const;
|
||||||
|
|
||||||
// Rotate an existing building or construction site to newRotation in place.
|
// Rotate an existing building or construction site to newRotation in place.
|
||||||
// For belt-type operational buildings, re-registers with BeltSystem (items
|
// For belt-type operational buildings, re-registers with BeltSystem (items
|
||||||
// currently on the tile are discarded by BeltSystem::removeTile).
|
// currently on the tile are discarded by BeltSystem::removeTile).
|
||||||
void rotateInPlace(EntityId id, Rotation newRotation);
|
void rotateInPlace(BuildingId id, Rotation newRotation);
|
||||||
|
|
||||||
// Find nearest operational building of the given type; nullptr if none.
|
// Find nearest operational building of the given type; nullptr if none.
|
||||||
const Building* findNearestBuilding(QVector2D worldPos, BuildingType type) const;
|
const Building* findNearestBuilding(QVector2D worldPos, BuildingType type) const;
|
||||||
|
|
||||||
// Register / unregister tile occupancy for ECS station entities.
|
// Register / unregister tile occupancy for ECS station entities.
|
||||||
void registerTileOccupancy(const std::vector<QPoint>& cells, EntityId ownerPlaceholder);
|
void registerTileOccupancy(const std::vector<QPoint>& cells, BuildingId ownerPlaceholder);
|
||||||
void unregisterTileOccupancy(const std::vector<QPoint>& cells);
|
void unregisterTileOccupancy(const std::vector<QPoint>& cells);
|
||||||
|
|
||||||
// Place one "scrap" item into a SalvageBay's output buffer.
|
// Place one "scrap" item into a SalvageBay's output buffer.
|
||||||
// Returns false if bay not found, wrong type, or output buffer is full.
|
// Returns false if bay not found, wrong type, or output buffer is full.
|
||||||
bool deliverScrapToSalvageBay(EntityId bayId);
|
bool deliverScrapToSalvageBay(BuildingId bayId);
|
||||||
|
|
||||||
// Bypass the construction queue and create a fully-operational Building
|
// Bypass the construction queue and create a fully-operational Building
|
||||||
// immediately. Used for pre-placed structures (HQ, defence stations).
|
// immediately. Used for pre-placed structures (HQ, defence stations).
|
||||||
// surfaceMask comes from the relevant config struct.
|
// surfaceMask comes from the relevant config struct.
|
||||||
EntityId placeImmediate(BuildingType type,
|
BuildingId placeImmediate(BuildingType type,
|
||||||
const std::vector<std::string>& surfaceMask,
|
const std::vector<std::string>& surfaceMask,
|
||||||
QPoint anchor, Rotation rotation);
|
QPoint anchor, Rotation rotation);
|
||||||
|
|
||||||
// Remove an operational building by id without refund (used for deaths).
|
// Remove an operational building by id without refund (used for deaths).
|
||||||
// Returns true if found and removed.
|
// Returns true if found and removed.
|
||||||
bool removeBuilding(EntityId id);
|
bool removeBuilding(BuildingId id);
|
||||||
|
|
||||||
// Mutable iteration over all operational buildings.
|
// Mutable iteration over all operational buildings.
|
||||||
void forEachBuilding(std::function<void(Building&)> fn);
|
void forEachBuilding(std::function<void(Building&)> fn);
|
||||||
@@ -130,7 +130,7 @@ private:
|
|||||||
|
|
||||||
const GameConfig& m_config;
|
const GameConfig& m_config;
|
||||||
BeltSystem& m_belts;
|
BeltSystem& m_belts;
|
||||||
std::function<EntityId()> m_allocateId;
|
std::function<BuildingId()> m_allocateBuildingId;
|
||||||
std::function<void(int)> m_addBuildingBlocks;
|
std::function<void(int)> m_addBuildingBlocks;
|
||||||
std::function<void(const std::string&, QVector2D,
|
std::function<void(const std::string&, QVector2D,
|
||||||
const std::optional<ShipLayoutConfig>&)> m_spawnShip;
|
const std::optional<ShipLayoutConfig>&)> m_spawnShip;
|
||||||
@@ -140,5 +140,5 @@ private:
|
|||||||
std::deque<ConstructionSite> m_constructionQueue;
|
std::deque<ConstructionSite> m_constructionQueue;
|
||||||
|
|
||||||
// Maps every occupied body-cell coordinate to the entity that owns it.
|
// Maps every occupied body-cell coordinate to the entity that owns it.
|
||||||
std::map<std::pair<int, int>, EntityId> m_tileOccupancy;
|
std::map<std::pair<int, int>, BuildingId> m_tileOccupancy;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include <QVector2D>
|
#include <QVector2D>
|
||||||
|
|
||||||
#include "EntityId.h"
|
#include "BuildingId.h"
|
||||||
#include "MovementIntent.h"
|
#include "MovementIntent.h"
|
||||||
|
|
||||||
#include "entt/entity/entity.hpp"
|
#include "entt/entity/entity.hpp"
|
||||||
@@ -49,7 +49,7 @@ struct ThreatResponse
|
|||||||
struct ScrapCollector
|
struct ScrapCollector
|
||||||
{
|
{
|
||||||
std::optional<QVector2D> scrapTarget;
|
std::optional<QVector2D> scrapTarget;
|
||||||
EntityId deliveryBay; // kInvalidEntityId until assigned at a salvage bay
|
BuildingId deliveryBay; // kInvalidBuildingId until assigned at a salvage bay
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RepairBehavior
|
struct RepairBehavior
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ entt::entity ShipSystem::spawn(const std::string& schematicId, int level, QVecto
|
|||||||
|
|
||||||
ScrapCollector sc;
|
ScrapCollector sc;
|
||||||
sc.scrapTarget = std::nullopt;
|
sc.scrapTarget = std::nullopt;
|
||||||
sc.deliveryBay = kInvalidEntityId;
|
sc.deliveryBay = kInvalidBuildingId;
|
||||||
m_admin.addComponent<ScrapCollector>(entity, sc);
|
m_admin.addComponent<ScrapCollector>(entity, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ Simulation::Simulation(GameConfig config, unsigned int seed)
|
|||||||
, m_rng(seed)
|
, m_rng(seed)
|
||||||
, m_currentTick(0)
|
, m_currentTick(0)
|
||||||
, m_nextDepartureTick(secondsToTicks(m_config.world.departureIntervalSeconds))
|
, m_nextDepartureTick(secondsToTicks(m_config.world.departureIntervalSeconds))
|
||||||
, m_nextId(1)
|
, m_nextBuildingId(1)
|
||||||
, m_buildingBlocksStock(m_config.world.startingBuildingBlocks)
|
, m_buildingBlocksStock(m_config.world.startingBuildingBlocks)
|
||||||
, m_gameOver(false)
|
, m_gameOver(false)
|
||||||
, m_hqBuildingId(kInvalidEntityId)
|
, m_hqBuildingId(kInvalidBuildingId)
|
||||||
, m_hqProxyEntity(entt::null)
|
, m_hqProxyEntity(entt::null)
|
||||||
, m_playerStation1Entity(entt::null)
|
, m_playerStation1Entity(entt::null)
|
||||||
, m_playerStation2Entity(entt::null)
|
, m_playerStation2Entity(entt::null)
|
||||||
@@ -32,7 +32,7 @@ Simulation::Simulation(GameConfig config, unsigned int seed)
|
|||||||
m_buildingSystem = std::make_unique<BuildingSystem>(
|
m_buildingSystem = std::make_unique<BuildingSystem>(
|
||||||
m_config,
|
m_config,
|
||||||
m_beltSystem,
|
m_beltSystem,
|
||||||
[this]() { return allocateId(); },
|
[this]() { return allocateBuildingId(); },
|
||||||
[this](int amount) { m_buildingBlocksStock += amount; },
|
[this](int amount) { m_buildingBlocksStock += amount; },
|
||||||
[this](const std::string& id, QVector2D pos,
|
[this](const std::string& id, QVector2D pos,
|
||||||
const std::optional<ShipLayoutConfig>& layout) {
|
const std::optional<ShipLayoutConfig>& layout) {
|
||||||
@@ -82,10 +82,10 @@ void Simulation::reset(unsigned int seed)
|
|||||||
m_rng.seed(seed);
|
m_rng.seed(seed);
|
||||||
m_currentTick = 0;
|
m_currentTick = 0;
|
||||||
m_nextDepartureTick = secondsToTicks(m_config.world.departureIntervalSeconds);
|
m_nextDepartureTick = secondsToTicks(m_config.world.departureIntervalSeconds);
|
||||||
m_nextId = 1;
|
m_nextBuildingId = 1;
|
||||||
m_buildingBlocksStock = m_config.world.startingBuildingBlocks;
|
m_buildingBlocksStock = m_config.world.startingBuildingBlocks;
|
||||||
m_gameOver = false;
|
m_gameOver = false;
|
||||||
m_hqBuildingId = kInvalidEntityId;
|
m_hqBuildingId = kInvalidBuildingId;
|
||||||
m_hqProxyEntity = entt::null;
|
m_hqProxyEntity = entt::null;
|
||||||
m_playerStation1Entity = entt::null;
|
m_playerStation1Entity = entt::null;
|
||||||
m_playerStation2Entity = entt::null;
|
m_playerStation2Entity = entt::null;
|
||||||
@@ -99,7 +99,7 @@ void Simulation::reset(unsigned int seed)
|
|||||||
m_buildingSystem = std::make_unique<BuildingSystem>(
|
m_buildingSystem = std::make_unique<BuildingSystem>(
|
||||||
m_config,
|
m_config,
|
||||||
m_beltSystem,
|
m_beltSystem,
|
||||||
[this]() { return allocateId(); },
|
[this]() { return allocateBuildingId(); },
|
||||||
[this](int amount) { m_buildingBlocksStock += amount; },
|
[this](int amount) { m_buildingBlocksStock += amount; },
|
||||||
[this](const std::string& id, QVector2D pos,
|
[this](const std::string& id, QVector2D pos,
|
||||||
const std::optional<ShipLayoutConfig>& layout) {
|
const std::optional<ShipLayoutConfig>& layout) {
|
||||||
@@ -247,7 +247,7 @@ void Simulation::placeInitialStructures()
|
|||||||
m_playerStation1Entity = m_admin.spawnStation(
|
m_playerStation1Entity = m_admin.spawnStation(
|
||||||
anchor, psParsed.footprint, absCells, psHp, psHp, false);
|
anchor, psParsed.footprint, absCells, psHp, psHp, false);
|
||||||
m_admin.addComponent<Weapon>(m_playerStation1Entity, psWeapon);
|
m_admin.addComponent<Weapon>(m_playerStation1Entity, psWeapon);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const QPoint anchor(psAnchorX, ps2Y);
|
const QPoint anchor(psAnchorX, ps2Y);
|
||||||
@@ -259,7 +259,7 @@ void Simulation::placeInitialStructures()
|
|||||||
m_playerStation2Entity = m_admin.spawnStation(
|
m_playerStation2Entity = m_admin.spawnStation(
|
||||||
anchor, psParsed.footprint, absCells, psHp, psHp, false);
|
anchor, psParsed.footprint, absCells, psHp, psHp, false);
|
||||||
m_admin.addComponent<Weapon>(m_playerStation2Entity, psWeapon);
|
m_admin.addComponent<Weapon>(m_playerStation2Entity, psWeapon);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rally point: center of the player defence stations' X column, world vertical midpoint.
|
// Rally point: center of the player defence stations' X column, world vertical midpoint.
|
||||||
@@ -308,7 +308,7 @@ void Simulation::placeEnemyStationSet(int generation)
|
|||||||
m_currentEnemyStationEntities[0] = m_admin.spawnStation(
|
m_currentEnemyStationEntities[0] = m_admin.spawnStation(
|
||||||
anchor, esParsed.footprint, absCells, esHp, esHp, true);
|
anchor, esParsed.footprint, absCells, esHp, esHp, true);
|
||||||
m_admin.addComponent<Weapon>(m_currentEnemyStationEntities[0], esWeapon);
|
m_admin.addComponent<Weapon>(m_currentEnemyStationEntities[0], esWeapon);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const QPoint anchor(anchorX, y2);
|
const QPoint anchor(anchorX, y2);
|
||||||
@@ -320,7 +320,7 @@ void Simulation::placeEnemyStationSet(int generation)
|
|||||||
m_currentEnemyStationEntities[1] = m_admin.spawnStation(
|
m_currentEnemyStationEntities[1] = m_admin.spawnStation(
|
||||||
anchor, esParsed.footprint, absCells, esHp, esHp, true);
|
anchor, esParsed.footprint, absCells, esHp, esHp, true);
|
||||||
m_admin.addComponent<Weapon>(m_currentEnemyStationEntities[1], esWeapon);
|
m_admin.addComponent<Weapon>(m_currentEnemyStationEntities[1], esWeapon);
|
||||||
m_buildingSystem->registerTileOccupancy(absCells, allocateId());
|
m_buildingSystem->registerTileOccupancy(absCells, allocateBuildingId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,7 +512,7 @@ bool Simulation::isSchematicUnlocked(const std::string& shipId) const
|
|||||||
return it->second.unlocked;
|
return it->second.unlocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityId Simulation::tryPlaceBuilding(BuildingType type, QPoint anchor, Rotation rotation)
|
BuildingId Simulation::tryPlaceBuilding(BuildingType type, QPoint anchor, Rotation rotation)
|
||||||
{
|
{
|
||||||
int cost = 0;
|
int cost = 0;
|
||||||
for (const BuildingDef& def : m_config.buildings.buildings)
|
for (const BuildingDef& def : m_config.buildings.buildings)
|
||||||
@@ -525,13 +525,13 @@ EntityId Simulation::tryPlaceBuilding(BuildingType type, QPoint anchor, Rotation
|
|||||||
}
|
}
|
||||||
if (m_buildingBlocksStock < cost)
|
if (m_buildingBlocksStock < cost)
|
||||||
{
|
{
|
||||||
return kInvalidEntityId;
|
return kInvalidBuildingId;
|
||||||
}
|
}
|
||||||
m_buildingBlocksStock -= cost;
|
m_buildingBlocksStock -= cost;
|
||||||
return m_buildingSystem->place(type, anchor, rotation, m_currentTick);
|
return m_buildingSystem->place(type, anchor, rotation, m_currentTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Simulation::demolish(EntityId id)
|
void Simulation::demolish(BuildingId id)
|
||||||
{
|
{
|
||||||
m_buildingBlocksStock += m_buildingSystem->demolish(id);
|
m_buildingBlocksStock += m_buildingSystem->demolish(id);
|
||||||
}
|
}
|
||||||
@@ -586,7 +586,7 @@ const EntityAdmin& Simulation::admin() const
|
|||||||
return m_admin;
|
return m_admin;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityId Simulation::allocateId()
|
BuildingId Simulation::allocateBuildingId()
|
||||||
{
|
{
|
||||||
return m_nextId++;
|
return m_nextBuildingId++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
#include "entt/entity/entity.hpp"
|
#include "entt/entity/entity.hpp"
|
||||||
#include "SchematicDropEvent.h"
|
#include "SchematicDropEvent.h"
|
||||||
#include "BuildingType.h"
|
#include "BuildingType.h"
|
||||||
#include "EntityId.h"
|
#include "BuildingId.h"
|
||||||
#include "FireEvent.h"
|
#include "FireEvent.h"
|
||||||
#include "GameConfig.h"
|
#include "GameConfig.h"
|
||||||
#include "Rotation.h"
|
#include "Rotation.h"
|
||||||
@@ -62,11 +62,11 @@ public:
|
|||||||
bool isSchematicUnlocked(const std::string& shipId) const;
|
bool isSchematicUnlocked(const std::string& shipId) const;
|
||||||
|
|
||||||
// Checks affordability, deducts building blocks, and places the building.
|
// Checks affordability, deducts building blocks, and places the building.
|
||||||
// Returns the new entity id, or kInvalidEntityId if blocks are insufficient.
|
// Returns the new entity id, or kInvalidBuildingId if blocks are insufficient.
|
||||||
EntityId tryPlaceBuilding(BuildingType type, QPoint anchor, Rotation rotation);
|
BuildingId tryPlaceBuilding(BuildingType type, QPoint anchor, Rotation rotation);
|
||||||
|
|
||||||
// Demolishes the building with the given id and refunds building blocks.
|
// Demolishes the building with the given id and refunds building blocks.
|
||||||
void demolish(EntityId id);
|
void demolish(BuildingId id);
|
||||||
|
|
||||||
BuildingSystem& buildings();
|
BuildingSystem& buildings();
|
||||||
const BuildingSystem& buildings() const;
|
const BuildingSystem& buildings() const;
|
||||||
@@ -80,7 +80,7 @@ public:
|
|||||||
const EntityAdmin& admin() const;
|
const EntityAdmin& admin() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EntityId allocateId(); // Strictly increasing; never returns kInvalidEntityId.
|
BuildingId allocateBuildingId(); // Strictly increasing; never returns kInvalidBuildingId.
|
||||||
|
|
||||||
// Populate HQ, player defence stations, and the first enemy station set.
|
// Populate HQ, player defence stations, and the first enemy station set.
|
||||||
void placeInitialStructures();
|
void placeInitialStructures();
|
||||||
@@ -100,12 +100,12 @@ private:
|
|||||||
|
|
||||||
Tick m_currentTick;
|
Tick m_currentTick;
|
||||||
Tick m_nextDepartureTick;
|
Tick m_nextDepartureTick;
|
||||||
EntityId m_nextId;
|
BuildingId m_nextBuildingId;
|
||||||
int m_buildingBlocksStock;
|
int m_buildingBlocksStock;
|
||||||
bool m_gameOver = false;
|
bool m_gameOver = false;
|
||||||
|
|
||||||
// Pre-placed structure IDs.
|
// Pre-placed structure IDs.
|
||||||
EntityId m_hqBuildingId; // Building id (for belt integration)
|
BuildingId m_hqBuildingId; // Building id (for belt integration)
|
||||||
entt::entity m_hqProxyEntity; // ECS entity (HP, targeting)
|
entt::entity m_hqProxyEntity; // ECS entity (HP, targeting)
|
||||||
entt::entity m_playerStation1Entity;
|
entt::entity m_playerStation1Entity;
|
||||||
entt::entity m_playerStation2Entity;
|
entt::entity m_playerStation2Entity;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ struct Fixture
|
|||||||
{
|
{
|
||||||
GameConfig cfg;
|
GameConfig cfg;
|
||||||
BeltSystem belts;
|
BeltSystem belts;
|
||||||
EntityId nextId;
|
BuildingId nextBuildingId;
|
||||||
int stock;
|
int stock;
|
||||||
std::mt19937 rng;
|
std::mt19937 rng;
|
||||||
EntityAdmin admin;
|
EntityAdmin admin;
|
||||||
@@ -46,11 +46,11 @@ struct Fixture
|
|||||||
explicit Fixture()
|
explicit Fixture()
|
||||||
: cfg(loadConfig())
|
: cfg(loadConfig())
|
||||||
, belts(cfg.world.beltSpeedTilesPerSecond)
|
, belts(cfg.world.beltSpeedTilesPerSecond)
|
||||||
, nextId(1)
|
, nextBuildingId(1)
|
||||||
, stock(0)
|
, stock(0)
|
||||||
, rng(42)
|
, rng(42)
|
||||||
, buildings(cfg, belts,
|
, buildings(cfg, belts,
|
||||||
[this]() { return nextId++; },
|
[this]() { return nextBuildingId++; },
|
||||||
[this](int n) { stock += n; },
|
[this](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng)
|
rng)
|
||||||
@@ -365,7 +365,7 @@ TEST_CASE("BehaviorSystem: full-cargo salvage ship moves toward SalvageBay", "[b
|
|||||||
{
|
{
|
||||||
Fixture f;
|
Fixture f;
|
||||||
|
|
||||||
const EntityId bayId = f.buildings.place(BuildingType::SalvageBay,
|
const BuildingId bayId = f.buildings.place(BuildingType::SalvageBay,
|
||||||
QPoint(-4, 0), Rotation::East, 0);
|
QPoint(-4, 0), Rotation::East, 0);
|
||||||
Tick t = 0;
|
Tick t = 0;
|
||||||
for (int i = 0; i < 500; ++i)
|
for (int i = 0; i < 500; ++i)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#include "BuildingSystem.h"
|
#include "BuildingSystem.h"
|
||||||
#include "BuildingType.h"
|
#include "BuildingType.h"
|
||||||
#include "ConfigLoader.h"
|
#include "ConfigLoader.h"
|
||||||
#include "EntityId.h"
|
#include "BuildingId.h"
|
||||||
#include "Rotation.h"
|
#include "Rotation.h"
|
||||||
#include "Simulation.h"
|
#include "Simulation.h"
|
||||||
#include "SurfaceMask.h"
|
#include "SurfaceMask.h"
|
||||||
@@ -521,13 +521,13 @@ TEST_CASE("Blueprint placement: buildings land at anchor + offset from cursor",
|
|||||||
const QPoint offsetA(-1, 0);
|
const QPoint offsetA(-1, 0);
|
||||||
const QPoint offsetB( 1, 0);
|
const QPoint offsetB( 1, 0);
|
||||||
|
|
||||||
const EntityId idA = sim.tryPlaceBuilding(
|
const BuildingId idA = sim.tryPlaceBuilding(
|
||||||
BuildingType::Belt, cursor + offsetA, Rotation::East);
|
BuildingType::Belt, cursor + offsetA, Rotation::East);
|
||||||
const EntityId idB = sim.tryPlaceBuilding(
|
const BuildingId idB = sim.tryPlaceBuilding(
|
||||||
BuildingType::Belt, cursor + offsetB, Rotation::East);
|
BuildingType::Belt, cursor + offsetB, Rotation::East);
|
||||||
|
|
||||||
REQUIRE(idA != kInvalidEntityId);
|
REQUIRE(idA != kInvalidBuildingId);
|
||||||
REQUIRE(idB != kInvalidEntityId);
|
REQUIRE(idB != kInvalidBuildingId);
|
||||||
REQUIRE(sim.buildings().isTileOccupied(cursor + offsetA)); // (-6, 0)
|
REQUIRE(sim.buildings().isTileOccupied(cursor + offsetA)); // (-6, 0)
|
||||||
REQUIRE(sim.buildings().isTileOccupied(cursor + offsetB)); // (-4, 0)
|
REQUIRE(sim.buildings().isTileOccupied(cursor + offsetB)); // (-4, 0)
|
||||||
REQUIRE_FALSE(sim.buildings().isTileOccupied(cursor)); // center not occupied
|
REQUIRE_FALSE(sim.buildings().isTileOccupied(cursor)); // center not occupied
|
||||||
@@ -555,7 +555,7 @@ TEST_CASE("Blueprint placement: cost is deducted for each building in sequence",
|
|||||||
REQUIRE(sim.buildingBlocksStock() == startBlocks - 2 * beltCost);
|
REQUIRE(sim.buildingBlocksStock() == startBlocks - 2 * beltCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Blueprint placement: insufficient blocks returns kInvalidEntityId and deducts nothing",
|
TEST_CASE("Blueprint placement: insufficient blocks returns kInvalidBuildingId and deducts nothing",
|
||||||
"[blueprint]")
|
"[blueprint]")
|
||||||
{
|
{
|
||||||
Simulation sim(loadConfig());
|
Simulation sim(loadConfig());
|
||||||
@@ -578,11 +578,11 @@ TEST_CASE("Blueprint placement: insufficient blocks returns kInvalidEntityId and
|
|||||||
}
|
}
|
||||||
|
|
||||||
const int blocksBeforeAttempt = sim.buildingBlocksStock();
|
const int blocksBeforeAttempt = sim.buildingBlocksStock();
|
||||||
const EntityId id = sim.tryPlaceBuilding(
|
const BuildingId id = sim.tryPlaceBuilding(
|
||||||
BuildingType::Miner, QPoint(col - 2, 0), Rotation::East);
|
BuildingType::Miner, QPoint(col - 2, 0), Rotation::East);
|
||||||
|
|
||||||
// Placement must fail and leave the stock unchanged.
|
// Placement must fail and leave the stock unchanged.
|
||||||
REQUIRE(id == kInvalidEntityId);
|
REQUIRE(id == kInvalidBuildingId);
|
||||||
REQUIRE(sim.buildingBlocksStock() == blocksBeforeAttempt);
|
REQUIRE(sim.buildingBlocksStock() == blocksBeforeAttempt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,8 +618,8 @@ TEST_CASE("Blueprint placement: setRecipe on construction site stores recipe", "
|
|||||||
Simulation sim(loadConfig());
|
Simulation sim(loadConfig());
|
||||||
|
|
||||||
// Miner body cells: (0,0),(1,0),(0,1) — all at x < 0, valid for asteroid.
|
// Miner body cells: (0,0),(1,0),(0,1) — all at x < 0, valid for asteroid.
|
||||||
const EntityId id = sim.tryPlaceBuilding(BuildingType::Miner, QPoint(-2, 0), Rotation::East);
|
const BuildingId id = sim.tryPlaceBuilding(BuildingType::Miner, QPoint(-2, 0), Rotation::East);
|
||||||
REQUIRE(id != kInvalidEntityId);
|
REQUIRE(id != kInvalidBuildingId);
|
||||||
|
|
||||||
sim.buildings().setRecipe(id, "mine_iron_ore");
|
sim.buildings().setRecipe(id, "mine_iron_ore");
|
||||||
|
|
||||||
@@ -633,8 +633,8 @@ TEST_CASE("Blueprint placement: recipe transfers to building after construction
|
|||||||
{
|
{
|
||||||
Simulation sim(loadConfig());
|
Simulation sim(loadConfig());
|
||||||
|
|
||||||
const EntityId id = sim.tryPlaceBuilding(BuildingType::Miner, QPoint(-2, 0), Rotation::East);
|
const BuildingId id = sim.tryPlaceBuilding(BuildingType::Miner, QPoint(-2, 0), Rotation::East);
|
||||||
REQUIRE(id != kInvalidEntityId);
|
REQUIRE(id != kInvalidBuildingId);
|
||||||
sim.buildings().setRecipe(id, "mine_copper_ore");
|
sim.buildings().setRecipe(id, "mine_copper_ore");
|
||||||
|
|
||||||
// Miner construction_time_seconds = 10 → completesAt = secondsToTicks(10) = 300.
|
// Miner construction_time_seconds = 10 → completesAt = secondsToTicks(10) = 300.
|
||||||
|
|||||||
@@ -74,15 +74,15 @@ TEST_CASE("BuildingSystem: place miner occupies expected body tiles", "[building
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||||
REQUIRE(id != kInvalidEntityId);
|
REQUIRE(id != kInvalidBuildingId);
|
||||||
|
|
||||||
// Miner mask ["AA","A>"] with East rotation → body at (0,0),(1,0),(0,1).
|
// Miner mask ["AA","A>"] with East rotation → body at (0,0),(1,0),(0,1).
|
||||||
REQUIRE(bs.isTileOccupied(QPoint(0, 0)));
|
REQUIRE(bs.isTileOccupied(QPoint(0, 0)));
|
||||||
@@ -99,9 +99,9 @@ TEST_CASE("BuildingSystem: placing a belt registers it with BeltSystem after con
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
@@ -127,14 +127,14 @@ TEST_CASE("BuildingSystem: placed building enters construction queue", "[buildin
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||||
|
|
||||||
REQUIRE(bs.allSites().size() == 1);
|
REQUIRE(bs.allSites().size() == 1);
|
||||||
REQUIRE(bs.allBuildings().empty());
|
REQUIRE(bs.allBuildings().empty());
|
||||||
@@ -147,14 +147,14 @@ TEST_CASE("BuildingSystem: demolish frees tiles and returns refund", "[building]
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||||
|
|
||||||
// Miner construction_time_seconds = 10. completesAt = secondsToTicks(10) = 300.
|
// Miner construction_time_seconds = 10. completesAt = secondsToTicks(10) = 300.
|
||||||
// We need to process tick 300 itself, so run 301 ticks (ticks 0..300).
|
// We need to process tick 300 itself, so run 301 ticks (ticks 0..300).
|
||||||
@@ -180,9 +180,9 @@ TEST_CASE("BuildingSystem: first queued building starts construction immediately
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
@@ -197,9 +197,9 @@ TEST_CASE("BuildingSystem: second queued building waits (completesAt == 0)", "[b
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
@@ -218,14 +218,14 @@ TEST_CASE("BuildingSystem: construction completes after configured duration", "[
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||||
|
|
||||||
// Miner construction_time_seconds = 10. completesAt = secondsToTicks(10) = 300.
|
// Miner construction_time_seconds = 10. completesAt = secondsToTicks(10) = 300.
|
||||||
// We need to process tick 300 itself, so run 301 ticks (ticks 0..300).
|
// We need to process tick 300 itself, so run 301 ticks (ticks 0..300).
|
||||||
@@ -242,15 +242,15 @@ TEST_CASE("BuildingSystem: second building starts after first completes", "[buil
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||||
const EntityId id2 = bs.place(BuildingType::Miner, QPoint(5, 5), Rotation::East, 0);
|
const BuildingId id2 = bs.place(BuildingType::Miner, QPoint(5, 5), Rotation::East, 0);
|
||||||
|
|
||||||
// Process through tick 300 to complete first miner's construction.
|
// Process through tick 300 to complete first miner's construction.
|
||||||
Tick tick = 0;
|
Tick tick = 0;
|
||||||
@@ -271,14 +271,14 @@ TEST_CASE("BuildingSystem: miner produces iron_ore after recipe duration", "[bui
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||||
bs.setRecipe(id, "mine_iron_ore");
|
bs.setRecipe(id, "mine_iron_ore");
|
||||||
|
|
||||||
Tick tick = 0;
|
Tick tick = 0;
|
||||||
@@ -300,14 +300,14 @@ TEST_CASE("BuildingSystem: miner output buffer stalls when full", "[building]")
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||||
bs.setRecipe(id, "mine_iron_ore");
|
bs.setRecipe(id, "mine_iron_ore");
|
||||||
|
|
||||||
Tick tick = 0;
|
Tick tick = 0;
|
||||||
@@ -339,16 +339,16 @@ TEST_CASE("BuildingSystem: smelter input buffer fills from adjacent west-flowing
|
|||||||
BeltSystem belts(static_cast<double>(kTickRateHz));
|
BeltSystem belts(static_cast<double>(kTickRateHz));
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
// Smelter mask ["AA ","AA>"] → body (0,0),(1,0),(0,1),(1,1).
|
// Smelter mask ["AA ","AA>"] → body (0,0),(1,0),(0,1),(1,1).
|
||||||
// Output port (2,1) East. Input port example: (2,0) West.
|
// Output port (2,1) East. Input port example: (2,0) West.
|
||||||
const EntityId sid = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId sid = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0);
|
||||||
bs.setRecipe(sid, "iron_ingot");
|
bs.setRecipe(sid, "iron_ingot");
|
||||||
|
|
||||||
// Complete construction (15s → tick 450+1 = 451 ticks).
|
// Complete construction (15s → tick 450+1 = 451 ticks).
|
||||||
@@ -380,14 +380,14 @@ TEST_CASE("BuildingSystem: miner output buffer drains onto adjacent belt", "[bui
|
|||||||
BeltSystem belts(static_cast<double>(kTickRateHz));
|
BeltSystem belts(static_cast<double>(kTickRateHz));
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||||
bs.setRecipe(id, "mine_iron_ore");
|
bs.setRecipe(id, "mine_iron_ore");
|
||||||
|
|
||||||
// Belt at the miner's output port tile (1,1) flowing East.
|
// Belt at the miner's output port tile (1,1) flowing East.
|
||||||
@@ -419,14 +419,14 @@ TEST_CASE("BuildingSystem: setRecipe clears output buffer and active production"
|
|||||||
BeltSystem belts(static_cast<double>(kTickRateHz));
|
BeltSystem belts(static_cast<double>(kTickRateHz));
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
|
||||||
bs.setRecipe(id, "mine_iron_ore");
|
bs.setRecipe(id, "mine_iron_ore");
|
||||||
|
|
||||||
Tick tick = 0;
|
Tick tick = 0;
|
||||||
@@ -459,14 +459,14 @@ TEST_CASE("BuildingSystem: reprocessing plant output buffer capacity equals max
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::ReprocessingPlant,
|
const BuildingId id = bs.place(BuildingType::ReprocessingPlant,
|
||||||
QPoint(0, 0), Rotation::East, 0);
|
QPoint(0, 0), Rotation::East, 0);
|
||||||
bs.setRecipe(id, "reprocessing_cycle");
|
bs.setRecipe(id, "reprocessing_cycle");
|
||||||
|
|
||||||
@@ -489,14 +489,14 @@ TEST_CASE("BuildingSystem: reprocessing plant produces one cycle output then sta
|
|||||||
int stock = 0;
|
int stock = 0;
|
||||||
// Seed chosen so first roll produces 2-item output (iron_ingot), filling buffer.
|
// Seed chosen so first roll produces 2-item output (iron_ingot), filling buffer.
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::ReprocessingPlant,
|
const BuildingId id = bs.place(BuildingType::ReprocessingPlant,
|
||||||
QPoint(0, 0), Rotation::East, 0);
|
QPoint(0, 0), Rotation::East, 0);
|
||||||
bs.setRecipe(id, "reprocessing_cycle");
|
bs.setRecipe(id, "reprocessing_cycle");
|
||||||
|
|
||||||
@@ -547,9 +547,9 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget returns nullopt when tile is
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
@@ -565,16 +565,16 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget returns the site id for a que
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
||||||
|
|
||||||
const std::optional<EntityId> result =
|
const std::optional<BuildingId> result =
|
||||||
bs.findRotateInPlaceTarget(BuildingType::Belt, QPoint(0, 0), Rotation::North);
|
bs.findRotateInPlaceTarget(BuildingType::Belt, QPoint(0, 0), Rotation::North);
|
||||||
REQUIRE(result.has_value());
|
REQUIRE(result.has_value());
|
||||||
REQUIRE(*result == id);
|
REQUIRE(*result == id);
|
||||||
@@ -587,20 +587,20 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget returns the building id for a
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
||||||
|
|
||||||
Tick tick = 0;
|
Tick tick = 0;
|
||||||
runTicks(bs, belts, static_cast<int>(secondsToTicks(1.0)) + 1, tick);
|
runTicks(bs, belts, static_cast<int>(secondsToTicks(1.0)) + 1, tick);
|
||||||
REQUIRE(bs.allSites().empty());
|
REQUIRE(bs.allSites().empty());
|
||||||
|
|
||||||
const std::optional<EntityId> result =
|
const std::optional<BuildingId> result =
|
||||||
bs.findRotateInPlaceTarget(BuildingType::Belt, QPoint(0, 0), Rotation::South);
|
bs.findRotateInPlaceTarget(BuildingType::Belt, QPoint(0, 0), Rotation::South);
|
||||||
REQUIRE(result.has_value());
|
REQUIRE(result.has_value());
|
||||||
REQUIRE(*result == id);
|
REQUIRE(*result == id);
|
||||||
@@ -613,9 +613,9 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget returns nullopt when building
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
@@ -634,9 +634,9 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget returns nullopt when footprin
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
@@ -657,18 +657,18 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget works for a symmetric multi-t
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
// Smelter is a fully filled 2×2 footprint — rotating the ghost produces the
|
// Smelter is a fully filled 2×2 footprint — rotating the ghost produces the
|
||||||
// same four body tiles, so findRotateInPlaceTarget must still return the id.
|
// same four body tiles, so findRotateInPlaceTarget must still return the id.
|
||||||
const EntityId id = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Smelter, QPoint(0, 0), Rotation::East, 0);
|
||||||
|
|
||||||
const std::optional<EntityId> result =
|
const std::optional<BuildingId> result =
|
||||||
bs.findRotateInPlaceTarget(BuildingType::Smelter, QPoint(0, 0), Rotation::North);
|
bs.findRotateInPlaceTarget(BuildingType::Smelter, QPoint(0, 0), Rotation::North);
|
||||||
REQUIRE(result.has_value());
|
REQUIRE(result.has_value());
|
||||||
REQUIRE(*result == id);
|
REQUIRE(*result == id);
|
||||||
@@ -685,14 +685,14 @@ TEST_CASE("BuildingSystem: rotateInPlace updates the rotation field of a constru
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
||||||
REQUIRE(bs.findSite(id)->rotation == Rotation::East);
|
REQUIRE(bs.findSite(id)->rotation == Rotation::East);
|
||||||
|
|
||||||
bs.rotateInPlace(id, Rotation::North);
|
bs.rotateInPlace(id, Rotation::North);
|
||||||
@@ -707,14 +707,14 @@ TEST_CASE("BuildingSystem: rotateInPlace preserves the construction progress of
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
||||||
const Tick completesAt = bs.findSite(id)->completesAt;
|
const Tick completesAt = bs.findSite(id)->completesAt;
|
||||||
REQUIRE(completesAt > 0);
|
REQUIRE(completesAt > 0);
|
||||||
|
|
||||||
@@ -730,14 +730,14 @@ TEST_CASE("BuildingSystem: rotateInPlace updates rotation and output port direct
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
||||||
|
|
||||||
Tick tick = 0;
|
Tick tick = 0;
|
||||||
runTicks(bs, belts, static_cast<int>(secondsToTicks(1.0)) + 1, tick);
|
runTicks(bs, belts, static_cast<int>(secondsToTicks(1.0)) + 1, tick);
|
||||||
@@ -760,14 +760,14 @@ TEST_CASE("BuildingSystem: rotateInPlace re-registers a belt tile with BeltSyste
|
|||||||
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
BeltSystem belts(cfg.world.beltSpeedTilesPerSecond);
|
||||||
int stock = 0;
|
int stock = 0;
|
||||||
std::mt19937 rng(0);
|
std::mt19937 rng(0);
|
||||||
EntityId nextId = 1;
|
BuildingId nextBuildingId = 1;
|
||||||
BuildingSystem bs(cfg, belts,
|
BuildingSystem bs(cfg, belts,
|
||||||
[&nextId]() { return nextId++; },
|
[&nextBuildingId]() { return nextBuildingId++; },
|
||||||
[&stock](int n) { stock += n; },
|
[&stock](int n) { stock += n; },
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng);
|
rng);
|
||||||
|
|
||||||
const EntityId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
const BuildingId id = bs.place(BuildingType::Belt, QPoint(0, 0), Rotation::East, 0);
|
||||||
|
|
||||||
Tick tick = 0;
|
Tick tick = 0;
|
||||||
runTicks(bs, belts, static_cast<int>(secondsToTicks(1.0)) + 1, tick);
|
runTicks(bs, belts, static_cast<int>(secondsToTicks(1.0)) + 1, tick);
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ struct CombatFixture
|
|||||||
GameConfig cfg;
|
GameConfig cfg;
|
||||||
std::mt19937 rng;
|
std::mt19937 rng;
|
||||||
EntityAdmin admin;
|
EntityAdmin admin;
|
||||||
EntityId nextBldId;
|
BuildingId nextBuildingId;
|
||||||
BeltSystem belts;
|
BeltSystem belts;
|
||||||
ShipSystem ships;
|
ShipSystem ships;
|
||||||
BuildingSystem buildings;
|
BuildingSystem buildings;
|
||||||
@@ -49,11 +49,11 @@ struct CombatFixture
|
|||||||
explicit CombatFixture()
|
explicit CombatFixture()
|
||||||
: cfg(loadConfig())
|
: cfg(loadConfig())
|
||||||
, rng(42)
|
, rng(42)
|
||||||
, nextBldId(1)
|
, nextBuildingId(1)
|
||||||
, belts(cfg.world.beltSpeedTilesPerSecond)
|
, belts(cfg.world.beltSpeedTilesPerSecond)
|
||||||
, ships(cfg, admin)
|
, ships(cfg, admin)
|
||||||
, buildings(cfg, belts,
|
, buildings(cfg, belts,
|
||||||
[this]() { return nextBldId++; },
|
[this]() { return nextBuildingId++; },
|
||||||
[](int){},
|
[](int){},
|
||||||
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
[](const std::string&, QVector2D, const std::optional<ShipLayoutConfig>&) {},
|
||||||
rng)
|
rng)
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ static const BuildingDef* findShipyardDef(const GameConfig& cfg)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static EntityId placeShipyard(Simulation& sim, const BuildingDef& yardDef)
|
static BuildingId placeShipyard(Simulation& sim, const BuildingDef& yardDef)
|
||||||
{
|
{
|
||||||
return sim.buildings().placeImmediate(
|
return sim.buildings().placeImmediate(
|
||||||
BuildingType::Shipyard,
|
BuildingType::Shipyard,
|
||||||
@@ -54,7 +54,7 @@ static EntityId placeShipyard(Simulation& sim, const BuildingDef& yardDef)
|
|||||||
Rotation::East);
|
Rotation::East);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fillMaterials(Simulation& sim, EntityId yardId,
|
static void fillMaterials(Simulation& sim, BuildingId yardId,
|
||||||
const ShipDef& def,
|
const ShipDef& def,
|
||||||
const ShipLayoutConfig& layout)
|
const ShipLayoutConfig& layout)
|
||||||
{
|
{
|
||||||
@@ -199,7 +199,7 @@ TEST_CASE("Shipyard: setShipLayout reinitializes buffers with module materials",
|
|||||||
const BuildingDef* yardDef = findShipyardDef(sim.config());
|
const BuildingDef* yardDef = findShipyardDef(sim.config());
|
||||||
REQUIRE(yardDef != nullptr);
|
REQUIRE(yardDef != nullptr);
|
||||||
|
|
||||||
const EntityId yardId = placeShipyard(sim, *yardDef);
|
const BuildingId yardId = placeShipyard(sim, *yardDef);
|
||||||
sim.buildings().setRecipe(yardId, "interceptor");
|
sim.buildings().setRecipe(yardId, "interceptor");
|
||||||
|
|
||||||
ShipLayoutConfig layout;
|
ShipLayoutConfig layout;
|
||||||
@@ -228,7 +228,7 @@ TEST_CASE("Shipyard: setShipLayout cancels in-progress production",
|
|||||||
const BuildingDef* yardDef = findShipyardDef(sim.config());
|
const BuildingDef* yardDef = findShipyardDef(sim.config());
|
||||||
REQUIRE(yardDef != nullptr);
|
REQUIRE(yardDef != nullptr);
|
||||||
|
|
||||||
const EntityId yardId = placeShipyard(sim, *yardDef);
|
const BuildingId yardId = placeShipyard(sim, *yardDef);
|
||||||
sim.buildings().setRecipe(yardId, "interceptor");
|
sim.buildings().setRecipe(yardId, "interceptor");
|
||||||
|
|
||||||
// Fill materials and tick to start production.
|
// Fill materials and tick to start production.
|
||||||
@@ -261,7 +261,7 @@ TEST_CASE("Shipyard: setRecipe clears ship layout", "[modules][shipyard]")
|
|||||||
const BuildingDef* yardDef = findShipyardDef(sim.config());
|
const BuildingDef* yardDef = findShipyardDef(sim.config());
|
||||||
REQUIRE(yardDef != nullptr);
|
REQUIRE(yardDef != nullptr);
|
||||||
|
|
||||||
const EntityId yardId = placeShipyard(sim, *yardDef);
|
const BuildingId yardId = placeShipyard(sim, *yardDef);
|
||||||
sim.buildings().setRecipe(yardId, "interceptor");
|
sim.buildings().setRecipe(yardId, "interceptor");
|
||||||
|
|
||||||
ShipLayoutConfig layout;
|
ShipLayoutConfig layout;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include "ConfigLoader.h"
|
#include "ConfigLoader.h"
|
||||||
#include "EcsComponents.h"
|
#include "EcsComponents.h"
|
||||||
#include "EntityAdmin.h"
|
#include "EntityAdmin.h"
|
||||||
#include "EntityId.h"
|
#include "BuildingId.h"
|
||||||
#include "Ship.h"
|
#include "Ship.h"
|
||||||
#include "ShipSystem.h"
|
#include "ShipSystem.h"
|
||||||
#include "Tick.h"
|
#include "Tick.h"
|
||||||
@@ -116,7 +116,7 @@ TEST_CASE("ShipSystem: salvage_ship cargo capacity matches config", "[ship]")
|
|||||||
// cargo_capacity = 10
|
// cargo_capacity = 10
|
||||||
REQUIRE(admin.get<SalvageCargo>(e).capacity == 10);
|
REQUIRE(admin.get<SalvageCargo>(e).capacity == 10);
|
||||||
REQUIRE(admin.get<SalvageCargo>(e).current == 0);
|
REQUIRE(admin.get<SalvageCargo>(e).current == 0);
|
||||||
REQUIRE(admin.get<ScrapCollector>(e).deliveryBay == kInvalidEntityId);
|
REQUIRE(admin.get<ScrapCollector>(e).deliveryBay == kInvalidBuildingId);
|
||||||
REQUIRE_FALSE(admin.get<ScrapCollector>(e).scrapTarget.has_value());
|
REQUIRE_FALSE(admin.get<ScrapCollector>(e).scrapTarget.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ static const BuildingDef* findShipyardDef(const GameConfig& cfg)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static EntityId placeShipyard(Simulation& sim, const BuildingDef& yardDef)
|
static BuildingId placeShipyard(Simulation& sim, const BuildingDef& yardDef)
|
||||||
{
|
{
|
||||||
return sim.buildings().placeImmediate(
|
return sim.buildings().placeImmediate(
|
||||||
BuildingType::Shipyard,
|
BuildingType::Shipyard,
|
||||||
@@ -60,7 +60,7 @@ static int countShips(Simulation& sim)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fillMaterials(Simulation& sim, EntityId yardId, const ShipDef& def)
|
static void fillMaterials(Simulation& sim, BuildingId yardId, const ShipDef& def)
|
||||||
{
|
{
|
||||||
sim.buildings().forEachBuilding([&](Building& b)
|
sim.buildings().forEachBuilding([&](Building& b)
|
||||||
{
|
{
|
||||||
@@ -91,8 +91,8 @@ TEST_CASE("Shipyard: spawns a player ship after production cycle completes",
|
|||||||
|
|
||||||
const int shipsBefore = countShips(sim);
|
const int shipsBefore = countShips(sim);
|
||||||
|
|
||||||
const EntityId yardId = placeShipyard(sim, *yardDef);
|
const BuildingId yardId = placeShipyard(sim, *yardDef);
|
||||||
REQUIRE(yardId != kInvalidEntityId);
|
REQUIRE(yardId != kInvalidBuildingId);
|
||||||
|
|
||||||
sim.buildings().setRecipe(yardId, def->id);
|
sim.buildings().setRecipe(yardId, def->id);
|
||||||
fillMaterials(sim, yardId, *def);
|
fillMaterials(sim, yardId, *def);
|
||||||
@@ -152,7 +152,7 @@ TEST_CASE("Shipyard: does not spawn with insufficient materials", "[shipyard]")
|
|||||||
|
|
||||||
const int shipsBefore = countShips(sim);
|
const int shipsBefore = countShips(sim);
|
||||||
|
|
||||||
const EntityId yardId = placeShipyard(sim, *yardDef);
|
const BuildingId yardId = placeShipyard(sim, *yardDef);
|
||||||
sim.buildings().setRecipe(yardId, def->id);
|
sim.buildings().setRecipe(yardId, def->id);
|
||||||
// Materials remain at zero (default after setRecipe); no cycle starts.
|
// Materials remain at zero (default after setRecipe); no cycle starts.
|
||||||
|
|
||||||
@@ -174,7 +174,7 @@ TEST_CASE("Shipyard: spawns a second ship after materials replenished", "[shipya
|
|||||||
const BuildingDef* yardDef = findShipyardDef(sim.config());
|
const BuildingDef* yardDef = findShipyardDef(sim.config());
|
||||||
REQUIRE(yardDef != nullptr);
|
REQUIRE(yardDef != nullptr);
|
||||||
|
|
||||||
const EntityId yardId = placeShipyard(sim, *yardDef);
|
const BuildingId yardId = placeShipyard(sim, *yardDef);
|
||||||
sim.buildings().setRecipe(yardId, def->id);
|
sim.buildings().setRecipe(yardId, def->id);
|
||||||
|
|
||||||
const Tick cycleTicks = secondsToTicks(def->schematic.productionTimeSeconds);
|
const Tick cycleTicks = secondsToTicks(def->schematic.productionTimeSeconds);
|
||||||
|
|||||||
@@ -62,9 +62,9 @@ BlueprintPanel::BlueprintPanel(Simulation* sim, const GameConfig* config, QWidge
|
|||||||
connect(m_loadBtn, &QPushButton::clicked, this, &BlueprintPanel::onLoadClicked);
|
connect(m_loadBtn, &QPushButton::clicked, this, &BlueprintPanel::onLoadClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlueprintPanel::onSelectionChanged(const std::vector<EntityId>& ids)
|
void BlueprintPanel::onSelectionChanged(const std::vector<BuildingId>& ids)
|
||||||
{
|
{
|
||||||
m_selectedIds = ids;
|
m_selectedBuildingIds = ids;
|
||||||
refreshButtonStates();
|
refreshButtonStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ void BlueprintPanel::clearActiveBlueprintButton()
|
|||||||
|
|
||||||
void BlueprintPanel::onCreateClicked()
|
void BlueprintPanel::onCreateClicked()
|
||||||
{
|
{
|
||||||
if (m_selectedIds.empty()) { return; }
|
if (m_selectedBuildingIds.empty()) { return; }
|
||||||
|
|
||||||
Blueprint bp = createBlueprintFromSelection();
|
Blueprint bp = createBlueprintFromSelection();
|
||||||
if (bp.buildings.empty()) { return; }
|
if (bp.buildings.empty()) { return; }
|
||||||
@@ -144,9 +144,9 @@ Blueprint BlueprintPanel::createBlueprintFromSelection() const
|
|||||||
const Building* building;
|
const Building* building;
|
||||||
};
|
};
|
||||||
std::vector<Entry> entries;
|
std::vector<Entry> entries;
|
||||||
entries.reserve(m_selectedIds.size());
|
entries.reserve(m_selectedBuildingIds.size());
|
||||||
|
|
||||||
for (const EntityId id : m_selectedIds)
|
for (const BuildingId id : m_selectedBuildingIds)
|
||||||
{
|
{
|
||||||
const Building* b = m_sim->buildings().findBuilding(id);
|
const Building* b = m_sim->buildings().findBuilding(id);
|
||||||
if (!b) { continue; }
|
if (!b) { continue; }
|
||||||
@@ -320,7 +320,7 @@ void BlueprintPanel::onLoadClicked()
|
|||||||
void BlueprintPanel::refreshButtonStates()
|
void BlueprintPanel::refreshButtonStates()
|
||||||
{
|
{
|
||||||
const bool anyPlaceable = [&]() {
|
const bool anyPlaceable = [&]() {
|
||||||
for (const EntityId id : m_selectedIds)
|
for (const BuildingId id : m_selectedBuildingIds)
|
||||||
{
|
{
|
||||||
const Building* b = m_sim->buildings().findBuilding(id);
|
const Building* b = m_sim->buildings().findBuilding(id);
|
||||||
if (!b) { continue; }
|
if (!b) { continue; }
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "Blueprint.h"
|
#include "Blueprint.h"
|
||||||
#include "EntityId.h"
|
#include "BuildingId.h"
|
||||||
#include "GameConfig.h"
|
#include "GameConfig.h"
|
||||||
#include "Tick.h"
|
#include "Tick.h"
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ public:
|
|||||||
BlueprintPanel(Simulation* sim, const GameConfig* config, QWidget* parent = nullptr);
|
BlueprintPanel(Simulation* sim, const GameConfig* config, QWidget* parent = nullptr);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onSelectionChanged(const std::vector<EntityId>& ids);
|
void onSelectionChanged(const std::vector<BuildingId>& ids);
|
||||||
void onStateUpdated(Tick tick, int blocks, double speed);
|
void onStateUpdated(Tick tick, int blocks, double speed);
|
||||||
void clearActiveBlueprintButton();
|
void clearActiveBlueprintButton();
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ private:
|
|||||||
|
|
||||||
Simulation* m_sim;
|
Simulation* m_sim;
|
||||||
const GameConfig* m_config;
|
const GameConfig* m_config;
|
||||||
std::vector<EntityId> m_selectedIds;
|
std::vector<BuildingId> m_selectedBuildingIds;
|
||||||
int m_currentBlocks;
|
int m_currentBlocks;
|
||||||
int m_activeIndex;
|
int m_activeIndex;
|
||||||
std::vector<Blueprint> m_blueprints;
|
std::vector<Blueprint> m_blueprints;
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ GameWorldView::GameWorldView(Simulation* sim, const GameConfig* config,
|
|||||||
, m_ghostValid(false)
|
, m_ghostValid(false)
|
||||||
, m_dragging(false)
|
, m_dragging(false)
|
||||||
, m_demolishMode(false)
|
, m_demolishMode(false)
|
||||||
, m_demolishHoverId(kInvalidEntityId)
|
, m_demolishHoverBuildingId(kInvalidBuildingId)
|
||||||
, m_debugDraw(false)
|
, m_debugDraw(false)
|
||||||
, m_rng(std::random_device{}())
|
, m_rng(std::random_device{}())
|
||||||
, m_boxSelecting(false)
|
, m_boxSelecting(false)
|
||||||
@@ -412,7 +412,7 @@ bool GameWorldView::isValidPlacement(BuildingType type, QPoint anchor,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityId GameWorldView::buildingAtTile(QPoint tile) const
|
BuildingId GameWorldView::buildingAtTile(QPoint tile) const
|
||||||
{
|
{
|
||||||
for (const Building& b : m_sim->buildings().allBuildings())
|
for (const Building& b : m_sim->buildings().allBuildings())
|
||||||
{
|
{
|
||||||
@@ -424,10 +424,10 @@ EntityId GameWorldView::buildingAtTile(QPoint tile) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return kInvalidEntityId;
|
return kInvalidBuildingId;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityId GameWorldView::siteAtTile(QPoint tile) const
|
BuildingId GameWorldView::siteAtTile(QPoint tile) const
|
||||||
{
|
{
|
||||||
for (const ConstructionSite& s : m_sim->buildings().allSites())
|
for (const ConstructionSite& s : m_sim->buildings().allSites())
|
||||||
{
|
{
|
||||||
@@ -439,7 +439,7 @@ EntityId GameWorldView::siteAtTile(QPoint tile) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return kInvalidEntityId;
|
return kInvalidBuildingId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -495,7 +495,7 @@ void GameWorldView::placeBlueprintAtTile(QPoint center)
|
|||||||
for (const BlueprintBuilding& bb : bp.buildings)
|
for (const BlueprintBuilding& bb : bp.buildings)
|
||||||
{
|
{
|
||||||
const QPoint anchor = center + bb.offset;
|
const QPoint anchor = center + bb.offset;
|
||||||
const std::optional<EntityId> rotateTarget =
|
const std::optional<BuildingId> rotateTarget =
|
||||||
m_sim->buildings().findRotateInPlaceTarget(bb.type, anchor, bb.rotation);
|
m_sim->buildings().findRotateInPlaceTarget(bb.type, anchor, bb.rotation);
|
||||||
if (rotateTarget.has_value())
|
if (rotateTarget.has_value())
|
||||||
{
|
{
|
||||||
@@ -503,8 +503,8 @@ void GameWorldView::placeBlueprintAtTile(QPoint center)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EntityId id = m_sim->tryPlaceBuilding(bb.type, anchor, bb.rotation);
|
const BuildingId id = m_sim->tryPlaceBuilding(bb.type, anchor, bb.rotation);
|
||||||
if (id == kInvalidEntityId || bb.recipeId.empty()) { continue; }
|
if (id == kInvalidBuildingId || bb.recipeId.empty()) { continue; }
|
||||||
|
|
||||||
if (bb.type == BuildingType::Shipyard)
|
if (bb.type == BuildingType::Shipyard)
|
||||||
{
|
{
|
||||||
@@ -533,7 +533,7 @@ void GameWorldView::placeAtTile(QPoint tile)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::optional<EntityId> rotateTarget =
|
const std::optional<BuildingId> rotateTarget =
|
||||||
m_sim->buildings().findRotateInPlaceTarget(type, tile, m_ghostRotation);
|
m_sim->buildings().findRotateInPlaceTarget(type, tile, m_ghostRotation);
|
||||||
if (rotateTarget.has_value())
|
if (rotateTarget.has_value())
|
||||||
{
|
{
|
||||||
@@ -549,9 +549,9 @@ void GameWorldView::placeAtTile(QPoint tile)
|
|||||||
}
|
}
|
||||||
if (!m_sim->buildings().isTileOccupied(tile))
|
if (!m_sim->buildings().isTileOccupied(tile))
|
||||||
{
|
{
|
||||||
const EntityId id = m_sim->tryPlaceBuilding(
|
const BuildingId id = m_sim->tryPlaceBuilding(
|
||||||
type, tile, m_ghostRotation);
|
type, tile, m_ghostRotation);
|
||||||
if (id != kInvalidEntityId)
|
if (id != kInvalidBuildingId)
|
||||||
{
|
{
|
||||||
m_beltDragTiles.insert(tile);
|
m_beltDragTiles.insert(tile);
|
||||||
}
|
}
|
||||||
@@ -563,8 +563,8 @@ void GameWorldView::placeAtTile(QPoint tile)
|
|||||||
{
|
{
|
||||||
if (!m_sim->buildings().isTileOccupied(tile))
|
if (!m_sim->buildings().isTileOccupied(tile))
|
||||||
{
|
{
|
||||||
const EntityId id = m_sim->tryPlaceBuilding(type, tile, m_ghostRotation);
|
const BuildingId id = m_sim->tryPlaceBuilding(type, tile, m_ghostRotation);
|
||||||
if (id != kInvalidEntityId)
|
if (id != kInvalidBuildingId)
|
||||||
{
|
{
|
||||||
if (type == BuildingType::TunnelEntry)
|
if (type == BuildingType::TunnelEntry)
|
||||||
{
|
{
|
||||||
@@ -677,7 +677,7 @@ void GameWorldView::drawBuildings(QPainter& painter)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool selected = false;
|
bool selected = false;
|
||||||
for (EntityId selId : m_selectedIds)
|
for (BuildingId selId : m_selectedBuildingIds)
|
||||||
{
|
{
|
||||||
if (selId == b.id) { selected = true; break; }
|
if (selId == b.id) { selected = true; break; }
|
||||||
}
|
}
|
||||||
@@ -957,9 +957,9 @@ void GameWorldView::drawOverlays(QPainter& painter)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Demolish hover tint
|
// Demolish hover tint
|
||||||
if (m_demolishMode && m_demolishHoverId != kInvalidEntityId)
|
if (m_demolishMode && m_demolishHoverBuildingId != kInvalidBuildingId)
|
||||||
{
|
{
|
||||||
const Building* b = m_sim->buildings().findBuilding(m_demolishHoverId);
|
const Building* b = m_sim->buildings().findBuilding(m_demolishHoverBuildingId);
|
||||||
if (b)
|
if (b)
|
||||||
{
|
{
|
||||||
for (const QPoint& cell : b->bodyCells)
|
for (const QPoint& cell : b->bodyCells)
|
||||||
@@ -1168,55 +1168,55 @@ void GameWorldView::mousePressEvent(QMouseEvent* event)
|
|||||||
}
|
}
|
||||||
else if (m_demolishMode)
|
else if (m_demolishMode)
|
||||||
{
|
{
|
||||||
EntityId hovered = buildingAtTile(tile);
|
BuildingId hovered = buildingAtTile(tile);
|
||||||
if (hovered == kInvalidEntityId)
|
if (hovered == kInvalidBuildingId)
|
||||||
{
|
{
|
||||||
hovered = siteAtTile(tile);
|
hovered = siteAtTile(tile);
|
||||||
}
|
}
|
||||||
if (hovered != kInvalidEntityId)
|
if (hovered != kInvalidBuildingId)
|
||||||
{
|
{
|
||||||
const Building* b = m_sim->buildings().findBuilding(hovered);
|
const Building* b = m_sim->buildings().findBuilding(hovered);
|
||||||
const bool isProtected = b && b->type == BuildingType::Hq;
|
const bool isProtected = b && b->type == BuildingType::Hq;
|
||||||
if (!isProtected)
|
if (!isProtected)
|
||||||
{
|
{
|
||||||
m_sim->demolish(hovered);
|
m_sim->demolish(hovered);
|
||||||
m_demolishHoverId = kInvalidEntityId;
|
m_demolishHoverBuildingId = kInvalidBuildingId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
EntityId id = buildingAtTile(tile);
|
BuildingId id = buildingAtTile(tile);
|
||||||
if (id == kInvalidEntityId)
|
if (id == kInvalidBuildingId)
|
||||||
{
|
{
|
||||||
id = siteAtTile(tile);
|
id = siteAtTile(tile);
|
||||||
}
|
}
|
||||||
if (id != kInvalidEntityId)
|
if (id != kInvalidBuildingId)
|
||||||
{
|
{
|
||||||
if (event->modifiers() & Qt::ControlModifier)
|
if (event->modifiers() & Qt::ControlModifier)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
std::vector<EntityId> newSel;
|
std::vector<BuildingId> newSel;
|
||||||
for (EntityId sel : m_selectedIds)
|
for (BuildingId sel : m_selectedBuildingIds)
|
||||||
{
|
{
|
||||||
if (sel == id) { found = true; }
|
if (sel == id) { found = true; }
|
||||||
else { newSel.push_back(sel); }
|
else { newSel.push_back(sel); }
|
||||||
}
|
}
|
||||||
if (!found) { newSel.push_back(id); }
|
if (!found) { newSel.push_back(id); }
|
||||||
m_selectedIds = newSel;
|
m_selectedBuildingIds = newSel;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_selectedIds = { id };
|
m_selectedBuildingIds = { id };
|
||||||
}
|
}
|
||||||
emit selectionChanged(m_selectedIds);
|
emit selectionChanged(m_selectedBuildingIds);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!(event->modifiers() & Qt::ControlModifier))
|
if (!(event->modifiers() & Qt::ControlModifier))
|
||||||
{
|
{
|
||||||
m_selectedIds.clear();
|
m_selectedBuildingIds.clear();
|
||||||
emit selectionChanged(m_selectedIds);
|
emit selectionChanged(m_selectedBuildingIds);
|
||||||
}
|
}
|
||||||
m_boxSelecting = true;
|
m_boxSelecting = true;
|
||||||
m_boxStartTile = tile;
|
m_boxStartTile = tile;
|
||||||
@@ -1245,7 +1245,7 @@ void GameWorldView::mouseMoveEvent(QMouseEvent* event)
|
|||||||
}
|
}
|
||||||
else if (m_demolishMode)
|
else if (m_demolishMode)
|
||||||
{
|
{
|
||||||
m_demolishHoverId = buildingAtTile(tile);
|
m_demolishHoverBuildingId = buildingAtTile(tile);
|
||||||
}
|
}
|
||||||
else if (m_boxSelecting)
|
else if (m_boxSelecting)
|
||||||
{
|
{
|
||||||
@@ -1272,7 +1272,7 @@ void GameWorldView::mouseReleaseEvent(QMouseEvent* event)
|
|||||||
const int x1 = std::max(m_boxStartTile.x(), m_boxCurrentTile.x());
|
const int x1 = std::max(m_boxStartTile.x(), m_boxCurrentTile.x());
|
||||||
const int y1 = std::max(m_boxStartTile.y(), m_boxCurrentTile.y());
|
const int y1 = std::max(m_boxStartTile.y(), m_boxCurrentTile.y());
|
||||||
|
|
||||||
std::vector<EntityId> boxSel;
|
std::vector<BuildingId> boxSel;
|
||||||
for (const Building& b : m_sim->buildings().allBuildings())
|
for (const Building& b : m_sim->buildings().allBuildings())
|
||||||
{
|
{
|
||||||
for (const QPoint& cell : b.bodyCells)
|
for (const QPoint& cell : b.bodyCells)
|
||||||
@@ -1300,21 +1300,21 @@ void GameWorldView::mouseReleaseEvent(QMouseEvent* event)
|
|||||||
|
|
||||||
if (!(event->modifiers() & Qt::ControlModifier))
|
if (!(event->modifiers() & Qt::ControlModifier))
|
||||||
{
|
{
|
||||||
m_selectedIds = boxSel;
|
m_selectedBuildingIds = boxSel;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (EntityId id : boxSel)
|
for (BuildingId id : boxSel)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (EntityId sel : m_selectedIds)
|
for (BuildingId sel : m_selectedBuildingIds)
|
||||||
{
|
{
|
||||||
if (sel == id) { found = true; break; }
|
if (sel == id) { found = true; break; }
|
||||||
}
|
}
|
||||||
if (!found) { m_selectedIds.push_back(id); }
|
if (!found) { m_selectedBuildingIds.push_back(id); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit selectionChanged(m_selectedIds);
|
emit selectionChanged(m_selectedBuildingIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1327,7 +1327,7 @@ void GameWorldView::toggleDemolishMode()
|
|||||||
if (m_demolishMode)
|
if (m_demolishMode)
|
||||||
{
|
{
|
||||||
m_demolishMode = false;
|
m_demolishMode = false;
|
||||||
m_demolishHoverId = kInvalidEntityId;
|
m_demolishHoverBuildingId = kInvalidBuildingId;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1393,9 +1393,9 @@ void GameWorldView::resetForNewGame()
|
|||||||
m_ghostRotation = Rotation::East;
|
m_ghostRotation = Rotation::East;
|
||||||
m_ghostValid = false;
|
m_ghostValid = false;
|
||||||
m_demolishMode = false;
|
m_demolishMode = false;
|
||||||
m_demolishHoverId = kInvalidEntityId;
|
m_demolishHoverBuildingId = kInvalidBuildingId;
|
||||||
emit demolishModeChanged(false);
|
emit demolishModeChanged(false);
|
||||||
m_selectedIds.clear();
|
m_selectedBuildingIds.clear();
|
||||||
m_boxSelecting = false;
|
m_boxSelecting = false;
|
||||||
m_scrollXTiles = 0.0f;
|
m_scrollXTiles = 0.0f;
|
||||||
m_scrollLeft = false;
|
m_scrollLeft = false;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#include "Blueprint.h"
|
#include "Blueprint.h"
|
||||||
#include "SchematicDropEvent.h"
|
#include "SchematicDropEvent.h"
|
||||||
#include "BuildingType.h"
|
#include "BuildingType.h"
|
||||||
#include "EntityId.h"
|
#include "BuildingId.h"
|
||||||
#include "FireEvent.h"
|
#include "FireEvent.h"
|
||||||
|
|
||||||
#include "entt/entity/entity.hpp"
|
#include "entt/entity/entity.hpp"
|
||||||
@@ -46,7 +46,7 @@ public:
|
|||||||
const VisualsConfig* visuals, QWidget* parent = nullptr);
|
const VisualsConfig* visuals, QWidget* parent = nullptr);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void selectionChanged(const std::vector<EntityId>& ids);
|
void selectionChanged(const std::vector<BuildingId>& ids);
|
||||||
void stateUpdated(Tick tick, int blocks, double speed);
|
void stateUpdated(Tick tick, int blocks, double speed);
|
||||||
void gameOver();
|
void gameOver();
|
||||||
void builderModeExited();
|
void builderModeExited();
|
||||||
@@ -104,8 +104,8 @@ private:
|
|||||||
|
|
||||||
bool isValidPlacement(BuildingType type, QPoint anchor, Rotation rot) const;
|
bool isValidPlacement(BuildingType type, QPoint anchor, Rotation rot) const;
|
||||||
const BuildingDef* findBuildingDef(BuildingType type) const;
|
const BuildingDef* findBuildingDef(BuildingType type) const;
|
||||||
EntityId buildingAtTile(QPoint tile) const;
|
BuildingId buildingAtTile(QPoint tile) const;
|
||||||
EntityId siteAtTile(QPoint tile) const;
|
BuildingId siteAtTile(QPoint tile) const;
|
||||||
|
|
||||||
void drawPortGlyph(QPainter& painter, QPoint bodyTile,
|
void drawPortGlyph(QPainter& painter, QPoint bodyTile,
|
||||||
Rotation direction, const QColor& color);
|
Rotation direction, const QColor& color);
|
||||||
@@ -162,10 +162,10 @@ private:
|
|||||||
QPoint m_blueprintGhostTile;
|
QPoint m_blueprintGhostTile;
|
||||||
|
|
||||||
bool m_demolishMode;
|
bool m_demolishMode;
|
||||||
EntityId m_demolishHoverId;
|
BuildingId m_demolishHoverBuildingId;
|
||||||
bool m_debugDraw;
|
bool m_debugDraw;
|
||||||
|
|
||||||
std::vector<EntityId> m_selectedIds;
|
std::vector<BuildingId> m_selectedBuildingIds;
|
||||||
bool m_boxSelecting;
|
bool m_boxSelecting;
|
||||||
QPoint m_boxStartTile;
|
QPoint m_boxStartTile;
|
||||||
QPoint m_boxCurrentTile;
|
QPoint m_boxCurrentTile;
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ void MainWindow::onEscapeMenuRequested()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onLayoutDialogRequested(EntityId shipyardId)
|
void MainWindow::onLayoutDialogRequested(BuildingId shipyardId)
|
||||||
{
|
{
|
||||||
const double prevSpeed = m_gameWorldView->gameSpeed();
|
const double prevSpeed = m_gameWorldView->gameSpeed();
|
||||||
m_gameWorldView->setGameSpeed(0.0);
|
m_gameWorldView->setGameSpeed(0.0);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "EntityId.h"
|
#include "BuildingId.h"
|
||||||
#include "ShipLayoutBlueprint.h"
|
#include "ShipLayoutBlueprint.h"
|
||||||
#include "Tick.h"
|
#include "Tick.h"
|
||||||
#include "VisualsConfig.h"
|
#include "VisualsConfig.h"
|
||||||
@@ -34,7 +34,7 @@ private slots:
|
|||||||
void onGameOver();
|
void onGameOver();
|
||||||
void onStateUpdated(Tick tick, int blocks, double speed);
|
void onStateUpdated(Tick tick, int blocks, double speed);
|
||||||
void onEscapeMenuRequested();
|
void onEscapeMenuRequested();
|
||||||
void onLayoutDialogRequested(EntityId shipyardId);
|
void onLayoutDialogRequested(BuildingId shipyardId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void layoutPanels();
|
void layoutPanels();
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ SelectedBuildingPanel::SelectedBuildingPanel(Simulation* sim,
|
|||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, m_sim(sim)
|
, m_sim(sim)
|
||||||
, m_config(config)
|
, m_config(config)
|
||||||
, m_singleId(kInvalidEntityId)
|
, m_singleBuildingId(kInvalidBuildingId)
|
||||||
, m_splitterTile(0, 0)
|
, m_splitterTile(0, 0)
|
||||||
{
|
{
|
||||||
m_layout = new QVBoxLayout(this);
|
m_layout = new QVBoxLayout(this);
|
||||||
@@ -125,9 +125,9 @@ SelectedBuildingPanel::SelectedBuildingPanel(Simulation* sim,
|
|||||||
connect(m_clearBeltBtn, &QPushButton::clicked,
|
connect(m_clearBeltBtn, &QPushButton::clicked,
|
||||||
this, &SelectedBuildingPanel::onClearBelt);
|
this, &SelectedBuildingPanel::onClearBelt);
|
||||||
connect(m_configureLayoutBtn, &QPushButton::clicked, this, [this]() {
|
connect(m_configureLayoutBtn, &QPushButton::clicked, this, [this]() {
|
||||||
if (m_singleId != kInvalidEntityId)
|
if (m_singleBuildingId != kInvalidBuildingId)
|
||||||
{
|
{
|
||||||
emit layoutDialogRequested(m_singleId);
|
emit layoutDialogRequested(m_singleBuildingId);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(m_filterAList, &QListWidget::itemChanged,
|
connect(m_filterAList, &QListWidget::itemChanged,
|
||||||
@@ -138,31 +138,31 @@ SelectedBuildingPanel::SelectedBuildingPanel(Simulation* sim,
|
|||||||
buildEmpty();
|
buildEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectedBuildingPanel::onSelectionChanged(const std::vector<EntityId>& ids)
|
void SelectedBuildingPanel::onSelectionChanged(const std::vector<BuildingId>& ids)
|
||||||
{
|
{
|
||||||
m_selection = ids;
|
m_selectedBuildingIds = ids;
|
||||||
rebuild();
|
rebuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectedBuildingPanel::rebuild()
|
void SelectedBuildingPanel::rebuild()
|
||||||
{
|
{
|
||||||
if (m_selection.empty())
|
if (m_selectedBuildingIds.empty())
|
||||||
{
|
{
|
||||||
buildEmpty();
|
buildEmpty();
|
||||||
}
|
}
|
||||||
else if (m_selection.size() == 1)
|
else if (m_selectedBuildingIds.size() == 1)
|
||||||
{
|
{
|
||||||
buildSingle(m_selection[0]);
|
buildSingle(m_selectedBuildingIds[0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buildMulti(m_selection);
|
buildMulti(m_selectedBuildingIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectedBuildingPanel::buildEmpty()
|
void SelectedBuildingPanel::buildEmpty()
|
||||||
{
|
{
|
||||||
m_singleId = kInvalidEntityId;
|
m_singleBuildingId = kInvalidBuildingId;
|
||||||
m_titleLabel->hide();
|
m_titleLabel->hide();
|
||||||
m_recipeCombo->hide();
|
m_recipeCombo->hide();
|
||||||
m_layoutPreview->hide();
|
m_layoutPreview->hide();
|
||||||
@@ -175,9 +175,9 @@ void SelectedBuildingPanel::buildEmpty()
|
|||||||
m_buffersLabel->hide();
|
m_buffersLabel->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectedBuildingPanel::buildSingle(EntityId id)
|
void SelectedBuildingPanel::buildSingle(BuildingId id)
|
||||||
{
|
{
|
||||||
m_singleId = id;
|
m_singleBuildingId = id;
|
||||||
|
|
||||||
const Building* b = m_sim->buildings().findBuilding(id);
|
const Building* b = m_sim->buildings().findBuilding(id);
|
||||||
if (!b)
|
if (!b)
|
||||||
@@ -490,8 +490,8 @@ const ShipDef* SelectedBuildingPanel::findShipDef(const std::string& id) const
|
|||||||
|
|
||||||
void SelectedBuildingPanel::onStateUpdated(Tick /*tick*/, int /*blocks*/, double /*speed*/)
|
void SelectedBuildingPanel::onStateUpdated(Tick /*tick*/, int /*blocks*/, double /*speed*/)
|
||||||
{
|
{
|
||||||
if (m_singleId == kInvalidEntityId) { return; }
|
if (m_singleBuildingId == kInvalidBuildingId) { return; }
|
||||||
const Building* b = m_sim->buildings().findBuilding(m_singleId);
|
const Building* b = m_sim->buildings().findBuilding(m_singleBuildingId);
|
||||||
if (b)
|
if (b)
|
||||||
{
|
{
|
||||||
// If the panel was last showing this id as a construction site, the
|
// If the panel was last showing this id as a construction site, the
|
||||||
@@ -506,7 +506,7 @@ void SelectedBuildingPanel::onStateUpdated(Tick /*tick*/, int /*blocks*/, double
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const ConstructionSite* s = m_sim->buildings().findSite(m_singleId);
|
const ConstructionSite* s = m_sim->buildings().findSite(m_singleBuildingId);
|
||||||
if (s)
|
if (s)
|
||||||
{
|
{
|
||||||
rebuild();
|
rebuild();
|
||||||
@@ -515,9 +515,9 @@ void SelectedBuildingPanel::onStateUpdated(Tick /*tick*/, int /*blocks*/, double
|
|||||||
buildEmpty();
|
buildEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectedBuildingPanel::buildMulti(const std::vector<EntityId>& ids)
|
void SelectedBuildingPanel::buildMulti(const std::vector<BuildingId>& ids)
|
||||||
{
|
{
|
||||||
m_singleId = kInvalidEntityId;
|
m_singleBuildingId = kInvalidBuildingId;
|
||||||
m_recipeCombo->hide();
|
m_recipeCombo->hide();
|
||||||
m_clearBeltBtn->hide();
|
m_clearBeltBtn->hide();
|
||||||
m_filterALabel->hide();
|
m_filterALabel->hide();
|
||||||
@@ -527,7 +527,7 @@ void SelectedBuildingPanel::buildMulti(const std::vector<EntityId>& ids)
|
|||||||
m_buffersLabel->hide();
|
m_buffersLabel->hide();
|
||||||
|
|
||||||
std::map<BuildingType, int> counts;
|
std::map<BuildingType, int> counts;
|
||||||
for (EntityId id : ids)
|
for (BuildingId id : ids)
|
||||||
{
|
{
|
||||||
const Building* b = m_sim->buildings().findBuilding(id);
|
const Building* b = m_sim->buildings().findBuilding(id);
|
||||||
if (b)
|
if (b)
|
||||||
@@ -564,12 +564,12 @@ void SelectedBuildingPanel::buildMulti(const std::vector<EntityId>& ids)
|
|||||||
|
|
||||||
void SelectedBuildingPanel::onRecipeChanged(int comboIndex)
|
void SelectedBuildingPanel::onRecipeChanged(int comboIndex)
|
||||||
{
|
{
|
||||||
if (m_singleId == kInvalidEntityId)
|
if (m_singleBuildingId == kInvalidBuildingId)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const QString recipeId = m_recipeCombo->itemData(comboIndex).toString();
|
const QString recipeId = m_recipeCombo->itemData(comboIndex).toString();
|
||||||
m_sim->buildings().setRecipe(m_singleId, recipeId.toStdString());
|
m_sim->buildings().setRecipe(m_singleBuildingId, recipeId.toStdString());
|
||||||
rebuild();
|
rebuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,7 +619,7 @@ void SelectedBuildingPanel::buildSplitterFilters(QPoint splitterTile)
|
|||||||
|
|
||||||
void SelectedBuildingPanel::onSplitterFilterChanged()
|
void SelectedBuildingPanel::onSplitterFilterChanged()
|
||||||
{
|
{
|
||||||
if (m_singleId == kInvalidEntityId)
|
if (m_singleBuildingId == kInvalidBuildingId)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -664,7 +664,7 @@ std::vector<std::string> SelectedBuildingPanel::allItemIds() const
|
|||||||
void SelectedBuildingPanel::onClearBelt()
|
void SelectedBuildingPanel::onClearBelt()
|
||||||
{
|
{
|
||||||
std::vector<QPoint> tiles;
|
std::vector<QPoint> tiles;
|
||||||
for (EntityId id : m_selection)
|
for (BuildingId id : m_selectedBuildingIds)
|
||||||
{
|
{
|
||||||
const Building* b = m_sim->buildings().findBuilding(id);
|
const Building* b = m_sim->buildings().findBuilding(id);
|
||||||
if (b && isBeltLike(b->type))
|
if (b && isBeltLike(b->type))
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
#include "Building.h"
|
#include "Building.h"
|
||||||
#include "EntityId.h"
|
#include "BuildingId.h"
|
||||||
#include "GameConfig.h"
|
#include "GameConfig.h"
|
||||||
#include "RecipesConfig.h"
|
#include "RecipesConfig.h"
|
||||||
#include "ShipLayout.h"
|
#include "ShipLayout.h"
|
||||||
@@ -31,10 +31,10 @@ public:
|
|||||||
QWidget* parent = nullptr);
|
QWidget* parent = nullptr);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void layoutDialogRequested(EntityId shipyardId);
|
void layoutDialogRequested(BuildingId shipyardId);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onSelectionChanged(const std::vector<EntityId>& ids);
|
void onSelectionChanged(const std::vector<BuildingId>& ids);
|
||||||
void onStateUpdated(Tick tick, int blocks, double speed);
|
void onStateUpdated(Tick tick, int blocks, double speed);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
@@ -46,8 +46,8 @@ private:
|
|||||||
void rebuild();
|
void rebuild();
|
||||||
void clearContent();
|
void clearContent();
|
||||||
void buildEmpty();
|
void buildEmpty();
|
||||||
void buildSingle(EntityId id);
|
void buildSingle(BuildingId id);
|
||||||
void buildMulti(const std::vector<EntityId>& ids);
|
void buildMulti(const std::vector<BuildingId>& ids);
|
||||||
void refreshBuffers(const Building* b);
|
void refreshBuffers(const Building* b);
|
||||||
void buildSplitterFilters(QPoint splitterTile);
|
void buildSplitterFilters(QPoint splitterTile);
|
||||||
const RecipeDef* findRecipe(const Building* b) const;
|
const RecipeDef* findRecipe(const Building* b) const;
|
||||||
@@ -56,7 +56,7 @@ private:
|
|||||||
|
|
||||||
Simulation* m_sim;
|
Simulation* m_sim;
|
||||||
const GameConfig* m_config;
|
const GameConfig* m_config;
|
||||||
std::vector<EntityId> m_selection;
|
std::vector<BuildingId> m_selectedBuildingIds;
|
||||||
|
|
||||||
QVBoxLayout* m_layout;
|
QVBoxLayout* m_layout;
|
||||||
QLabel* m_titleLabel;
|
QLabel* m_titleLabel;
|
||||||
@@ -71,7 +71,7 @@ private:
|
|||||||
ShipLayoutPreview* m_layoutPreview;
|
ShipLayoutPreview* m_layoutPreview;
|
||||||
QPushButton* m_configureLayoutBtn;
|
QPushButton* m_configureLayoutBtn;
|
||||||
|
|
||||||
EntityId m_singleId;
|
BuildingId m_singleBuildingId;
|
||||||
QPoint m_splitterTile;
|
QPoint m_splitterTile;
|
||||||
std::string m_currentRecipeId;
|
std::string m_currentRecipeId;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user