Prefix all getters with "get"

This commit is contained in:
2026-07-19 21:17:38 +02:00
parent 08752aeced
commit d412c69f82
51 changed files with 574 additions and 574 deletions

View File

@@ -95,7 +95,7 @@ ArenaSimulation::ArenaSimulation(const GameConfig& gameConfig,
updateStatus(); updateStatus();
} }
std::string ArenaStatus::TeamStatus::ehpPercentText() const std::string ArenaStatus::TeamStatus::getEhpPercentText() const
{ {
if (maxEhp <= 0.0) if (maxEhp <= 0.0)
{ {
@@ -312,7 +312,7 @@ void ArenaSimulation::requestStop()
m_stopRequested.store(true, std::memory_order_relaxed); m_stopRequested.store(true, std::memory_order_relaxed);
} }
ArenaStatus ArenaSimulation::status() const ArenaStatus ArenaSimulation::getStatus() const
{ {
std::lock_guard<std::mutex> lock(m_statusMutex); std::lock_guard<std::mutex> lock(m_statusMutex);
return m_status; return m_status;
@@ -473,42 +473,42 @@ bool ArenaSimulation::isFinished() const
return m_finished; return m_finished;
} }
int ArenaSimulation::winnerTeam() const int ArenaSimulation::getWinnerTeam() const
{ {
return m_winnerTeam; return m_winnerTeam;
} }
Tick ArenaSimulation::currentTick() const Tick ArenaSimulation::getCurrentTick() const
{ {
return m_currentTick; return m_currentTick;
} }
const ArenaConfig& ArenaSimulation::arenaConfig() const const ArenaConfig& ArenaSimulation::getArenaConfig() const
{ {
return m_arenaConfig; return m_arenaConfig;
} }
const BuildingSystem& ArenaSimulation::buildings() const const BuildingSystem& ArenaSimulation::getBuildings() const
{ {
return *m_buildingSystem; return *m_buildingSystem;
} }
const ShipSystem& ArenaSimulation::ships() const const ShipSystem& ArenaSimulation::getShips() const
{ {
return *m_shipSystem; return *m_shipSystem;
} }
const ScrapSystem& ArenaSimulation::scraps() const const ScrapSystem& ArenaSimulation::getScraps() const
{ {
return *m_scrapSystem; return *m_scrapSystem;
} }
EntityAdmin& ArenaSimulation::admin() EntityAdmin& ArenaSimulation::getAdmin()
{ {
return m_admin; return m_admin;
} }
const EntityAdmin& ArenaSimulation::admin() const const EntityAdmin& ArenaSimulation::getAdmin() const
{ {
return m_admin; return m_admin;
} }

View File

@@ -46,14 +46,14 @@ struct ArenaStatus
double threatLevel = 0.0; // accumulated threat of the team's configured ships double threatLevel = 0.0; // accumulated threat of the team's configured ships
// Remaining durability of the team's ships and defence stations (HQ // Remaining durability of the team's ships and defence stations (HQ
// excluded). currentEhp is summed live; maxEhp is the fixed full-HP // excluded). currentEhp is summed live; maxEhp is the fixed full-HP
// baseline. See ehpPercentText() for the displayed value. // baseline. See getEhpPercentText() for the displayed value.
double currentEhp = 0.0; double currentEhp = 0.0;
double maxEhp = 0.0; double maxEhp = 0.0;
std::vector<Entry> entries; // HQ first, then ships, then stations std::vector<Entry> entries; // HQ first, then ships, then stations
// Remaining EHP as a whole-number percentage ("NN%"), or "n/a" when the // Remaining EHP as a whole-number percentage ("NN%"), or "n/a" when the
// team has no ships or stations (maxEhp == 0). // team has no ships or stations (maxEhp == 0).
std::string ehpPercentText() const; std::string getEhpPercentText() const;
}; };
TeamStatus teams[2]; TeamStatus teams[2];
@@ -78,17 +78,17 @@ public:
void tickOnce(); void tickOnce();
std::vector<BeamFiredEvent> drainBeamFiredEvents(); std::vector<BeamFiredEvent> drainBeamFiredEvents();
ArenaStatus status() const; ArenaStatus getStatus() const;
bool isFinished() const; bool isFinished() const;
int winnerTeam() const; int getWinnerTeam() const;
Tick currentTick() const; Tick getCurrentTick() const;
const ArenaConfig& arenaConfig() const; const ArenaConfig& getArenaConfig() const;
const BuildingSystem& buildings() const; const BuildingSystem& getBuildings() const;
const ShipSystem& ships() const; const ShipSystem& getShips() const;
const ScrapSystem& scraps() const; const ScrapSystem& getScraps() const;
EntityAdmin& admin(); EntityAdmin& getAdmin();
const EntityAdmin& admin() const; const EntityAdmin& getAdmin() const;
private: private:
BuildingId allocateBuildingId(); BuildingId allocateBuildingId();

View File

@@ -73,7 +73,7 @@ void ArenaView::setGameSpeed(double multiplier)
std::make_shared<GameSpeedChangedEvent>(multiplier)); std::make_shared<GameSpeedChangedEvent>(multiplier));
} }
double ArenaView::gameSpeed() const double ArenaView::getGameSpeed() const
{ {
return m_gameSpeedMultiplier; return m_gameSpeedMultiplier;
} }
@@ -121,7 +121,7 @@ void ArenaView::onFrame()
// Expire old beams. Lifetime is measured in game ticks so beams stay // Expire old beams. Lifetime is measured in game ticks so beams stay
// visible while the simulation is paused or slowed (REQ-SHP-FIRING-BEAM). // visible while the simulation is paused or slowed (REQ-SHP-FIRING-BEAM).
{ {
const Tick now = m_sim->currentTick(); const Tick now = m_sim->getCurrentTick();
std::vector<ActiveBeam> live; std::vector<ActiveBeam> live;
for (const ActiveBeam& b : m_activeBeams) for (const ActiveBeam& b : m_activeBeams)
{ {
@@ -144,16 +144,16 @@ void ArenaView::onFrame()
void ArenaView::handleEvent(std::shared_ptr<const BeamFiredEvent> event) void ArenaView::handleEvent(std::shared_ptr<const BeamFiredEvent> event)
{ {
float maxRadius = 0.125f; float maxRadius = 0.125f;
if (m_sim->admin().isValid(event->target) if (m_sim->getAdmin().isValid(event->target)
&& m_sim->admin().hasAll<StationBodyComponent>(event->target)) && m_sim->getAdmin().hasAll<StationBodyComponent>(event->target))
{ {
const StationBodyComponent& sb = m_sim->admin().get<StationBodyComponent>(event->target); const StationBodyComponent& sb = m_sim->getAdmin().get<StationBodyComponent>(event->target);
const int shorter = std::min(sb.footprint.width(), const int shorter = std::min(sb.footprint.width(),
sb.footprint.height()); sb.footprint.height());
maxRadius = shorter / 2.0f; maxRadius = shorter / 2.0f;
} }
else if (m_sim->admin().isValid(event->target) else if (m_sim->getAdmin().isValid(event->target)
&& m_sim->admin().hasAll<ScrapDataComponent>(event->target)) && m_sim->getAdmin().hasAll<ScrapDataComponent>(event->target))
{ {
maxRadius = 0.1f; maxRadius = 0.1f;
} }
@@ -192,9 +192,9 @@ void ArenaView::paintGL()
// Coordinate helpers // Coordinate helpers
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
float ArenaView::tilePx() const float ArenaView::getTilePx() const
{ {
const ArenaConfig& ac = m_sim->arenaConfig(); const ArenaConfig& ac = m_sim->getArenaConfig();
const int totalWidth = ac.playerBufferWidth_tiles const int totalWidth = ac.playerBufferWidth_tiles
+ ac.contestZoneWidth_tiles + ac.contestZoneWidth_tiles
+ ac.enemyBufferWidth_tiles; + ac.enemyBufferWidth_tiles;
@@ -209,8 +209,8 @@ float ArenaView::tilePx() const
QPointF ArenaView::worldToWidget(QVector2D worldPos) const QPointF ArenaView::worldToWidget(QVector2D worldPos) const
{ {
return QPointF( return QPointF(
static_cast<qreal>(worldPos.x() * tilePx()), static_cast<qreal>(worldPos.x() * getTilePx()),
static_cast<qreal>(worldPos.y() * tilePx())); static_cast<qreal>(worldPos.y() * getTilePx()));
} }
QPointF ArenaView::tileToWidget(QPoint tile) const QPointF ArenaView::tileToWidget(QPoint tile) const
@@ -223,21 +223,21 @@ QRectF ArenaView::tileRect(QPoint tile) const
{ {
const QPointF tl = tileToWidget(tile); const QPointF tl = tileToWidget(tile);
return QRectF(tl.x(), tl.y(), return QRectF(tl.x(), tl.y(),
static_cast<qreal>(tilePx()), static_cast<qreal>(tilePx())); static_cast<qreal>(getTilePx()), static_cast<qreal>(getTilePx()));
} }
std::optional<QVector2D> ArenaView::entityPosition(entt::entity entity) const std::optional<QVector2D> ArenaView::entityPosition(entt::entity entity) const
{ {
if (!m_sim->admin().isValid(entity) || !m_sim->admin().hasAll<PositionComponent>(entity)) if (!m_sim->getAdmin().isValid(entity) || !m_sim->getAdmin().hasAll<PositionComponent>(entity))
{ {
return std::nullopt; return std::nullopt;
} }
return m_sim->admin().get<PositionComponent>(entity).value; return m_sim->getAdmin().get<PositionComponent>(entity).value;
} }
QVector2D ArenaView::widgetToWorld(QPoint widgetPt) const QVector2D ArenaView::widgetToWorld(QPoint widgetPt) const
{ {
const float px = tilePx(); const float px = getTilePx();
if (px < 0.001f) { return QVector2D(0.0f, 0.0f); } if (px < 0.001f) { return QVector2D(0.0f, 0.0f); }
return QVector2D(static_cast<float>(widgetPt.x()) / px, return QVector2D(static_cast<float>(widgetPt.x()) / px,
static_cast<float>(widgetPt.y()) / px); static_cast<float>(widgetPt.y()) / px);
@@ -248,7 +248,7 @@ void ArenaView::mousePressEvent(QMouseEvent* event)
if (event->button() == Qt::LeftButton) if (event->button() == Qt::LeftButton)
{ {
const QVector2D worldPos = widgetToWorld(event->pos()); const QVector2D worldPos = widgetToWorld(event->pos());
entt::entity hit = entityAtWorldPos(m_sim->admin(), worldPos); entt::entity hit = entityAtWorldPos(m_sim->getAdmin(), worldPos);
if (hit != entt::null) if (hit != entt::null)
{ {
@@ -282,7 +282,7 @@ void ArenaView::keyPressEvent(QKeyEvent* event)
void ArenaView::drawTiles(QPainter& painter) void ArenaView::drawTiles(QPainter& painter)
{ {
const ArenaConfig& ac = m_sim->arenaConfig(); const ArenaConfig& ac = m_sim->getArenaConfig();
const int totalWidth = ac.playerBufferWidth_tiles const int totalWidth = ac.playerBufferWidth_tiles
+ ac.contestZoneWidth_tiles + ac.contestZoneWidth_tiles
+ ac.enemyBufferWidth_tiles; + ac.enemyBufferWidth_tiles;
@@ -300,7 +300,7 @@ void ArenaView::drawTiles(QPainter& painter)
void ArenaView::drawBuildings(QPainter& painter) void ArenaView::drawBuildings(QPainter& painter)
{ {
for (const Building& b : m_sim->buildings().allBuildings()) for (const Building& b : m_sim->getBuildings().getAllBuildings())
{ {
const std::map<BuildingType, BuildingVisuals>::const_iterator it = const std::map<BuildingType, BuildingVisuals>::const_iterator it =
m_visuals->buildings.find(b.type); m_visuals->buildings.find(b.type);
@@ -315,8 +315,8 @@ void ArenaView::drawBuildings(QPainter& painter)
const QPointF tl = tileToWidget(b.anchor); const QPointF tl = tileToWidget(b.anchor);
const QRectF bboxRect(tl.x(), tl.y(), const QRectF bboxRect(tl.x(), tl.y(),
b.footprint.width() * static_cast<qreal>(tilePx()), b.footprint.width() * static_cast<qreal>(getTilePx()),
b.footprint.height() * static_cast<qreal>(tilePx())); b.footprint.height() * static_cast<qreal>(getTilePx()));
painter.setPen(QPen(bv.outline, 1)); painter.setPen(QPen(bv.outline, 1));
painter.setBrush(Qt::NoBrush); painter.setBrush(Qt::NoBrush);
@@ -332,8 +332,8 @@ void ArenaView::drawBuildings(QPainter& painter)
void ArenaView::drawScrap(QPainter& painter) void ArenaView::drawScrap(QPainter& painter)
{ {
const float r = tilePx() * 0.2f; const float r = getTilePx() * 0.2f;
for (const ScrapInfo& scrap : m_sim->scraps().allScrapInfo()) for (const ScrapInfo& scrap : m_sim->getScraps().getAllScrapInfo())
{ {
const QPointF center = worldToWidget(scrap.position); const QPointF center = worldToWidget(scrap.position);
painter.setBrush(QColor(128, 110, 90)); painter.setBrush(QColor(128, 110, 90));
@@ -345,7 +345,7 @@ void ArenaView::drawScrap(QPainter& painter)
void ArenaView::drawStations(QPainter& painter) void ArenaView::drawStations(QPainter& painter)
{ {
m_sim->admin().forEach<StationBodyComponent, FactionComponent, HealthComponent>( m_sim->getAdmin().forEach<StationBodyComponent, FactionComponent, HealthComponent>(
[&](entt::entity e, const StationBodyComponent& sb, const FactionComponent& f, const HealthComponent& h) [&](entt::entity e, const StationBodyComponent& sb, const FactionComponent& f, const HealthComponent& h)
{ {
const BuildingType visType = f.isEnemy const BuildingType visType = f.isEnemy
@@ -364,8 +364,8 @@ void ArenaView::drawStations(QPainter& painter)
const QPointF tl = tileToWidget(sb.anchor); const QPointF tl = tileToWidget(sb.anchor);
const QRectF bboxRect(tl.x(), tl.y(), const QRectF bboxRect(tl.x(), tl.y(),
sb.footprint.width() * static_cast<qreal>(tilePx()), sb.footprint.width() * static_cast<qreal>(getTilePx()),
sb.footprint.height() * static_cast<qreal>(tilePx())); sb.footprint.height() * static_cast<qreal>(getTilePx()));
painter.setPen(QPen(bv.outline, 1)); painter.setPen(QPen(bv.outline, 1));
painter.setBrush(Qt::NoBrush); painter.setBrush(Qt::NoBrush);
@@ -374,7 +374,7 @@ void ArenaView::drawStations(QPainter& painter)
if (h.maxHp > 0.0f) if (h.maxHp > 0.0f)
{ {
const float fraction = std::max(0.0f, h.hp / h.maxHp); const float fraction = std::max(0.0f, h.hp / h.maxHp);
const qreal barH = static_cast<qreal>(tilePx()) * 0.12; const qreal barH = static_cast<qreal>(getTilePx()) * 0.12;
const qreal barY = bboxRect.bottom() + 1.0; const qreal barY = bboxRect.bottom() + 1.0;
const qreal barW = bboxRect.width(); const qreal barW = bboxRect.width();
painter.fillRect(QRectF(bboxRect.left(), barY, barW, barH), painter.fillRect(QRectF(bboxRect.left(), barY, barW, barH),
@@ -394,7 +394,7 @@ void ArenaView::drawStations(QPainter& painter)
void ArenaView::drawShips(QPainter& painter) void ArenaView::drawShips(QPainter& painter)
{ {
m_sim->admin().forEach<ShipIdentityComponent, PositionComponent, FacingComponent, m_sim->getAdmin().forEach<ShipIdentityComponent, PositionComponent, FacingComponent,
FactionComponent, HealthComponent>( FactionComponent, HealthComponent>(
[&](entt::entity e, const ShipIdentityComponent& si, [&](entt::entity e, const ShipIdentityComponent& si,
const PositionComponent& pos, const FacingComponent& facing, const PositionComponent& pos, const FacingComponent& facing,
@@ -408,8 +408,8 @@ void ArenaView::drawShips(QPainter& painter)
const QVector2D dir(std::cos(facing.radians), std::sin(facing.radians)); const QVector2D dir(std::cos(facing.radians), std::sin(facing.radians));
const QVector2D perp(-dir.y(), dir.x()); const QVector2D perp(-dir.y(), dir.x());
const float fwd = tilePx() * 0.45f; const float fwd = getTilePx() * 0.45f;
const float side = tilePx() * 0.25f; const float side = getTilePx() * 0.25f;
QPolygonF tri; QPolygonF tri;
tri << QPointF(center.x() + static_cast<qreal>(dir.x() * fwd), tri << QPointF(center.x() + static_cast<qreal>(dir.x() * fwd),
@@ -427,7 +427,7 @@ void ArenaView::drawShips(QPainter& painter)
{ {
const float fraction = std::max(0.0f, h.hp / h.maxHp); const float fraction = std::max(0.0f, h.hp / h.maxHp);
const qreal barW = static_cast<qreal>(fwd) * 2.0; const qreal barW = static_cast<qreal>(fwd) * 2.0;
const qreal barH = static_cast<qreal>(tilePx()) * 0.12; const qreal barH = static_cast<qreal>(getTilePx()) * 0.12;
const qreal barX = center.x() - static_cast<qreal>(fwd); const qreal barX = center.x() - static_cast<qreal>(fwd);
const qreal barY = center.y() + static_cast<qreal>(fwd) + 1.0; const qreal barY = center.y() + static_cast<qreal>(fwd) + 1.0;
painter.fillRect(QRectF(barX, barY, barW, barH), QColor(60, 60, 60)); painter.fillRect(QRectF(barX, barY, barW, barH), QColor(60, 60, 60));
@@ -437,7 +437,7 @@ void ArenaView::drawShips(QPainter& painter)
if (m_selectedEntity.has_value() && *m_selectedEntity == e) if (m_selectedEntity.has_value() && *m_selectedEntity == e)
{ {
const qreal radius = static_cast<qreal>(tilePx()) * 0.55; const qreal radius = static_cast<qreal>(getTilePx()) * 0.55;
painter.setPen(QPen(QColor(255, 255, 0), 2)); painter.setPen(QPen(QColor(255, 255, 0), 2));
painter.setBrush(Qt::NoBrush); painter.setBrush(Qt::NoBrush);
painter.drawEllipse(center, radius, radius); painter.drawEllipse(center, radius, radius);
@@ -448,7 +448,7 @@ void ArenaView::drawShips(QPainter& painter)
void ArenaView::drawDebugSensorRanges(QPainter& painter) void ArenaView::drawDebugSensorRanges(QPainter& painter)
{ {
painter.setBrush(Qt::NoBrush); painter.setBrush(Qt::NoBrush);
m_sim->admin().forEach<ShipIdentityComponent, PositionComponent, SensorRangeComponent>( m_sim->getAdmin().forEach<ShipIdentityComponent, PositionComponent, SensorRangeComponent>(
[&](entt::entity /*e*/, const ShipIdentityComponent& si, [&](entt::entity /*e*/, const ShipIdentityComponent& si,
const PositionComponent& pos, const SensorRangeComponent& sensor) const PositionComponent& pos, const SensorRangeComponent& sensor)
{ {
@@ -458,7 +458,7 @@ void ArenaView::drawDebugSensorRanges(QPainter& painter)
const QPointF center = worldToWidget(pos.value); const QPointF center = worldToWidget(pos.value);
const qreal radiusPx = static_cast<qreal>(sensor.value_tiles) const qreal radiusPx = static_cast<qreal>(sensor.value_tiles)
* static_cast<qreal>(tilePx()); * static_cast<qreal>(getTilePx());
QColor circleColor = it->second.outline; QColor circleColor = it->second.outline;
circleColor.setAlpha(77); circleColor.setAlpha(77);
painter.setPen(QPen(circleColor, 1)); painter.setPen(QPen(circleColor, 1));
@@ -487,7 +487,7 @@ void ArenaView::drawDebugTargetLines(QPainter& painter)
painter.drawLine(worldToWidget(from), worldToWidget(to)); painter.drawLine(worldToWidget(from), worldToWidget(to));
}; };
m_sim->admin().forEach<ShipIdentityComponent, PositionComponent, m_sim->getAdmin().forEach<ShipIdentityComponent, PositionComponent,
FactionComponent, AttackBehavior>( FactionComponent, AttackBehavior>(
[&](entt::entity /*e*/, const ShipIdentityComponent& /*si*/, [&](entt::entity /*e*/, const ShipIdentityComponent& /*si*/,
const PositionComponent& pos, const FactionComponent& fac, const PositionComponent& pos, const FactionComponent& fac,
@@ -502,7 +502,7 @@ void ArenaView::drawDebugTargetLines(QPainter& painter)
drawTargetLine(fac.isEnemy, pos.value, *targetPos); drawTargetLine(fac.isEnemy, pos.value, *targetPos);
}); });
m_sim->admin().forEach<ShipIdentityComponent, PositionComponent, m_sim->getAdmin().forEach<ShipIdentityComponent, PositionComponent,
FactionComponent, RepairBehavior>( FactionComponent, RepairBehavior>(
[&](entt::entity /*e*/, const ShipIdentityComponent& /*si*/, [&](entt::entity /*e*/, const ShipIdentityComponent& /*si*/,
const PositionComponent& pos, const FactionComponent& fac, const PositionComponent& pos, const FactionComponent& fac,
@@ -517,7 +517,7 @@ void ArenaView::drawDebugTargetLines(QPainter& painter)
drawTargetLine(fac.isEnemy, pos.value, *targetPos); drawTargetLine(fac.isEnemy, pos.value, *targetPos);
}); });
m_sim->admin().forEach<ShipIdentityComponent, PositionComponent, m_sim->getAdmin().forEach<ShipIdentityComponent, PositionComponent,
FactionComponent, SalvageScrapBehavior>( FactionComponent, SalvageScrapBehavior>(
[&](entt::entity /*e*/, const ShipIdentityComponent& /*si*/, [&](entt::entity /*e*/, const ShipIdentityComponent& /*si*/,
const PositionComponent& pos, const FactionComponent& fac, const PositionComponent& pos, const FactionComponent& fac,

View File

@@ -32,7 +32,7 @@ public:
~ArenaView() override; ~ArenaView() override;
void setGameSpeed(double multiplier); void setGameSpeed(double multiplier);
double gameSpeed() const; double getGameSpeed() const;
void togglePause(); void togglePause();
void stopRendering(); void stopRendering();
@@ -56,7 +56,7 @@ private:
void drawDebugTargetLines(QPainter& painter); void drawDebugTargetLines(QPainter& painter);
void drawBeams(QPainter& painter); void drawBeams(QPainter& painter);
float tilePx() const; float getTilePx() const;
QPointF worldToWidget(QVector2D worldPos) const; QPointF worldToWidget(QVector2D worldPos) const;
QPointF tileToWidget(QPoint tile) const; QPointF tileToWidget(QPoint tile) const;
QRectF tileRect(QPoint tile) const; QRectF tileRect(QPoint tile) const;

View File

@@ -141,7 +141,7 @@ void ArenaWidget::updateStatus(const ArenaStatus& status)
} }
threat->setText(tr("Threat: %1").arg(QString::number(team.threatLevel, 'f', 0))); threat->setText(tr("Threat: %1").arg(QString::number(team.threatLevel, 'f', 0)));
ehp->setText(tr("EHP: %1").arg(QString::fromStdString(team.ehpPercentText()))); ehp->setText(tr("EHP: %1").arg(QString::fromStdString(team.getEhpPercentText())));
QString lines; QString lines;
for (const ArenaStatus::Entry& entry : team.entries) for (const ArenaStatus::Entry& entry : team.entries)

View File

@@ -46,7 +46,7 @@ namespace
header = QStringLiteral("[WON] ") + header; header = QStringLiteral("[WON] ") + header;
} }
header += QStringLiteral(" - threat %1").arg(QString::number(team.threatLevel, 'f', 0)); header += QStringLiteral(" - threat %1").arg(QString::number(team.threatLevel, 'f', 0));
header += QStringLiteral(" - EHP %1").arg(QString::fromStdString(team.ehpPercentText())); header += QStringLiteral(" - EHP %1").arg(QString::fromStdString(team.getEhpPercentText()));
return escapeCell(header); return escapeCell(header);
} }
@@ -147,7 +147,7 @@ void BalancingWindow::populateArenas(const BalancingConfig& balancingConfig)
entry.widget = new ArenaWidget(index, arenaConfig.name, scrollContent); entry.widget = new ArenaWidget(index, arenaConfig.name, scrollContent);
contentLayout->addWidget(entry.widget); contentLayout->addWidget(entry.widget);
entry.widget->updateStatus(entry.simulation->status()); entry.widget->updateStatus(entry.simulation->getStatus());
m_arenas.push_back(std::move(entry)); m_arenas.push_back(std::move(entry));
} }
@@ -179,14 +179,14 @@ void BalancingWindow::pollStatuses()
{ {
if (entry.worker.joinable()) if (entry.worker.joinable())
{ {
const ArenaStatus status = entry.simulation->status(); const ArenaStatus status = entry.simulation->getStatus();
entry.widget->updateStatus(status); entry.widget->updateStatus(status);
} }
} }
if (m_inspectedSim && m_inspectedArenaIndex >= 0) if (m_inspectedSim && m_inspectedArenaIndex >= 0)
{ {
const ArenaStatus status = m_inspectedSim->status(); const ArenaStatus status = m_inspectedSim->getStatus();
m_arenas[static_cast<std::size_t>(m_inspectedArenaIndex)].widget->updateStatus(status); m_arenas[static_cast<std::size_t>(m_inspectedArenaIndex)].widget->updateStatus(status);
} }
@@ -242,7 +242,7 @@ void BalancingWindow::startArena(int index)
entry.simulation = std::make_unique<ArenaSimulation>( entry.simulation = std::make_unique<ArenaSimulation>(
m_gameConfig, entry.config, m_nextSeed++); m_gameConfig, entry.config, m_nextSeed++);
entry.widget->startSimulation(); entry.widget->startSimulation();
entry.widget->updateStatus(entry.simulation->status()); entry.widget->updateStatus(entry.simulation->getStatus());
ArenaSimulation* sim = entry.simulation.get(); ArenaSimulation* sim = entry.simulation.get();
entry.worker = std::thread([sim]() { sim->run(); }); entry.worker = std::thread([sim]() { sim->run(); });
updateButtons(); updateButtons();
@@ -278,7 +278,7 @@ void BalancingWindow::inspectArena(int index)
entry.widget->resetToGrey(); entry.widget->resetToGrey();
entry.widget->startSimulation(); entry.widget->startSimulation();
entry.widget->updateStatus(m_inspectedSim->status()); entry.widget->updateStatus(m_inspectedSim->getStatus());
m_inspectWindow = new InspectWindow( m_inspectWindow = new InspectWindow(
m_inspectedSim.get(), &m_gameConfig, &m_visuals, entry.config.name, nullptr); m_inspectedSim.get(), &m_gameConfig, &m_visuals, entry.config.name, nullptr);
@@ -336,7 +336,7 @@ void BalancingWindow::updateButtons()
bool allRunning = true; bool allRunning = true;
for (ArenaEntry& entry : m_arenas) for (ArenaEntry& entry : m_arenas)
{ {
if (entry.worker.joinable() && !entry.simulation->status().finished) if (entry.worker.joinable() && !entry.simulation->getStatus().finished)
{ {
anyRunning = true; anyRunning = true;
} }

View File

@@ -199,7 +199,7 @@ void InspectWindow::handleEvent(std::shared_ptr<const GameSpeedChangedEvent> eve
void InspectWindow::pollStatus() void InspectWindow::pollStatus()
{ {
const ArenaStatus status = m_sim->status(); const ArenaStatus status = m_sim->getStatus();
updateInfoPanel(status); updateInfoPanel(status);
refreshEntityStats(); refreshEntityStats();
} }
@@ -228,7 +228,7 @@ void InspectWindow::updateInfoPanel(const ArenaStatus& status)
} }
threat->setText(tr("Threat: %1").arg(QString::number(team.threatLevel, 'f', 0))); threat->setText(tr("Threat: %1").arg(QString::number(team.threatLevel, 'f', 0)));
ehp->setText(tr("EHP: %1").arg(QString::fromStdString(team.ehpPercentText()))); ehp->setText(tr("EHP: %1").arg(QString::fromStdString(team.getEhpPercentText())));
QString lines; QString lines;
for (const ArenaStatus::Entry& entry : team.entries) for (const ArenaStatus::Entry& entry : team.entries)
@@ -256,7 +256,7 @@ void InspectWindow::handleEvent(std::shared_ptr<const EntitySelectedEvent> event
{ {
m_selectedEntity = event->entity; m_selectedEntity = event->entity;
EntityAdmin& admin = m_sim->admin(); EntityAdmin& admin = m_sim->getAdmin();
entt::entity entity = *m_selectedEntity; entt::entity entity = *m_selectedEntity;
if (!admin.isValid(entity)) if (!admin.isValid(entity))
@@ -332,7 +332,7 @@ void InspectWindow::refreshEntityStats()
{ {
if (!m_selectedEntity.has_value()) { return; } if (!m_selectedEntity.has_value()) { return; }
EntityAdmin& admin = m_sim->admin(); EntityAdmin& admin = m_sim->getAdmin();
entt::entity entity = *m_selectedEntity; entt::entity entity = *m_selectedEntity;
if (!admin.isValid(entity)) if (!admin.isValid(entity))

View File

@@ -30,7 +30,7 @@ public:
// Evaluates the expression at the given x. Requires a compiled formula. // Evaluates the expression at the given x. Requires a compiled formula.
double evaluate(double x) const; double evaluate(double x) const;
const std::string& source() const { return m_source; } const std::string& getSource() const { return m_source; }
bool isValid() const { return m_expr != nullptr; } bool isValid() const { return m_expr != nullptr; }
private: private:

View File

@@ -30,7 +30,7 @@ void SalvagerSystem::tick(Tick currentTick, ScrapSystem& scraps, BuildingSystem&
// Apply collections whose mid-beam delay has elapsed (cycles started earlier). // Apply collections whose mid-beam delay has elapsed (cycles started earlier).
applyPendingCollections(currentTick, scraps); applyPendingCollections(currentTick, scraps);
const std::vector<ScrapInfo> allScrap = scraps.allScrapInfo(); const std::vector<ScrapInfo> allScrap = scraps.getAllScrapInfo();
// Tick down per-module collection cooldowns. // Tick down per-module collection cooldowns.
m_admin.forEach<SalvagerComponent>( m_admin.forEach<SalvagerComponent>(

View File

@@ -65,7 +65,7 @@ bool ScrapSystem::collectOne(entt::entity entity)
return true; return true;
} }
std::vector<ScrapInfo> ScrapSystem::allScrapInfo() const std::vector<ScrapInfo> ScrapSystem::getAllScrapInfo() const
{ {
std::vector<ScrapInfo> result; std::vector<ScrapInfo> result;
m_admin.forEach<ScrapDataComponent>( m_admin.forEach<ScrapDataComponent>(

View File

@@ -35,7 +35,7 @@ public:
bool collectOne(entt::entity entity); bool collectOne(entt::entity entity);
// Lightweight snapshot for callers that need to iterate all scrap. // Lightweight snapshot for callers that need to iterate all scrap.
std::vector<ScrapInfo> allScrapInfo() const; std::vector<ScrapInfo> getAllScrapInfo() const;
private: private:
EntityAdmin& m_admin; EntityAdmin& m_admin;

View File

@@ -19,7 +19,7 @@ void SalvageScrapEvaluator::evaluate(EntityAdmin& admin, const ScrapSystem& scra
{ {
TRACE(); TRACE();
const std::unordered_map<entt::entity, CargoState> cargoByShip = buildCargoByShip(admin); const std::unordered_map<entt::entity, CargoState> cargoByShip = buildCargoByShip(admin);
const std::vector<ScrapInfo> allScrap = scraps.allScrapInfo(); const std::vector<ScrapInfo> allScrap = scraps.getAllScrapInfo();
admin.forEach<SalvageScrapBehavior, PositionComponent, SensorRangeComponent>( admin.forEach<SalvageScrapBehavior, PositionComponent, SensorRangeComponent>(
[&](entt::entity e, SalvageScrapBehavior& salvage, const PositionComponent& pos, [&](entt::entity e, SalvageScrapBehavior& salvage, const PositionComponent& pos,

View File

@@ -86,7 +86,7 @@ struct Building
// Total items held on the output side: buffered plus still-emerging. The // Total items held on the output side: buffered plus still-emerging. The
// output-buffer capacity rule (REQ-MAT-OUTPUT-BUFFER) counts emerging items, // output-buffer capacity rule (REQ-MAT-OUTPUT-BUFFER) counts emerging items,
// since they have not yet left the building. // since they have not yet left the building.
int outputItemCount() const int getOutputItemCount() const
{ {
int count = static_cast<int>(outputBuffer.items.size()); int count = static_cast<int>(outputBuffer.items.size());
for (const std::vector<BeltItemSlot>& lane : emergingItems) for (const std::vector<BeltItemSlot>& lane : emergingItems)

View File

@@ -26,15 +26,15 @@ struct SelectedBuilding
// (the HQ and defence stations, per REQ-UI-BLUEPRINT-CREATE). // (the HQ and defence stations, per REQ-UI-BLUEPRINT-CREATE).
std::optional<SelectedBuilding> resolvePlaceable(const Simulation& sim, BuildingId id) std::optional<SelectedBuilding> resolvePlaceable(const Simulation& sim, BuildingId id)
{ {
const Building* building = sim.buildings().findBuilding(id); const Building* building = sim.getBuildings().findBuilding(id);
const ConstructionSite* site = building ? nullptr : sim.buildings().findSite(id); const ConstructionSite* site = building ? nullptr : sim.getBuildings().findSite(id);
if (!building && !site) if (!building && !site)
{ {
return std::nullopt; return std::nullopt;
} }
const BuildingType type = building ? building->type : site->type; const BuildingType type = building ? building->type : site->type;
const BuildingDef* def = sim.config().buildings.findBuildingDef(type); const BuildingDef* def = sim.getConfig().buildings.findBuildingDef(type);
if (!def || !def->playerPlaceable) if (!def || !def->playerPlaceable)
{ {
return std::nullopt; return std::nullopt;
@@ -52,8 +52,8 @@ std::optional<SelectedBuilding> resolvePlaceable(const Simulation& sim, Building
std::optional<BuildingConfig> readBuildingConfig(const Simulation& sim, BuildingId id) std::optional<BuildingConfig> readBuildingConfig(const Simulation& sim, BuildingId id)
{ {
const Building* building = sim.buildings().findBuilding(id); const Building* building = sim.getBuildings().findBuilding(id);
const ConstructionSite* site = building ? nullptr : sim.buildings().findSite(id); const ConstructionSite* site = building ? nullptr : sim.getBuildings().findSite(id);
if (!building && !site) if (!building && !site)
{ {
return std::nullopt; return std::nullopt;
@@ -77,7 +77,7 @@ std::optional<BuildingConfig> readBuildingConfig(const Simulation& sim, Building
{ {
// Operational splitter filters live in the BeltSystem, keyed by tile. // Operational splitter filters live in the BeltSystem, keyed by tile.
const std::optional<BeltSystem::SplitterInfo> info = const std::optional<BeltSystem::SplitterInfo> info =
sim.belts().getSplitterInfo(building->anchor); sim.getBelts().getSplitterInfo(building->anchor);
if (info.has_value()) if (info.has_value())
{ {
config.splitterFilterA = info->filterA; config.splitterFilterA = info->filterA;

View File

@@ -1014,7 +1014,7 @@ void BuildingSystem::tickProduction(Tick currentTick)
// 3. Output buffer has space for chosen outputs? Emerging items still // 3. Output buffer has space for chosen outputs? Emerging items still
// count against the buffer (REQ-MAT-OUTPUT-EMERGE). // count against the buffer (REQ-MAT-OUTPUT-EMERGE).
const int newSize = building.outputItemCount() const int newSize = building.getOutputItemCount()
+ static_cast<int>(chosen.size()); + static_cast<int>(chosen.size());
if (newSize > building.outputBuffer.capacity) if (newSize > building.outputBuffer.capacity)
{ {
@@ -1279,12 +1279,12 @@ const ConstructionSite* BuildingSystem::findSite(BuildingId id) const
return nullptr; return nullptr;
} }
std::vector<Building> BuildingSystem::allBuildings() const std::vector<Building> BuildingSystem::getAllBuildings() const
{ {
return m_buildings; return m_buildings;
} }
std::vector<ConstructionSite> BuildingSystem::allSites() const std::vector<ConstructionSite> BuildingSystem::getAllSites() const
{ {
return std::vector<ConstructionSite>(m_constructionQueue.begin(), return std::vector<ConstructionSite>(m_constructionQueue.begin(),
m_constructionQueue.end()); m_constructionQueue.end());
@@ -1308,7 +1308,7 @@ bool isProductionBuildingType(BuildingType type)
} }
} // namespace } // namespace
int BuildingSystem::productionBuildingCount() const int BuildingSystem::getProductionBuildingCount() const
{ {
int count = 0; int count = 0;
for (const Building& b : m_buildings) for (const Building& b : m_buildings)
@@ -1318,7 +1318,7 @@ int BuildingSystem::productionBuildingCount() const
return count; return count;
} }
int BuildingSystem::activeProductionBuildingCount() const int BuildingSystem::getActiveProductionBuildingCount() const
{ {
int count = 0; int count = 0;
for (const Building& b : m_buildings) for (const Building& b : m_buildings)
@@ -1328,7 +1328,7 @@ int BuildingSystem::activeProductionBuildingCount() const
return count; return count;
} }
std::vector<BuildingSystem::BeltTileInfo> BuildingSystem::allBeltTiles() const std::vector<BuildingSystem::BeltTileInfo> BuildingSystem::getAllBeltTiles() const
{ {
std::vector<BeltTileInfo> result; std::vector<BeltTileInfo> result;
for (const Building& b : m_buildings) for (const Building& b : m_buildings)
@@ -1518,7 +1518,7 @@ bool BuildingSystem::deliverScrapToSalvageBay(BuildingId bayId)
} }
// Emerging scrap still counts against the bay's holding capacity // Emerging scrap still counts against the bay's holding capacity
// (REQ-MAT-OUTPUT-EMERGE). // (REQ-MAT-OUTPUT-EMERGE).
if (bay->outputItemCount() >= bay->outputBuffer.capacity) if (bay->getOutputItemCount() >= bay->outputBuffer.capacity)
{ {
return false; return false;
} }

View File

@@ -112,17 +112,17 @@ public:
const Building* findBuilding(BuildingId id) const; const Building* findBuilding(BuildingId id) const;
const ConstructionSite* findSite(BuildingId id) const; const ConstructionSite* findSite(BuildingId id) const;
std::vector<Building> allBuildings() const; std::vector<Building> getAllBuildings() const;
std::vector<ConstructionSite> allSites() const; std::vector<ConstructionSite> getAllSites() const;
// REQ-UI-DEBUG-OVERLAY "Max Factory Production": count of completed // REQ-UI-DEBUG-OVERLAY "Max Factory Production": count of completed
// (operational) Miner/Smelter/Assembler/ReprocessingPlant/Shipyard buildings. // (operational) Miner/Smelter/Assembler/ReprocessingPlant/Shipyard buildings.
int productionBuildingCount() const; int getProductionBuildingCount() const;
// REQ-UI-DEBUG-OVERLAY "Current Factory Production": subset of the above // REQ-UI-DEBUG-OVERLAY "Current Factory Production": subset of the above
// that currently has an active production cycle. // that currently has an active production cycle.
int activeProductionBuildingCount() const; int getActiveProductionBuildingCount() const;
std::vector<BeltTileInfo> allBeltTiles() const; std::vector<BeltTileInfo> getAllBeltTiles() const;
bool isTileOccupied(QPoint tile) const; bool isTileOccupied(QPoint tile) const;
// Visits every item currently emerging from a building output port on its // Visits every item currently emerging from a building output port on its

View File

@@ -46,18 +46,18 @@ void CommandManager::drain()
{ {
// Restart is a file boundary: a fresh file with the new seed. // Restart is a file boundary: a fresh file with the new seed.
m_recorder->startNewRun(m_simulation.getSeed(), m_recorder->startNewRun(m_simulation.getSeed(),
m_simulation.rngFingerprint()); m_simulation.getRngFingerprint());
} }
} }
else else
{ {
// Commands drain before the tick batch, so currentTick is the count of // Commands drain before the tick batch, so currentTick is the count of
// completed ticks the command is pinned to. // completed ticks the command is pinned to.
const Tick tick = m_simulation.currentTick(); const Tick tick = m_simulation.getCurrentTick();
m_simulation.apply(*command); m_simulation.apply(*command);
if (m_recorder) if (m_recorder)
{ {
m_recorder->recordCommand(tick, *command, m_simulation.rngFingerprint()); m_recorder->recordCommand(tick, *command, m_simulation.getRngFingerprint());
} }
} }
} }
@@ -74,7 +74,7 @@ void CommandManager::setRecorder(std::unique_ptr<ReplayRecorder> recorder)
m_recorder = std::move(recorder); m_recorder = std::move(recorder);
if (m_recorder) if (m_recorder)
{ {
m_recorder->startNewRun(m_simulation.getSeed(), m_simulation.rngFingerprint()); m_recorder->startNewRun(m_simulation.getSeed(), m_simulation.getRngFingerprint());
} }
} }
@@ -85,8 +85,8 @@ void CommandManager::setReplayMode(bool replayMode)
void CommandManager::recordTickCheckpoint() void CommandManager::recordTickCheckpoint()
{ {
if (m_recorder && (m_simulation.currentTick() % kChecksumIntervalTicks == 0)) if (m_recorder && (m_simulation.getCurrentTick() % kChecksumIntervalTicks == 0))
{ {
m_recorder->recordChecksum(m_simulation.currentTick(), m_simulation.rngFingerprint()); m_recorder->recordChecksum(m_simulation.getCurrentTick(), m_simulation.getRngFingerprint());
} }
} }

View File

@@ -48,7 +48,7 @@ void ReplayPlayer::processEntriesAt(Tick tick)
{ {
m_simulation.apply(*entry.command); m_simulation.apply(*entry.command);
} }
else if (m_simulation.rngFingerprint() != entry.fingerprint) else if (m_simulation.getRngFingerprint() != entry.fingerprint)
{ {
m_desyncTick = tick; m_desyncTick = tick;
} }

View File

@@ -19,7 +19,7 @@ class Simulation;
// each frame, for each tick to run: // each frame, for each tick to run:
// if (player.isFinished()) break; // if (player.isFinished()) break;
// sim.tick(); // sim.tick();
// player.advanceTo(sim.currentTick()); // player.advanceTo(sim.getCurrentTick());
class ReplayPlayer class ReplayPlayer
{ {
public: public:

View File

@@ -58,7 +58,7 @@ std::string computeReplayConfigHash(const std::string& configDir)
hasher.appendBytes(bytes.constData(), static_cast<std::size_t>(bytes.size())); hasher.appendBytes(bytes.constData(), static_cast<std::size_t>(bytes.size()));
} }
} }
return toHex(hasher.value()); return toHex(hasher.getValue());
} }
void ReplayRecorder::startNewRun(unsigned int seed, std::uint64_t initialRngFingerprint) void ReplayRecorder::startNewRun(unsigned int seed, std::uint64_t initialRngFingerprint)
@@ -124,7 +124,7 @@ bool ReplayRecorder::isOpen() const
return m_stream.is_open(); return m_stream.is_open();
} }
const std::string& ReplayRecorder::currentFilePath() const const std::string& ReplayRecorder::getCurrentFilePath() const
{ {
return m_filePath; return m_filePath;
} }

View File

@@ -44,7 +44,7 @@ public:
void close(); void close();
bool isOpen() const; bool isOpen() const;
const std::string& currentFilePath() const; const std::string& getCurrentFilePath() const;
private: private:
std::string m_configDir; std::string m_configDir;

View File

@@ -113,7 +113,7 @@ Simulation::~Simulation()
unregisterForEvents(); unregisterForEvents();
} }
const GameConfig& Simulation::config() const const GameConfig& Simulation::getConfig() const
{ {
return m_config; return m_config;
} }
@@ -579,7 +579,7 @@ void Simulation::tickDeathsAndLoot()
} }
else else
{ {
const double genD = static_cast<double>(m_waveSystem->generation()); const double genD = static_cast<double>(m_waveSystem->getGeneration());
scrap = static_cast<int>( scrap = static_cast<int>(
m_config.stations.enemyStation.scrapDropFormula.evaluate(genD)); m_config.stations.enemyStation.scrapDropFormula.evaluate(genD));
} }
@@ -619,9 +619,9 @@ void Simulation::tickDeathsAndLoot()
if (es0Gone && es1Gone && if (es0Gone && es1Gone &&
m_currentEnemyStationEntities[0] != entt::null) m_currentEnemyStationEntities[0] != entt::null)
{ {
const int destroyedLevel = m_waveSystem->generation(); const int destroyedLevel = m_waveSystem->getGeneration();
m_waveSystem->onEnemyStationsDestroyed(); m_waveSystem->onEnemyStationsDestroyed();
placeEnemyStationSet(m_waveSystem->generation()); placeEnemyStationSet(m_waveSystem->getGeneration());
generateSchematicChoices(destroyedLevel); generateSchematicChoices(destroyedLevel);
} }
} }
@@ -968,7 +968,7 @@ void Simulation::appendStringSet(Hasher& hasher, const std::set<std::string>& id
} }
} }
unsigned long long Simulation::rngFingerprint() const unsigned long long Simulation::getRngFingerprint() const
{ {
return fingerprintRng(m_rng); return fingerprintRng(m_rng);
} }
@@ -991,11 +991,11 @@ unsigned long long Simulation::computeStateChecksum() const
hasher.append(m_expansionsPurchased); hasher.append(m_expansionsPurchased);
// WaveSystem scalar state, reached through existing accessors. // WaveSystem scalar state, reached through existing accessors.
hasher.append(threatLevel()); hasher.append(getThreatLevel());
hasher.append(threatAccumulationRate()); hasher.append(getThreatAccumulationRate());
hasher.append(bossWaveCounter()); hasher.append(getBossWaveCounter());
hasher.append(bossCountdownTicks()); hasher.append(getBossCountdownTicks());
hasher.append(normalGapRemainingTicks()); hasher.append(getNormalGapRemainingTicks());
// Schematic / unlock state (std::map and std::set iterate in sorted order). // Schematic / unlock state (std::map and std::set iterate in sorted order).
appendSchematicMap(hasher, m_schematicLevels); appendSchematicMap(hasher, m_schematicLevels);
@@ -1052,7 +1052,7 @@ unsigned long long Simulation::computeStateChecksum() const
hasher.append(c.schematicId); hasher.append(c.schematicId);
}); });
return hasher.value(); return hasher.getValue();
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -1081,7 +1081,7 @@ bool Simulation::hasSchematicChoicesPending() const
// Accessors // Accessors
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
Tick Simulation::currentTick() const Tick Simulation::getCurrentTick() const
{ {
return m_currentTick; return m_currentTick;
} }
@@ -1091,18 +1091,18 @@ unsigned int Simulation::getSeed() const
return m_seed; return m_seed;
} }
int Simulation::buildingBlocksStock() const int Simulation::getBuildingBlocksStock() const
{ {
return m_buildingBlocksStock; return m_buildingBlocksStock;
} }
int Simulation::currentAsteroidWidth_tiles() const int Simulation::getCurrentAsteroidWidth_tiles() const
{ {
return m_config.world.regions.asteroidWidth_tiles return m_config.world.regions.asteroidWidth_tiles
+ m_expansionsPurchased * m_config.world.expansion.columnsPerExpansion_tiles; + m_expansionsPurchased * m_config.world.expansion.columnsPerExpansion_tiles;
} }
int Simulation::currentExpansionCost() const int Simulation::getCurrentExpansionCost() const
{ {
const double cost = m_config.world.expansion.costBuildingBlocksFormula.evaluate( const double cost = m_config.world.expansion.costBuildingBlocksFormula.evaluate(
static_cast<double>(m_expansionsPurchased)); static_cast<double>(m_expansionsPurchased));
@@ -1111,14 +1111,14 @@ int Simulation::currentExpansionCost() const
void Simulation::tryExpandAsteroid() void Simulation::tryExpandAsteroid()
{ {
const int cost = currentExpansionCost(); const int cost = getCurrentExpansionCost();
if (m_buildingBlocksStock < cost) if (m_buildingBlocksStock < cost)
{ {
return; return;
} }
m_buildingBlocksStock -= cost; m_buildingBlocksStock -= cost;
++m_expansionsPurchased; ++m_expansionsPurchased;
m_buildingSystem->setAsteroidWidth_tiles(currentAsteroidWidth_tiles()); m_buildingSystem->setAsteroidWidth_tiles(getCurrentAsteroidWidth_tiles());
} }
bool Simulation::isGameOver() const bool Simulation::isGameOver() const
@@ -1131,44 +1131,44 @@ bool Simulation::isWon() const
return m_isWon; return m_isWon;
} }
int Simulation::artifactCount() const int Simulation::getArtifactCount() const
{ {
return m_artifactCount; return m_artifactCount;
} }
double Simulation::threatLevel() const double Simulation::getThreatLevel() const
{ {
return m_waveSystem->threatLevel(); return m_waveSystem->getThreatLevel();
} }
double Simulation::threatAccumulationRate() const double Simulation::getThreatAccumulationRate() const
{ {
return m_waveSystem->threatAccumulationRate(); return m_waveSystem->getThreatAccumulationRate();
} }
double Simulation::maxFactoryProductionThreatRate() const double Simulation::getMaxFactoryProductionThreatRate() const
{ {
return static_cast<double>(m_buildingSystem->productionBuildingCount()); return static_cast<double>(m_buildingSystem->getProductionBuildingCount());
} }
double Simulation::currentFactoryProductionThreatRate() const double Simulation::getCurrentFactoryProductionThreatRate() const
{ {
return static_cast<double>(m_buildingSystem->activeProductionBuildingCount()); return static_cast<double>(m_buildingSystem->getActiveProductionBuildingCount());
} }
int Simulation::bossWaveCounter() const int Simulation::getBossWaveCounter() const
{ {
return m_waveSystem->bossWaveCounter(); return m_waveSystem->getBossWaveCounter();
} }
Tick Simulation::bossCountdownTicks() const Tick Simulation::getBossCountdownTicks() const
{ {
return m_waveSystem->bossCountdownTicks(); return m_waveSystem->getBossCountdownTicks();
} }
Tick Simulation::normalGapRemainingTicks() const Tick Simulation::getNormalGapRemainingTicks() const
{ {
return m_waveSystem->normalGapRemainingTicks(); return m_waveSystem->getNormalGapRemainingTicks();
} }
bool Simulation::isSchematicUnlocked(const std::string& shipId) const bool Simulation::isSchematicUnlocked(const std::string& shipId) const
@@ -1222,52 +1222,52 @@ void Simulation::demolish(BuildingId id)
m_buildingBlocksStock += m_buildingSystem->demolish(id); m_buildingBlocksStock += m_buildingSystem->demolish(id);
} }
BuildingSystem& Simulation::buildingsMutable() BuildingSystem& Simulation::getBuildingsMutable()
{ {
return *m_buildingSystem; return *m_buildingSystem;
} }
const BuildingSystem& Simulation::buildings() const const BuildingSystem& Simulation::getBuildings() const
{ {
return *m_buildingSystem; return *m_buildingSystem;
} }
BeltSystem& Simulation::beltsMutable() BeltSystem& Simulation::getBeltsMutable()
{ {
return m_beltSystem; return m_beltSystem;
} }
const BeltSystem& Simulation::belts() const const BeltSystem& Simulation::getBelts() const
{ {
return m_beltSystem; return m_beltSystem;
} }
ShipSystem& Simulation::ships() ShipSystem& Simulation::getShips()
{ {
return *m_shipSystem; return *m_shipSystem;
} }
const ShipSystem& Simulation::ships() const const ShipSystem& Simulation::getShips() const
{ {
return *m_shipSystem; return *m_shipSystem;
} }
ScrapSystem& Simulation::scraps() ScrapSystem& Simulation::getScraps()
{ {
return *m_scrapSystem; return *m_scrapSystem;
} }
const ScrapSystem& Simulation::scraps() const const ScrapSystem& Simulation::getScraps() const
{ {
return *m_scrapSystem; return *m_scrapSystem;
} }
EntityAdmin& Simulation::admin() EntityAdmin& Simulation::getAdmin()
{ {
return m_admin; return m_admin;
} }
const EntityAdmin& Simulation::admin() const const EntityAdmin& Simulation::getAdmin() const
{ {
return m_admin; return m_admin;
} }

View File

@@ -41,7 +41,7 @@ public:
explicit Simulation(GameConfig config, unsigned int seed = 0); explicit Simulation(GameConfig config, unsigned int seed = 0);
~Simulation(); ~Simulation();
const GameConfig& config() const; const GameConfig& getConfig() const;
// Reinitializes all simulation state as if constructed fresh. // Reinitializes all simulation state as if constructed fresh.
void reset(unsigned int seed = 0); void reset(unsigned int seed = 0);
@@ -68,26 +68,26 @@ public:
// Returns true if there are pending schematic choices waiting for player input. // Returns true if there are pending schematic choices waiting for player input.
bool hasSchematicChoicesPending() const; bool hasSchematicChoicesPending() const;
Tick currentTick() const; Tick getCurrentTick() const;
// The seed this run was (re)initialized with; written to the replay header. // The seed this run was (re)initialized with; written to the replay header.
unsigned int getSeed() const; unsigned int getSeed() const;
int buildingBlocksStock() const; int getBuildingBlocksStock() const;
// Current asteroid width in tiles = base width + purchased expansions // Current asteroid width in tiles = base width + purchased expansions
// (REQ-EXP-UNLOCK, REQ-GW-ASTEROID-EXPAND). // (REQ-EXP-UNLOCK, REQ-GW-ASTEROID-EXPAND).
int currentAsteroidWidth_tiles() const; int getCurrentAsteroidWidth_tiles() const;
// Building block cost of the next expansion, floored to an integer // Building block cost of the next expansion, floored to an integer
// (REQ-EXP-COST); x = number of expansions already purchased. // (REQ-EXP-COST); x = number of expansions already purchased.
int currentExpansionCost() const; int getCurrentExpansionCost() const;
bool isGameOver() const; bool isGameOver() const;
bool isWon() const; bool isWon() const;
int artifactCount() const; int getArtifactCount() const;
double threatLevel() const; double getThreatLevel() const;
double threatAccumulationRate() const; double getThreatAccumulationRate() const;
double maxFactoryProductionThreatRate() const; double getMaxFactoryProductionThreatRate() const;
double currentFactoryProductionThreatRate() const; double getCurrentFactoryProductionThreatRate() const;
int bossWaveCounter() const; int getBossWaveCounter() const;
Tick bossCountdownTicks() const; Tick getBossCountdownTicks() const;
Tick normalGapRemainingTicks() const; Tick getNormalGapRemainingTicks() const;
// Ship schematic state query. // Ship schematic state query.
bool isSchematicUnlocked(const std::string& shipId) const; bool isSchematicUnlocked(const std::string& shipId) const;
@@ -102,25 +102,25 @@ public:
// -- Determinism (see docs/replay_design.md) ----------------------------- // -- Determinism (see docs/replay_design.md) -----------------------------
// 64-bit fingerprint of the RNG stream state. Cheap; written to the replay // 64-bit fingerprint of the RNG stream state. Cheap; written to the replay
// file periodically + after each command for desync detection. // file periodically + after each command for desync detection.
unsigned long long rngFingerprint() const; unsigned long long getRngFingerprint() const;
// 64-bit fingerprint of the full simulation state (RNG, scalars, buildings, // 64-bit fingerprint of the full simulation state (RNG, scalars, buildings,
// belts, and ECS component state). Used by the double-run determinism test; // belts, and ECS component state). Used by the double-run determinism test;
// a superset of rngFingerprint(). // a superset of getRngFingerprint().
unsigned long long computeStateChecksum() const; unsigned long long computeStateChecksum() const;
// Const subsystem accessors (queries only). The mutable counterparts are // Const subsystem accessors (queries only). The mutable counterparts are
// private and reachable only through Simulation::apply (the command // private and reachable only through Simulation::apply (the command
// chokepoint) or, in tests, SimulationTestAccess — so production code cannot // chokepoint) or, in tests, SimulationTestAccess — so production code cannot
// mutate the factory outside the recorded command path (docs/replay_design.md). // mutate the factory outside the recorded command path (docs/replay_design.md).
const BuildingSystem& buildings() const; const BuildingSystem& getBuildings() const;
const BeltSystem& belts() const; const BeltSystem& getBelts() const;
ShipSystem& ships(); ShipSystem& getShips();
const ShipSystem& ships() const; const ShipSystem& getShips() const;
ScrapSystem& scraps(); ScrapSystem& getScraps();
const ScrapSystem& scraps() const; const ScrapSystem& getScraps() const;
EntityAdmin& admin(); EntityAdmin& getAdmin();
const EntityAdmin& admin() const; const EntityAdmin& getAdmin() const;
private: private:
// Grants tests access to the private player-action mutators below without // Grants tests access to the private player-action mutators below without
@@ -148,8 +148,8 @@ private:
void tryExpandAsteroid(); void tryExpandAsteroid();
// Mutable subsystem accessors; same chokepoint rule as the mutators above. // Mutable subsystem accessors; same chokepoint rule as the mutators above.
BuildingSystem& buildingsMutable(); BuildingSystem& getBuildingsMutable();
BeltSystem& beltsMutable(); BeltSystem& getBeltsMutable();
void handleEvent(std::shared_ptr<const TracePrintRequestedEvent> event) override; void handleEvent(std::shared_ptr<const TracePrintRequestedEvent> event) override;

View File

@@ -57,5 +57,5 @@ std::uint64_t fingerprintRng(const std::mt19937& rng)
stream << rng; // full internal state as space-separated integers stream << rng; // full internal state as space-separated integers
Hasher hasher; Hasher hasher;
hasher.append(stream.str()); hasher.append(stream.str());
return hasher.value(); return hasher.getValue();
} }

View File

@@ -43,7 +43,7 @@ public:
void append(const QVector2D& vector); void append(const QVector2D& vector);
void append(const std::string& text); void append(const std::string& text);
std::uint64_t value() const { return m_state; } std::uint64_t getValue() const { return m_state; }
private: private:
std::uint64_t m_state = 14695981039346656037ull; // FNV-1a 64-bit offset basis std::uint64_t m_state = 14695981039346656037ull; // FNV-1a 64-bit offset basis

View File

@@ -98,12 +98,12 @@ void WaveSystem::onEnemyStationsDestroyed()
++m_generation; ++m_generation;
} }
double WaveSystem::threatLevel() const double WaveSystem::getThreatLevel() const
{ {
return m_threatLevel; return m_threatLevel;
} }
double WaveSystem::threatAccumulationRate() const double WaveSystem::getThreatAccumulationRate() const
{ {
if (isInQuietWindow()) if (isInQuietWindow())
{ {
@@ -113,22 +113,22 @@ double WaveSystem::threatAccumulationRate() const
return std::max(0.0, m_config.world.waves.threatRateFormula.evaluate(x)); return std::max(0.0, m_config.world.waves.threatRateFormula.evaluate(x));
} }
int WaveSystem::generation() const int WaveSystem::getGeneration() const
{ {
return m_generation; return m_generation;
} }
int WaveSystem::bossWaveCounter() const int WaveSystem::getBossWaveCounter() const
{ {
return m_bossWaveCounter; return m_bossWaveCounter;
} }
Tick WaveSystem::bossCountdownTicks() const Tick WaveSystem::getBossCountdownTicks() const
{ {
return m_bossCountdownTicks; return m_bossCountdownTicks;
} }
Tick WaveSystem::normalGapRemainingTicks() const Tick WaveSystem::getNormalGapRemainingTicks() const
{ {
return m_normalGapRemainingTicks; return m_normalGapRemainingTicks;
} }

View File

@@ -34,26 +34,26 @@ public:
// (REQ-WAV-BOSS-ADVANCE, REQ-PSH-STATION-STATS). // (REQ-WAV-BOSS-ADVANCE, REQ-PSH-STATION-STATS).
void onEnemyStationsDestroyed(); void onEnemyStationsDestroyed();
double threatLevel() const; double getThreatLevel() const;
// Current rate at which threatLevel() is increasing, in threat/second // Current rate at which getThreatLevel() is increasing, in threat/second
// (REQ-WAV-THREAT-RATE). 0 during a quiet window (REQ-WAV-QUIET) or when // (REQ-WAV-THREAT-RATE). 0 during a quiet window (REQ-WAV-QUIET) or when
// the rate formula evaluates to a negative value. // the rate formula evaluates to a negative value.
double threatAccumulationRate() const; double getThreatAccumulationRate() const;
// Current enemy-station generation level (0 for initial set, // Current enemy-station generation level (0 for initial set,
// incremented by 1 after each push — REQ-PSH-STATION-STATS). // incremented by 1 after each push — REQ-PSH-STATION-STATS).
int generation() const; int getGeneration() const;
// Boss wave counter (REQ-WAV-BOSS-COUNTER): current cycle number, starts at 1. // Boss wave counter (REQ-WAV-BOSS-COUNTER): current cycle number, starts at 1.
int bossWaveCounter() const; int getBossWaveCounter() const;
// Ticks remaining until the next boss wave fires (REQ-WAV-BOSS-COUNTDOWN). // Ticks remaining until the next boss wave fires (REQ-WAV-BOSS-COUNTDOWN).
Tick bossCountdownTicks() const; Tick getBossCountdownTicks() const;
// Ticks remaining on the current normal-wave gap timer (REQ-WAV-GAP). // Ticks remaining on the current normal-wave gap timer (REQ-WAV-GAP).
// Frozen during quiet windows. // Frozen during quiet windows.
Tick normalGapRemainingTicks() const; Tick getNormalGapRemainingTicks() const;
private: private:
struct SpawnEntry struct SpawnEntry

View File

@@ -19,7 +19,7 @@ static GameConfig loadConfig()
static void killEnemyStations(Simulation& sim) static void killEnemyStations(Simulation& sim)
{ {
sim.admin().forEach<StationBodyComponent, FactionComponent, HealthComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent, HealthComponent>(
[](entt::entity, StationBodyComponent&, FactionComponent& faction, HealthComponent& health) [](entt::entity, StationBodyComponent&, FactionComponent& faction, HealthComponent& health)
{ {
if (faction.isEnemy) if (faction.isEnemy)
@@ -65,7 +65,7 @@ TEST_CASE("ArtifactWinCondition: artifact count is 0 and isWon is false at game
"[artifact_win]") "[artifact_win]")
{ {
const Simulation sim(loadConfig()); const Simulation sim(loadConfig());
CHECK(sim.artifactCount() == 0); CHECK(sim.getArtifactCount() == 0);
CHECK_FALSE(sim.isWon()); CHECK_FALSE(sim.isWon());
} }
@@ -145,7 +145,7 @@ TEST_CASE("ArtifactWinCondition: selecting artifact increments artifact count",
SimulationTestAccess::applySchematicChoice(sim,index); SimulationTestAccess::applySchematicChoice(sim,index);
CHECK(sim.artifactCount() == 1); CHECK(sim.getArtifactCount() == 1);
} }
TEST_CASE("ArtifactWinCondition: selecting a non-artifact option does not increment artifact count", TEST_CASE("ArtifactWinCondition: selecting a non-artifact option does not increment artifact count",
@@ -166,7 +166,7 @@ TEST_CASE("ArtifactWinCondition: selecting a non-artifact option does not increm
SimulationTestAccess::applySchematicChoice(sim,static_cast<int>(it - choices.begin())); SimulationTestAccess::applySchematicChoice(sim,static_cast<int>(it - choices.begin()));
CHECK(sim.artifactCount() == 0); CHECK(sim.getArtifactCount() == 0);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -205,7 +205,7 @@ TEST_CASE("ArtifactWinCondition: isWon stays false when artifact count is below
REQUIRE(sim.hasSchematicChoicesPending()); REQUIRE(sim.hasSchematicChoicesPending());
SimulationTestAccess::applySchematicChoice(sim,findArtifactChoiceIndex(sim)); SimulationTestAccess::applySchematicChoice(sim,findArtifactChoiceIndex(sim));
CHECK(sim.artifactCount() == 1); CHECK(sim.getArtifactCount() == 1);
CHECK_FALSE(sim.isWon()); CHECK_FALSE(sim.isWon());
} }
@@ -226,7 +226,7 @@ TEST_CASE("ArtifactWinCondition: isWon becomes true after collecting required nu
SimulationTestAccess::applySchematicChoice(sim,index); SimulationTestAccess::applySchematicChoice(sim,index);
} }
CHECK(sim.artifactCount() == 2); CHECK(sim.getArtifactCount() == 2);
CHECK(sim.isWon()); CHECK(sim.isWon());
} }
@@ -249,6 +249,6 @@ TEST_CASE("ArtifactWinCondition: reset clears artifact count and win state",
sim.reset(); sim.reset();
CHECK(sim.artifactCount() == 0); CHECK(sim.getArtifactCount() == 0);
CHECK_FALSE(sim.isWon()); CHECK_FALSE(sim.isWon());
} }

View File

@@ -533,9 +533,9 @@ TEST_CASE("Blueprint placement: buildings land at anchor + offset from cursor",
REQUIRE(idA != kInvalidBuildingId); REQUIRE(idA != kInvalidBuildingId);
REQUIRE(idB != kInvalidBuildingId); REQUIRE(idB != kInvalidBuildingId);
REQUIRE(sim.buildings().isTileOccupied(cursor + offsetA)); // (-6, 0) REQUIRE(sim.getBuildings().isTileOccupied(cursor + offsetA)); // (-6, 0)
REQUIRE(sim.buildings().isTileOccupied(cursor + offsetB)); // (-4, 0) REQUIRE(sim.getBuildings().isTileOccupied(cursor + offsetB)); // (-4, 0)
REQUIRE_FALSE(sim.buildings().isTileOccupied(cursor)); // center not occupied REQUIRE_FALSE(sim.getBuildings().isTileOccupied(cursor)); // center not occupied
} }
TEST_CASE("Blueprint placement: cost is deducted for each building in sequence", "[blueprint]") TEST_CASE("Blueprint placement: cost is deducted for each building in sequence", "[blueprint]")
@@ -544,20 +544,20 @@ TEST_CASE("Blueprint placement: cost is deducted for each building in sequence",
// Find belt cost from config (belt cost = 2 in test config). // Find belt cost from config (belt cost = 2 in test config).
int beltCost = 0; int beltCost = 0;
for (const BuildingDef& def : sim.config().buildings.buildings) for (const BuildingDef& def : sim.getConfig().buildings.buildings)
{ {
if (def.type == BuildingType::Belt) { beltCost = def.cost; break; } if (def.type == BuildingType::Belt) { beltCost = def.cost; break; }
} }
REQUIRE(beltCost > 0); REQUIRE(beltCost > 0);
const int startBlocks = sim.buildingBlocksStock(); const int startBlocks = sim.getBuildingBlocksStock();
REQUIRE(startBlocks >= 2 * beltCost); // test config has enough starting blocks REQUIRE(startBlocks >= 2 * beltCost); // test config has enough starting blocks
SimulationTestAccess::place(sim,BuildingType::Belt, QPoint(-6, 0), Rotation::East); SimulationTestAccess::place(sim,BuildingType::Belt, QPoint(-6, 0), Rotation::East);
REQUIRE(sim.buildingBlocksStock() == startBlocks - beltCost); REQUIRE(sim.getBuildingBlocksStock() == startBlocks - beltCost);
SimulationTestAccess::place(sim,BuildingType::Belt, QPoint(-4, 0), Rotation::East); SimulationTestAccess::place(sim,BuildingType::Belt, QPoint(-4, 0), Rotation::East);
REQUIRE(sim.buildingBlocksStock() == startBlocks - 2 * beltCost); REQUIRE(sim.getBuildingBlocksStock() == startBlocks - 2 * beltCost);
} }
TEST_CASE("Blueprint placement: insufficient blocks returns kInvalidBuildingId and deducts nothing", TEST_CASE("Blueprint placement: insufficient blocks returns kInvalidBuildingId and deducts nothing",
@@ -567,7 +567,7 @@ TEST_CASE("Blueprint placement: insufficient blocks returns kInvalidBuildingId a
// Find miner cost (15 in test config) — expensive enough to exhaust a small stock. // Find miner cost (15 in test config) — expensive enough to exhaust a small stock.
int minerCost = 0; int minerCost = 0;
for (const BuildingDef& def : sim.config().buildings.buildings) for (const BuildingDef& def : sim.getConfig().buildings.buildings)
{ {
if (def.type == BuildingType::Miner) { minerCost = def.cost; break; } if (def.type == BuildingType::Miner) { minerCost = def.cost; break; }
} }
@@ -576,26 +576,26 @@ TEST_CASE("Blueprint placement: insufficient blocks returns kInvalidBuildingId a
// Drain the stock by placing miners until we no longer have enough. // Drain the stock by placing miners until we no longer have enough.
// Non-overlapping columns: miner body is 2 wide, so step by 2. // Non-overlapping columns: miner body is 2 wide, so step by 2.
int col = -2; int col = -2;
while (sim.buildingBlocksStock() >= minerCost) while (sim.getBuildingBlocksStock() >= minerCost)
{ {
SimulationTestAccess::place(sim,BuildingType::Miner, QPoint(col, 0), Rotation::East); SimulationTestAccess::place(sim,BuildingType::Miner, QPoint(col, 0), Rotation::East);
col -= 2; col -= 2;
} }
const int blocksBeforeAttempt = sim.buildingBlocksStock(); const int blocksBeforeAttempt = sim.getBuildingBlocksStock();
const BuildingId id = SimulationTestAccess::place(sim, const BuildingId id = SimulationTestAccess::place(sim,
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 == kInvalidBuildingId); REQUIRE(id == kInvalidBuildingId);
REQUIRE(sim.buildingBlocksStock() == blocksBeforeAttempt); REQUIRE(sim.getBuildingBlocksStock() == blocksBeforeAttempt);
} }
TEST_CASE("Simulation: tryPlaceBuilding rejects terrain-invalid placement and charges nothing", TEST_CASE("Simulation: tryPlaceBuilding rejects terrain-invalid placement and charges nothing",
"[blueprint]") "[blueprint]")
{ {
Simulation sim(loadConfig()); Simulation sim(loadConfig());
const int startBlocks = sim.buildingBlocksStock(); const int startBlocks = sim.getBuildingBlocksStock();
// A miner is all-asteroid; placing it in space (x >= 0) violates the terrain // A miner is all-asteroid; placing it in space (x >= 0) violates the terrain
// rule, so it must be rejected without consuming building blocks. // rule, so it must be rejected without consuming building blocks.
@@ -603,8 +603,8 @@ TEST_CASE("Simulation: tryPlaceBuilding rejects terrain-invalid placement and ch
SimulationTestAccess::place(sim,BuildingType::Miner, QPoint(0, 0), Rotation::East); SimulationTestAccess::place(sim,BuildingType::Miner, QPoint(0, 0), Rotation::East);
REQUIRE(id == kInvalidBuildingId); REQUIRE(id == kInvalidBuildingId);
REQUIRE(sim.buildingBlocksStock() == startBlocks); REQUIRE(sim.getBuildingBlocksStock() == startBlocks);
REQUIRE(sim.buildings().allSites().empty()); REQUIRE(sim.getBuildings().getAllSites().empty());
} }
TEST_CASE("Simulation: tryPlaceBuilding accepts a valid asteroid spot, occupies tiles, charges cost", TEST_CASE("Simulation: tryPlaceBuilding accepts a valid asteroid spot, occupies tiles, charges cost",
@@ -613,12 +613,12 @@ TEST_CASE("Simulation: tryPlaceBuilding accepts a valid asteroid spot, occupies
Simulation sim(loadConfig()); Simulation sim(loadConfig());
int minerCost = 0; int minerCost = 0;
for (const BuildingDef& def : sim.config().buildings.buildings) for (const BuildingDef& def : sim.getConfig().buildings.buildings)
{ {
if (def.type == BuildingType::Miner) { minerCost = def.cost; break; } if (def.type == BuildingType::Miner) { minerCost = def.cost; break; }
} }
REQUIRE(minerCost > 0); REQUIRE(minerCost > 0);
const int startBlocks = sim.buildingBlocksStock(); const int startBlocks = sim.getBuildingBlocksStock();
// Miner mask ["AA","A>"] East at (-3,0) → all-asteroid body at // Miner mask ["AA","A>"] East at (-3,0) → all-asteroid body at
// (-3,0),(-2,0),(-3,1); a valid spot. // (-3,0),(-2,0),(-3,1); a valid spot.
@@ -626,12 +626,12 @@ TEST_CASE("Simulation: tryPlaceBuilding accepts a valid asteroid spot, occupies
SimulationTestAccess::place(sim,BuildingType::Miner, QPoint(-3, 0), Rotation::East); SimulationTestAccess::place(sim,BuildingType::Miner, QPoint(-3, 0), Rotation::East);
REQUIRE(id != kInvalidBuildingId); REQUIRE(id != kInvalidBuildingId);
REQUIRE(sim.buildingBlocksStock() == startBlocks - minerCost); REQUIRE(sim.getBuildingBlocksStock() == startBlocks - minerCost);
REQUIRE(sim.buildings().isTileOccupied(QPoint(-3, 0))); REQUIRE(sim.getBuildings().isTileOccupied(QPoint(-3, 0)));
REQUIRE(sim.buildings().isTileOccupied(QPoint(-2, 0))); REQUIRE(sim.getBuildings().isTileOccupied(QPoint(-2, 0)));
REQUIRE(sim.buildings().isTileOccupied(QPoint(-3, 1))); REQUIRE(sim.getBuildings().isTileOccupied(QPoint(-3, 1)));
// The output-port tile (1,1)+anchor = (-2,1) is not a body cell. // The output-port tile (1,1)+anchor = (-2,1) is not a body cell.
REQUIRE_FALSE(sim.buildings().isTileOccupied(QPoint(-2, 1))); REQUIRE_FALSE(sim.getBuildings().isTileOccupied(QPoint(-2, 1)));
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -671,7 +671,7 @@ TEST_CASE("Blueprint placement: setRecipe on construction site stores recipe", "
SimulationTestAccess::buildings(sim).setRecipe(id, "mine_iron_ore"); SimulationTestAccess::buildings(sim).setRecipe(id, "mine_iron_ore");
const ConstructionSite* site = sim.buildings().findSite(id); const ConstructionSite* site = sim.getBuildings().findSite(id);
REQUIRE(site != nullptr); REQUIRE(site != nullptr);
REQUIRE(site->recipeId == "mine_iron_ore"); REQUIRE(site->recipeId == "mine_iron_ore");
} }
@@ -692,7 +692,7 @@ TEST_CASE("Blueprint placement: recipe transfers to building after construction
sim.tick(); sim.tick();
} }
const Building* b = sim.buildings().findBuilding(id); const Building* b = sim.getBuildings().findBuilding(id);
REQUIRE(b != nullptr); REQUIRE(b != nullptr);
REQUIRE(b->recipeId == "mine_copper_ore"); REQUIRE(b->recipeId == "mine_copper_ore");
} }
@@ -712,8 +712,8 @@ TEST_CASE("Blueprint creation: a construction site is captured", "[blueprint]")
const BuildingId id = const BuildingId id =
SimulationTestAccess::place(sim, BuildingType::Belt, QPoint(-2, 0), Rotation::East); SimulationTestAccess::place(sim, BuildingType::Belt, QPoint(-2, 0), Rotation::East);
REQUIRE(id != kInvalidBuildingId); REQUIRE(id != kInvalidBuildingId);
REQUIRE(sim.buildings().findSite(id) != nullptr); REQUIRE(sim.getBuildings().findSite(id) != nullptr);
REQUIRE(sim.buildings().findBuilding(id) == nullptr); REQUIRE(sim.getBuildings().findBuilding(id) == nullptr);
const Blueprint bp = captureBlueprintFromSelection(sim, { id }); const Blueprint bp = captureBlueprintFromSelection(sim, { id });
@@ -748,14 +748,14 @@ TEST_CASE("Blueprint creation: mixed operational building and construction site
REQUIRE(idA != kInvalidBuildingId); REQUIRE(idA != kInvalidBuildingId);
SimulationTestAccess::buildings(sim).setRecipe(idA, "mine_iron_ore"); SimulationTestAccess::buildings(sim).setRecipe(idA, "mine_iron_ore");
for (int i = 0; i <= static_cast<int>(secondsToTicks(10.0)); ++i) { sim.tick(); } for (int i = 0; i <= static_cast<int>(secondsToTicks(10.0)); ++i) { sim.tick(); }
REQUIRE(sim.buildings().findBuilding(idA) != nullptr); REQUIRE(sim.getBuildings().findBuilding(idA) != nullptr);
// Building B: place and configure, but leave as a construction site. // Building B: place and configure, but leave as a construction site.
const BuildingId idB = const BuildingId idB =
SimulationTestAccess::place(sim, BuildingType::Miner, QPoint(-6, 0), Rotation::East); SimulationTestAccess::place(sim, BuildingType::Miner, QPoint(-6, 0), Rotation::East);
REQUIRE(idB != kInvalidBuildingId); REQUIRE(idB != kInvalidBuildingId);
SimulationTestAccess::buildings(sim).setRecipe(idB, "mine_copper_ore"); SimulationTestAccess::buildings(sim).setRecipe(idB, "mine_copper_ore");
REQUIRE(sim.buildings().findSite(idB) != nullptr); REQUIRE(sim.getBuildings().findSite(idB) != nullptr);
const Blueprint bp = captureBlueprintFromSelection(sim, { idA, idB }); const Blueprint bp = captureBlueprintFromSelection(sim, { idA, idB });
@@ -779,7 +779,7 @@ TEST_CASE("Blueprint creation: selectionHasPlaceableBuilding sees a construction
const BuildingId id = const BuildingId id =
SimulationTestAccess::place(sim, BuildingType::Miner, QPoint(-2, 0), Rotation::East); SimulationTestAccess::place(sim, BuildingType::Miner, QPoint(-2, 0), Rotation::East);
REQUIRE(id != kInvalidBuildingId); REQUIRE(id != kInvalidBuildingId);
REQUIRE(sim.buildings().findSite(id) != nullptr); REQUIRE(sim.getBuildings().findSite(id) != nullptr);
REQUIRE(selectionHasPlaceableBuilding(sim, { id })); REQUIRE(selectionHasPlaceableBuilding(sim, { id }));
} }
@@ -859,7 +859,7 @@ TEST_CASE("Blueprint placement: setShipLayout on construction site stores layout
SimulationTestAccess::buildings(sim).setShipLayout(id, layout); SimulationTestAccess::buildings(sim).setShipLayout(id, layout);
const ConstructionSite* site = sim.buildings().findSite(id); const ConstructionSite* site = sim.getBuildings().findSite(id);
REQUIRE(site != nullptr); REQUIRE(site != nullptr);
REQUIRE(site->shipLayout.has_value()); REQUIRE(site->shipLayout.has_value());
REQUIRE(site->shipLayout->placedModules.size() == 1); REQUIRE(site->shipLayout->placedModules.size() == 1);
@@ -885,7 +885,7 @@ TEST_CASE("Blueprint placement: ship layout transfers to building after construc
// Shipyard construction_time_seconds = 30 in the test config. // Shipyard construction_time_seconds = 30 in the test config.
double constructionTime = 0.0; double constructionTime = 0.0;
for (const BuildingDef& def : sim.config().buildings.buildings) for (const BuildingDef& def : sim.getConfig().buildings.buildings)
{ {
if (def.type == BuildingType::Shipyard) { constructionTime = def.constructionTimeSeconds; break; } if (def.type == BuildingType::Shipyard) { constructionTime = def.constructionTimeSeconds; break; }
} }
@@ -896,7 +896,7 @@ TEST_CASE("Blueprint placement: ship layout transfers to building after construc
sim.tick(); sim.tick();
} }
const Building* b = sim.buildings().findBuilding(id); const Building* b = sim.getBuildings().findBuilding(id);
REQUIRE(b != nullptr); REQUIRE(b != nullptr);
REQUIRE(b->shipLayout.has_value()); REQUIRE(b->shipLayout.has_value());
REQUIRE(b->shipLayout->placedModules.size() == 1); REQUIRE(b->shipLayout->placedModules.size() == 1);

View File

@@ -114,8 +114,8 @@ TEST_CASE("readBuildingConfig reads a queued construction site", "[copyconfig]")
const BuildingId id = const BuildingId id =
SimulationTestAccess::place(sim, BuildingType::Miner, QPoint(-2, 0), Rotation::East); SimulationTestAccess::place(sim, BuildingType::Miner, QPoint(-2, 0), Rotation::East);
REQUIRE(id != kInvalidBuildingId); REQUIRE(id != kInvalidBuildingId);
REQUIRE(sim.buildings().findBuilding(id) == nullptr); REQUIRE(sim.getBuildings().findBuilding(id) == nullptr);
REQUIRE(sim.buildings().findSite(id) != nullptr); REQUIRE(sim.getBuildings().findSite(id) != nullptr);
SimulationTestAccess::buildings(sim).setRecipe(id, "mine_iron_ore"); SimulationTestAccess::buildings(sim).setRecipe(id, "mine_iron_ore");

View File

@@ -140,7 +140,7 @@ TEST_CASE("BuildingSystem: place rejects a building above the world (y < 0)", "[
// row sits above the world. // row sits above the world.
const BuildingId id = f.bs.place(BuildingType::Miner, QPoint(0, -1), Rotation::East, 0); const BuildingId id = f.bs.place(BuildingType::Miner, QPoint(0, -1), Rotation::East, 0);
REQUIRE(id == kInvalidBuildingId); REQUIRE(id == kInvalidBuildingId);
REQUIRE(f.bs.allSites().empty()); REQUIRE(f.bs.getAllSites().empty());
REQUIRE_FALSE(f.bs.isTileOccupied(QPoint(0, 0))); REQUIRE_FALSE(f.bs.isTileOccupied(QPoint(0, 0)));
} }
@@ -154,7 +154,7 @@ TEST_CASE("BuildingSystem: place rejects a building below the world (y >= height
const BuildingId id = f.bs.place(BuildingType::Miner, const BuildingId id = f.bs.place(BuildingType::Miner,
QPoint(0, heightTiles - 1), Rotation::East, 0); QPoint(0, heightTiles - 1), Rotation::East, 0);
REQUIRE(id == kInvalidBuildingId); REQUIRE(id == kInvalidBuildingId);
REQUIRE(f.bs.allSites().empty()); REQUIRE(f.bs.getAllSites().empty());
} }
TEST_CASE("BuildingSystem: place rejects a building left of the asteroid edge", "[building]") TEST_CASE("BuildingSystem: place rejects a building left of the asteroid edge", "[building]")
@@ -165,7 +165,7 @@ TEST_CASE("BuildingSystem: place rejects a building left of the asteroid edge",
const BuildingId id = f.bs.place(BuildingType::Miner, const BuildingId id = f.bs.place(BuildingType::Miner,
QPoint(leftEdgeX - 1, 0), Rotation::East, 0); QPoint(leftEdgeX - 1, 0), Rotation::East, 0);
REQUIRE(id == kInvalidBuildingId); REQUIRE(id == kInvalidBuildingId);
REQUIRE(f.bs.allSites().empty()); REQUIRE(f.bs.getAllSites().empty());
} }
TEST_CASE("BuildingSystem: place accepts a building flush against the world's left edge", TEST_CASE("BuildingSystem: place accepts a building flush against the world's left edge",
@@ -237,9 +237,9 @@ TEST_CASE("BuildingSystem: placing a belt registers it with BeltSystem after con
runTicks(bs, belts, static_cast<int>(secondsToTicks(1.0)) + 1, tick); runTicks(bs, belts, static_cast<int>(secondsToTicks(1.0)) + 1, tick);
REQUIRE(belts.tryPutItem(QPoint(5, 5), makeItem("iron_ore"), Rotation::East)); REQUIRE(belts.tryPutItem(QPoint(5, 5), makeItem("iron_ore"), Rotation::East));
REQUIRE(bs.allBuildings().size() == 1); REQUIRE(bs.getAllBuildings().size() == 1);
REQUIRE(bs.allBuildings()[0].type == BuildingType::Belt); REQUIRE(bs.getAllBuildings()[0].type == BuildingType::Belt);
REQUIRE(bs.allBuildings()[0].anchor == QPoint(5, 5)); REQUIRE(bs.getAllBuildings()[0].anchor == QPoint(5, 5));
} }
TEST_CASE("BuildingSystem: placed building enters construction queue", "[building]") TEST_CASE("BuildingSystem: placed building enters construction queue", "[building]")
@@ -258,8 +258,8 @@ TEST_CASE("BuildingSystem: placed building enters construction queue", "[buildin
const BuildingId 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.getAllSites().size() == 1);
REQUIRE(bs.allBuildings().empty()); REQUIRE(bs.getAllBuildings().empty());
REQUIRE(bs.findSite(id) != nullptr); REQUIRE(bs.findSite(id) != nullptr);
} }
@@ -289,7 +289,7 @@ TEST_CASE("BuildingSystem: demolish frees tiles and returns refund", "[building]
// Miner cost = 15, refund = floor(15 * 75 / 100) = 11. // Miner cost = 15, refund = floor(15 * 75 / 100) = 11.
REQUIRE(refund == 15 * cfg.world.refundPercentage / 100); REQUIRE(refund == 15 * cfg.world.refundPercentage / 100);
REQUIRE_FALSE(bs.isTileOccupied(QPoint(0, 0))); REQUIRE_FALSE(bs.isTileOccupied(QPoint(0, 0)));
REQUIRE(bs.allSites().empty()); REQUIRE(bs.getAllSites().empty());
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -312,7 +312,7 @@ TEST_CASE("BuildingSystem: first queued building starts construction immediately
rng); rng);
bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0); bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
REQUIRE(bs.allSites().front().completesAt > 0); REQUIRE(bs.getAllSites().front().completesAt > 0);
} }
TEST_CASE("BuildingSystem: second queued building waits (completesAt == 0)", "[building]") TEST_CASE("BuildingSystem: second queued building waits (completesAt == 0)", "[building]")
@@ -332,9 +332,9 @@ TEST_CASE("BuildingSystem: second queued building waits (completesAt == 0)", "[b
bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0); bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0);
bs.place(BuildingType::Miner, QPoint(5, 5), Rotation::East, 0); bs.place(BuildingType::Miner, QPoint(5, 5), Rotation::East, 0);
REQUIRE(bs.allSites().size() == 2); REQUIRE(bs.getAllSites().size() == 2);
REQUIRE(bs.allSites()[0].completesAt > 0); REQUIRE(bs.getAllSites()[0].completesAt > 0);
REQUIRE(bs.allSites()[1].completesAt == 0); REQUIRE(bs.getAllSites()[1].completesAt == 0);
} }
TEST_CASE("BuildingSystem: construction completes after configured duration", "[building]") TEST_CASE("BuildingSystem: construction completes after configured duration", "[building]")
@@ -358,7 +358,7 @@ TEST_CASE("BuildingSystem: construction completes after configured duration", "[
Tick tick = 0; Tick tick = 0;
runTicks(bs, belts, static_cast<int>(secondsToTicks(10.0)) + 1, tick); runTicks(bs, belts, static_cast<int>(secondsToTicks(10.0)) + 1, tick);
REQUIRE(bs.allSites().empty()); REQUIRE(bs.getAllSites().empty());
REQUIRE(bs.findBuilding(id) != nullptr); REQUIRE(bs.findBuilding(id) != nullptr);
} }
@@ -383,9 +383,9 @@ TEST_CASE("BuildingSystem: second building starts after first completes", "[buil
Tick tick = 0; Tick tick = 0;
runTicks(bs, belts, static_cast<int>(secondsToTicks(10.0)) + 1, tick); runTicks(bs, belts, static_cast<int>(secondsToTicks(10.0)) + 1, tick);
REQUIRE(bs.allSites().size() == 1); REQUIRE(bs.getAllSites().size() == 1);
REQUIRE(bs.allSites().front().id == id2); REQUIRE(bs.getAllSites().front().id == id2);
REQUIRE(bs.allSites().front().completesAt > 0); REQUIRE(bs.getAllSites().front().completesAt > 0);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -457,7 +457,7 @@ TEST_CASE("BuildingSystem: miner output buffer stalls when full", "[building]")
REQUIRE(b != nullptr); REQUIRE(b != nullptr);
// Both produced items are held on the output side (buffer + emerging lane), // Both produced items are held on the output side (buffer + emerging lane),
// which is what the capacity rule counts (REQ-MAT-OUTPUT-EMERGE). // which is what the capacity rule counts (REQ-MAT-OUTPUT-EMERGE).
REQUIRE(b->outputItemCount() == 2); REQUIRE(b->getOutputItemCount() == 2);
REQUIRE_FALSE(b->production.has_value()); REQUIRE_FALSE(b->production.has_value());
} }
@@ -485,23 +485,23 @@ TEST_CASE("BuildingSystem: productionBuildingCount excludes construction sites",
Tick tick = 0; Tick tick = 0;
// Both still under construction. // Both still under construction.
REQUIRE(bs.productionBuildingCount() == 0); REQUIRE(bs.getProductionBuildingCount() == 0);
// The queue builds one at a time: miner (10s) completes at tick 300, then // The queue builds one at a time: miner (10s) completes at tick 300, then
// the smelter (15s) starts and completes at tick 300 + 450 = 750. // the smelter (15s) starts and completes at tick 300 + 450 = 750.
runTicks(bs, belts, static_cast<int>(secondsToTicks(10.0)) + 1, tick); runTicks(bs, belts, static_cast<int>(secondsToTicks(10.0)) + 1, tick);
REQUIRE(bs.productionBuildingCount() == 1); REQUIRE(bs.getProductionBuildingCount() == 1);
runTicks(bs, belts, static_cast<int>(secondsToTicks(15.0)), tick); runTicks(bs, belts, static_cast<int>(secondsToTicks(15.0)), tick);
REQUIRE(bs.productionBuildingCount() == 2); REQUIRE(bs.getProductionBuildingCount() == 2);
// Neither is producing yet: the miner has no recipe selected, and the // Neither is producing yet: the miner has no recipe selected, and the
// smelter (auto-recipe, REQ-BLD-SMELTER) has no input feeding it. // smelter (auto-recipe, REQ-BLD-SMELTER) has no input feeding it.
REQUIRE(bs.activeProductionBuildingCount() == 0); REQUIRE(bs.getActiveProductionBuildingCount() == 0);
bs.setRecipe(minerId, "mine_iron_ore"); bs.setRecipe(minerId, "mine_iron_ore");
runTicks(bs, belts, 1, tick); runTicks(bs, belts, 1, tick);
REQUIRE(bs.activeProductionBuildingCount() == 1); REQUIRE(bs.getActiveProductionBuildingCount() == 1);
} }
TEST_CASE("BuildingSystem: activeProductionBuildingCount tracks production cycle state", TEST_CASE("BuildingSystem: activeProductionBuildingCount tracks production cycle state",
@@ -524,11 +524,11 @@ TEST_CASE("BuildingSystem: activeProductionBuildingCount tracks production cycle
Tick tick = 0; Tick tick = 0;
// Not yet operational while under construction. // Not yet operational while under construction.
REQUIRE(bs.activeProductionBuildingCount() == 0); REQUIRE(bs.getActiveProductionBuildingCount() == 0);
// Construction completes at tick 300; cycle 1 starts the same tick (completesAt=330). // Construction completes at tick 300; cycle 1 starts the same tick (completesAt=330).
runTicks(bs, belts, static_cast<int>(secondsToTicks(10.0)) + 1, tick); runTicks(bs, belts, static_cast<int>(secondsToTicks(10.0)) + 1, tick);
REQUIRE(bs.activeProductionBuildingCount() == 1); REQUIRE(bs.getActiveProductionBuildingCount() == 1);
// Run cycles 1 and 2 to completion (1s each); cycle 3 stalls once the // Run cycles 1 and 2 to completion (1s each); cycle 3 stalls once the
// output buffer (capacity 2) is full (REQ-MAT-OUTPUT-BUFFER). // output buffer (capacity 2) is full (REQ-MAT-OUTPUT-BUFFER).
@@ -536,9 +536,9 @@ TEST_CASE("BuildingSystem: activeProductionBuildingCount tracks production cycle
const Building* b = bs.findBuilding(id); const Building* b = bs.findBuilding(id);
REQUIRE(b != nullptr); REQUIRE(b != nullptr);
REQUIRE(b->outputItemCount() == 2); REQUIRE(b->getOutputItemCount() == 2);
REQUIRE_FALSE(b->production.has_value()); REQUIRE_FALSE(b->production.has_value());
REQUIRE(bs.activeProductionBuildingCount() == 0); REQUIRE(bs.getActiveProductionBuildingCount() == 0);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -882,7 +882,7 @@ TEST_CASE("BuildingSystem: direct coupling to a non-consumer leaves the item stu
REQUIRE(sink != nullptr); REQUIRE(sink != nullptr);
// Nothing was delivered, and the producer's output side has backed up to its cap. // Nothing was delivered, and the producer's output side has backed up to its cap.
REQUIRE(sink->pendingInputCount(ItemType{"iron_ore"}) == 0); REQUIRE(sink->pendingInputCount(ItemType{"iron_ore"}) == 0);
REQUIRE(miner->outputItemCount() == miner->outputBuffer.capacity); REQUIRE(miner->getOutputItemCount() == miner->outputBuffer.capacity);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -916,7 +916,7 @@ TEST_CASE("BuildingSystem: setRecipe clears output buffer and active production"
{ {
const Building* b = bs.findBuilding(id); const Building* b = bs.findBuilding(id);
REQUIRE(b != nullptr); REQUIRE(b != nullptr);
REQUIRE(b->outputItemCount() > 0); REQUIRE(b->getOutputItemCount() > 0);
} }
bs.setRecipe(id, "mine_copper_ore"); bs.setRecipe(id, "mine_copper_ore");
@@ -924,7 +924,7 @@ TEST_CASE("BuildingSystem: setRecipe clears output buffer and active production"
const Building* b = bs.findBuilding(id); const Building* b = bs.findBuilding(id);
// Clearing the output buffer on a recipe change also discards emerging items // Clearing the output buffer on a recipe change also discards emerging items
// (REQ-MAT-OUTPUT-EMERGE). // (REQ-MAT-OUTPUT-EMERGE).
REQUIRE(b->outputItemCount() == 0); REQUIRE(b->getOutputItemCount() == 0);
REQUIRE_FALSE(b->production.has_value()); REQUIRE_FALSE(b->production.has_value());
} }
@@ -1083,7 +1083,7 @@ TEST_CASE("BuildingSystem: findRotateInPlaceTarget returns the building id for a
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.getAllSites().empty());
const std::optional<BuildingId> result = const std::optional<BuildingId> result =
bs.findRotateInPlaceTarget(BuildingType::Belt, QPoint(0, 0), Rotation::South); bs.findRotateInPlaceTarget(BuildingType::Belt, QPoint(0, 0), Rotation::South);
@@ -1295,12 +1295,12 @@ TEST_CASE("BuildingSystem: splitter filters configured on a construction site ca
// Run until construction completes. // Run until construction completes.
Tick tick = 0; Tick tick = 0;
while (f.bs.allBuildings().empty() && tick < 100000) while (f.bs.getAllBuildings().empty() && tick < 100000)
{ {
runTicks(f.bs, f.belts, 1, tick); runTicks(f.bs, f.belts, 1, tick);
} }
REQUIRE(f.bs.allBuildings().size() == 1); REQUIRE(f.bs.getAllBuildings().size() == 1);
REQUIRE(f.bs.allBuildings()[0].type == BuildingType::Splitter); REQUIRE(f.bs.getAllBuildings()[0].type == BuildingType::Splitter);
// The built splitter is registered with BeltSystem carrying the filters. // The built splitter is registered with BeltSystem carrying the filters.
const std::optional<BeltSystem::SplitterInfo> builtInfo = f.belts.getSplitterInfo(tile); const std::optional<BeltSystem::SplitterInfo> builtInfo = f.belts.getSplitterInfo(tile);

View File

@@ -183,7 +183,7 @@ TEST_CASE("CombatSystem: player station fires at enemy ship in range", "[combat]
// Find the player station entity via ECS. // Find the player station entity via ECS.
entt::entity stationEntity = entt::null; entt::entity stationEntity = entt::null;
QVector2D stationCenter; QVector2D stationCenter;
sim.admin().forEach<StationBodyComponent, FactionComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent>(
[&](entt::entity e, const StationBodyComponent& sb, const FactionComponent& f) [&](entt::entity e, const StationBodyComponent& sb, const FactionComponent& f)
{ {
if (!f.isEnemy && stationEntity == entt::null) if (!f.isEnemy && stationEntity == entt::null)
@@ -194,12 +194,12 @@ TEST_CASE("CombatSystem: player station fires at enemy ship in range", "[combat]
sb.anchor.y() + sb.footprint.height() / 2.0f); sb.anchor.y() + sb.footprint.height() / 2.0f);
} }
}); });
REQUIRE(sim.admin().isValid(stationEntity)); REQUIRE(sim.getAdmin().isValid(stationEntity));
const ShipDef* combatDef = findCombatShip(sim.config()); const ShipDef* combatDef = findCombatShip(sim.getConfig());
REQUIRE(combatDef != nullptr); REQUIRE(combatDef != nullptr);
const entt::entity enemyShip = sim.ships().spawn( const entt::entity enemyShip = sim.getShips().spawn(
combatDef->id, combatDef->id,
QVector2D(stationCenter.x() + 1.0f, stationCenter.y()), QVector2D(stationCenter.x() + 1.0f, stationCenter.y()),
/*isEnemy=*/true); /*isEnemy=*/true);
@@ -221,7 +221,7 @@ TEST_CASE("CombatSystem: enemy station fires at player ship in range", "[combat]
entt::entity stationEntity = entt::null; entt::entity stationEntity = entt::null;
QVector2D stationCenter; QVector2D stationCenter;
sim.admin().forEach<StationBodyComponent, FactionComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent>(
[&](entt::entity e, const StationBodyComponent& sb, const FactionComponent& f) [&](entt::entity e, const StationBodyComponent& sb, const FactionComponent& f)
{ {
if (f.isEnemy && stationEntity == entt::null) if (f.isEnemy && stationEntity == entt::null)
@@ -232,12 +232,12 @@ TEST_CASE("CombatSystem: enemy station fires at player ship in range", "[combat]
sb.anchor.y() + sb.footprint.height() / 2.0f); sb.anchor.y() + sb.footprint.height() / 2.0f);
} }
}); });
REQUIRE(sim.admin().isValid(stationEntity)); REQUIRE(sim.getAdmin().isValid(stationEntity));
const ShipDef* combatDef = findCombatShip(sim.config()); const ShipDef* combatDef = findCombatShip(sim.getConfig());
REQUIRE(combatDef != nullptr); REQUIRE(combatDef != nullptr);
sim.ships().spawn( sim.getShips().spawn(
combatDef->id, combatDef->id,
QVector2D(stationCenter.x() - 1.0f, stationCenter.y()), QVector2D(stationCenter.x() - 1.0f, stationCenter.y()),
/*isEnemy=*/false); /*isEnemy=*/false);
@@ -259,7 +259,7 @@ TEST_CASE("CombatSystem: player ship fires at enemy station in range", "[combat]
entt::entity stationEntity = entt::null; entt::entity stationEntity = entt::null;
QVector2D stationCenter; QVector2D stationCenter;
sim.admin().forEach<StationBodyComponent, FactionComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent>(
[&](entt::entity e, const StationBodyComponent& sb, const FactionComponent& f) [&](entt::entity e, const StationBodyComponent& sb, const FactionComponent& f)
{ {
if (f.isEnemy && stationEntity == entt::null) if (f.isEnemy && stationEntity == entt::null)
@@ -270,12 +270,12 @@ TEST_CASE("CombatSystem: player ship fires at enemy station in range", "[combat]
sb.anchor.y() + sb.footprint.height() / 2.0f); sb.anchor.y() + sb.footprint.height() / 2.0f);
} }
}); });
REQUIRE(sim.admin().isValid(stationEntity)); REQUIRE(sim.getAdmin().isValid(stationEntity));
const ShipDef* combatDef = findCombatShip(sim.config()); const ShipDef* combatDef = findCombatShip(sim.getConfig());
REQUIRE(combatDef != nullptr); REQUIRE(combatDef != nullptr);
const entt::entity playerShip = sim.ships().spawn( const entt::entity playerShip = sim.getShips().spawn(
combatDef->id, combatDef->id,
QVector2D(stationCenter.x() - 1.0f, stationCenter.y()), QVector2D(stationCenter.x() - 1.0f, stationCenter.y()),
/*isEnemy=*/false); /*isEnemy=*/false);
@@ -390,17 +390,17 @@ TEST_CASE("CombatSystem: dead ship is removed after tick step 9", "[combat]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* combatDef = findCombatShip(sim.config()); const ShipDef* combatDef = findCombatShip(sim.getConfig());
REQUIRE(combatDef != nullptr); REQUIRE(combatDef != nullptr);
const entt::entity ship = sim.ships().spawn(combatDef->id, const entt::entity ship = sim.getShips().spawn(combatDef->id,
QVector2D(10.0f, 10.0f)); QVector2D(10.0f, 10.0f));
sim.admin().get<HealthComponent>(ship).hp = -1.0f; sim.getAdmin().get<HealthComponent>(ship).hp = -1.0f;
sim.tick(); sim.tick();
REQUIRE_FALSE(sim.admin().isValid(ship)); REQUIRE_FALSE(sim.getAdmin().isValid(ship));
} }
TEST_CASE("CombatSystem: scrap is spawned on ship death", "[combat]") TEST_CASE("CombatSystem: scrap is spawned on ship death", "[combat]")
@@ -411,15 +411,15 @@ TEST_CASE("CombatSystem: scrap is spawned on ship death", "[combat]")
// (REQ-RES-SCRAP-DROP): round(threat * scrap_per_threat). The interceptor's // (REQ-RES-SCRAP-DROP): round(threat * scrap_per_threat). The interceptor's
// threat is 59.0 and the test config sets scrap_per_threat = 1.0, so it drops // threat is 59.0 and the test config sets scrap_per_threat = 1.0, so it drops
// round(59.0 * 1.0) = 59 scrap. // round(59.0 * 1.0) = 59 scrap.
const entt::entity ship = sim.ships().spawn("interceptor", const entt::entity ship = sim.getShips().spawn("interceptor",
QVector2D(10.0f, 10.0f)); QVector2D(10.0f, 10.0f));
sim.admin().get<HealthComponent>(ship).hp = -1.0f; sim.getAdmin().get<HealthComponent>(ship).hp = -1.0f;
sim.tick(); sim.tick();
const std::vector<ScrapInfo> scraps = sim.scraps().allScrapInfo(); const std::vector<ScrapInfo> scraps = sim.getScraps().getAllScrapInfo();
REQUIRE(scraps.size() == 1); REQUIRE(scraps.size() == 1);
CHECK(sim.admin().get<ScrapDataComponent>(scraps[0].entity).amount == 59); CHECK(sim.getAdmin().get<ScrapDataComponent>(scraps[0].entity).amount == 59);
} }
TEST_CASE("CombatSystem: HQ death sets game over", "[combat]") TEST_CASE("CombatSystem: HQ death sets game over", "[combat]")
@@ -427,7 +427,7 @@ TEST_CASE("CombatSystem: HQ death sets game over", "[combat]")
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
// Damage the HQ proxy entity (has HqProxy + Health). // Damage the HQ proxy entity (has HqProxy + Health).
sim.admin().forEach<HqProxyComponent, HealthComponent>( sim.getAdmin().forEach<HqProxyComponent, HealthComponent>(
[](entt::entity /*e*/, const HqProxyComponent& /*hq*/, HealthComponent& h) [](entt::entity /*e*/, const HqProxyComponent& /*hq*/, HealthComponent& h)
{ {
h.hp = -1.0f; h.hp = -1.0f;

View File

@@ -67,7 +67,7 @@ TEST_CASE("Hasher: identical inputs produce identical values", "[determinism]")
b.append(3.5f); b.append(3.5f);
b.append(std::string("ore")); b.append(std::string("ore"));
REQUIRE(a.value() == b.value()); REQUIRE(a.getValue() == b.getValue());
} }
TEST_CASE("Hasher: differing inputs produce differing values", "[determinism]") TEST_CASE("Hasher: differing inputs produce differing values", "[determinism]")
@@ -77,7 +77,7 @@ TEST_CASE("Hasher: differing inputs produce differing values", "[determinism]")
a.append(42); a.append(42);
b.append(43); b.append(43);
REQUIRE(a.value() != b.value()); REQUIRE(a.getValue() != b.getValue());
} }
TEST_CASE("Hasher: string concatenation does not collide", "[determinism]") TEST_CASE("Hasher: string concatenation does not collide", "[determinism]")
@@ -89,7 +89,7 @@ TEST_CASE("Hasher: string concatenation does not collide", "[determinism]")
b.append(std::string("a")); b.append(std::string("a"));
b.append(std::string("bc")); b.append(std::string("bc"));
REQUIRE(a.value() != b.value()); REQUIRE(a.getValue() != b.getValue());
} }
TEST_CASE("Hasher: negative and positive zero hash equally", "[determinism]") TEST_CASE("Hasher: negative and positive zero hash equally", "[determinism]")
@@ -99,7 +99,7 @@ TEST_CASE("Hasher: negative and positive zero hash equally", "[determinism]")
a.append(-0.0f); a.append(-0.0f);
b.append(0.0f); b.append(0.0f);
REQUIRE(a.value() == b.value()); REQUIRE(a.getValue() == b.getValue());
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -124,7 +124,7 @@ TEST_CASE("Simulation::rngFingerprint is stable for equal seeds", "[determinism]
const Simulation a(loadConfig(), 777); const Simulation a(loadConfig(), 777);
const Simulation b(loadConfig(), 777); const Simulation b(loadConfig(), 777);
REQUIRE(a.rngFingerprint() == b.rngFingerprint()); REQUIRE(a.getRngFingerprint() == b.getRngFingerprint());
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@@ -37,7 +37,7 @@ TEST_CASE("Formula retains its source string", "[formula]")
const std::string source = "10 + x / 5"; const std::string source = "10 + x / 5";
const Formula f = Formula::compile(source); const Formula f = Formula::compile(source);
REQUIRE(f.source() == source); REQUIRE(f.getSource() == source);
} }
TEST_CASE("Formula throws on malformed source", "[formula]") TEST_CASE("Formula throws on malformed source", "[formula]")

View File

@@ -22,7 +22,7 @@ static GameConfig loadConfig()
// tickDeathsAndLoot fires, triggering the push and schematic choices. // tickDeathsAndLoot fires, triggering the push and schematic choices.
static void killEnemyStations(Simulation& sim) static void killEnemyStations(Simulation& sim)
{ {
sim.admin().forEach<StationBodyComponent, FactionComponent, HealthComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent, HealthComponent>(
[](entt::entity, StationBodyComponent&, FactionComponent& faction, HealthComponent& health) [](entt::entity, StationBodyComponent&, FactionComponent& faction, HealthComponent& health)
{ {
if (faction.isEnemy) if (faction.isEnemy)

View File

@@ -166,7 +166,7 @@ TEST_CASE("a recorded run replays to byte-identical state with no desync", "[rep
manager.drain(); manager.drain();
for (int i = 0; i < 60; ++i) { rec.tick(); manager.recordTickCheckpoint(); } for (int i = 0; i < 60; ++i) { rec.tick(); manager.recordTickCheckpoint(); }
replayPath = recorderPtr->currentFilePath(); replayPath = recorderPtr->getCurrentFilePath();
recordedFinalChecksum = rec.computeStateChecksum(); recordedFinalChecksum = rec.computeStateChecksum();
manager.setRecorder(nullptr); // close the file manager.setRecorder(nullptr); // close the file
} }
@@ -185,11 +185,11 @@ TEST_CASE("a recorded run replays to byte-identical state with no desync", "[rep
while (!player.isFinished()) while (!player.isFinished())
{ {
play.tick(); play.tick();
player.advanceTo(play.currentTick()); player.advanceTo(play.getCurrentTick());
} }
REQUIRE_FALSE(player.getDesyncTick().has_value()); REQUIRE_FALSE(player.getDesyncTick().has_value());
REQUIRE(play.currentTick() == 150); REQUIRE(play.getCurrentTick() == 150);
REQUIRE(play.computeStateChecksum() == recordedFinalChecksum); REQUIRE(play.computeStateChecksum() == recordedFinalChecksum);
QFile::remove(QString::fromStdString(replayPath)); QFile::remove(QString::fromStdString(replayPath));
@@ -208,7 +208,7 @@ TEST_CASE("ReplayPlayer reports a desync when a checksum is corrupted", "[replay
ReplayRecorder* recorderPtr = recorder.get(); ReplayRecorder* recorderPtr = recorder.get();
manager.setRecorder(std::move(recorder)); manager.setRecorder(std::move(recorder));
for (int i = 0; i < 60; ++i) { rec.tick(); manager.recordTickCheckpoint(); } for (int i = 0; i < 60; ++i) { rec.tick(); manager.recordTickCheckpoint(); }
replayPath = recorderPtr->currentFilePath(); replayPath = recorderPtr->getCurrentFilePath();
manager.setRecorder(nullptr); manager.setRecorder(nullptr);
} }
@@ -234,7 +234,7 @@ TEST_CASE("ReplayPlayer reports a desync when a checksum is corrupted", "[replay
while (!player.isFinished()) while (!player.isFinished())
{ {
play.tick(); play.tick();
player.advanceTo(play.currentTick()); player.advanceTo(play.getCurrentTick());
} }
REQUIRE(player.getDesyncTick().has_value()); REQUIRE(player.getDesyncTick().has_value());
@@ -267,7 +267,7 @@ TEST_CASE("a long recorded run (through waves and combat) replays with no desync
manager.drain(); manager.drain();
for (int i = 0; i < 900; ++i) { rec.tick(); manager.recordTickCheckpoint(); } for (int i = 0; i < 900; ++i) { rec.tick(); manager.recordTickCheckpoint(); }
replayPath = recorderPtr->currentFilePath(); replayPath = recorderPtr->getCurrentFilePath();
recordedFinalChecksum = rec.computeStateChecksum(); recordedFinalChecksum = rec.computeStateChecksum();
manager.setRecorder(nullptr); manager.setRecorder(nullptr);
} }
@@ -281,11 +281,11 @@ TEST_CASE("a long recorded run (through waves and combat) replays with no desync
while (!player.isFinished()) while (!player.isFinished())
{ {
play.tick(); play.tick();
player.advanceTo(play.currentTick()); player.advanceTo(play.getCurrentTick());
} }
REQUIRE_FALSE(player.getDesyncTick().has_value()); REQUIRE_FALSE(player.getDesyncTick().has_value());
REQUIRE(play.currentTick() == 2400); REQUIRE(play.getCurrentTick() == 2400);
REQUIRE(play.computeStateChecksum() == recordedFinalChecksum); REQUIRE(play.computeStateChecksum() == recordedFinalChecksum);
QFile::remove(QString::fromStdString(replayPath)); QFile::remove(QString::fromStdString(replayPath));

View File

@@ -120,7 +120,7 @@ TEST_CASE("ReplayRecorder writes a well-formed file", "[replay]")
recorder.recordChecksum(30, 0x0ffffffffffffff0ull); recorder.recordChecksum(30, 0x0ffffffffffffff0ull);
const std::string path = recorder.currentFilePath(); const std::string path = recorder.getCurrentFilePath();
REQUIRE_FALSE(path.empty()); REQUIRE_FALSE(path.empty());
recorder.close(); recorder.close();
@@ -152,7 +152,7 @@ TEST_CASE("CommandManager records commands and an initial checksum on drain", "[
ReplayRecorder* recorderPtr = recorder.get(); ReplayRecorder* recorderPtr = recorder.get();
// setRecorder opens the file and writes the header + the tick-0 checksum. // setRecorder opens the file and writes the header + the tick-0 checksum.
manager.setRecorder(std::move(recorder)); manager.setRecorder(std::move(recorder));
const std::string path = recorderPtr->currentFilePath(); const std::string path = recorderPtr->getCurrentFilePath();
REQUIRE_FALSE(path.empty()); REQUIRE_FALSE(path.empty());
std::shared_ptr<PlaceBuildingCommand> place = std::make_shared<PlaceBuildingCommand>(); std::shared_ptr<PlaceBuildingCommand> place = std::make_shared<PlaceBuildingCommand>();
@@ -175,10 +175,10 @@ TEST_CASE("ReplayRecorder startNewRun rolls to a new file", "[replay]")
ReplayRecorder recorder(CONFIG_DIR, tempOutputDir()); ReplayRecorder recorder(CONFIG_DIR, tempOutputDir());
recorder.startNewRun(1u, 0ull); recorder.startNewRun(1u, 0ull);
const std::string first = recorder.currentFilePath(); const std::string first = recorder.getCurrentFilePath();
recorder.startNewRun(2u, 0ull); recorder.startNewRun(2u, 0ull);
const std::string second = recorder.currentFilePath(); const std::string second = recorder.getCurrentFilePath();
REQUIRE(first != second); REQUIRE(first != second);
REQUIRE(second.find("_2.replay") != std::string::npos); REQUIRE(second.find("_2.replay") != std::string::npos);
@@ -194,7 +194,7 @@ TEST_CASE("CommandManager rolls the replay file on a Reset command", "[replay]")
std::make_unique<ReplayRecorder>(CONFIG_DIR, tempOutputDir()); std::make_unique<ReplayRecorder>(CONFIG_DIR, tempOutputDir());
ReplayRecorder* recorderPtr = recorder.get(); ReplayRecorder* recorderPtr = recorder.get();
manager.setRecorder(std::move(recorder)); manager.setRecorder(std::move(recorder));
const std::string firstPath = recorderPtr->currentFilePath(); const std::string firstPath = recorderPtr->getCurrentFilePath();
std::shared_ptr<ResetCommand> reset = std::make_shared<ResetCommand>(); std::shared_ptr<ResetCommand> reset = std::make_shared<ResetCommand>();
reset->config = std::make_shared<GameConfig>(ConfigLoader::loadFromDirectory(CONFIG_DIR)); reset->config = std::make_shared<GameConfig>(ConfigLoader::loadFromDirectory(CONFIG_DIR));
@@ -202,7 +202,7 @@ TEST_CASE("CommandManager rolls the replay file on a Reset command", "[replay]")
manager.enqueue(reset); manager.enqueue(reset);
manager.drain(); manager.drain();
const std::string secondPath = recorderPtr->currentFilePath(); const std::string secondPath = recorderPtr->getCurrentFilePath();
REQUIRE(firstPath != secondPath); REQUIRE(firstPath != secondPath);
REQUIRE(secondPath.find("_999.replay") != std::string::npos); REQUIRE(secondPath.find("_999.replay") != std::string::npos);

View File

@@ -148,7 +148,7 @@ TEST_CASE("ScrapSystem: allScrapInfo returns all spawned scrap", "[scrap]")
ss.spawn(QVector2D(1.0f, 2.0f), 3, 100); ss.spawn(QVector2D(1.0f, 2.0f), 3, 100);
ss.spawn(QVector2D(4.0f, 5.0f), 6, 200); ss.spawn(QVector2D(4.0f, 5.0f), 6, 200);
const std::vector<ScrapInfo> info = ss.allScrapInfo(); const std::vector<ScrapInfo> info = ss.getAllScrapInfo();
REQUIRE(info.size() == 2); REQUIRE(info.size() == 2);
} }
@@ -160,7 +160,7 @@ TEST_CASE("ScrapSystem: allScrapInfo reports each pile's remaining amount", "[sc
const entt::entity a = ss.spawn(QVector2D(1.0f, 2.0f), 3, 100); const entt::entity a = ss.spawn(QVector2D(1.0f, 2.0f), 3, 100);
const entt::entity b = ss.spawn(QVector2D(4.0f, 5.0f), 6, 200); const entt::entity b = ss.spawn(QVector2D(4.0f, 5.0f), 6, 200);
const std::vector<ScrapInfo> info = ss.allScrapInfo(); const std::vector<ScrapInfo> info = ss.getAllScrapInfo();
REQUIRE(info.size() == 2); REQUIRE(info.size() == 2);
for (const ScrapInfo& i : info) for (const ScrapInfo& i : info)
{ {

View File

@@ -87,7 +87,7 @@ static void fillMaterials(Simulation& sim, BuildingId yardId,
} }
for (const PlacedModule& pm : layout.placedModules) for (const PlacedModule& pm : layout.placedModules)
{ {
for (const ModuleDef& modDef : sim.config().modules.modules) for (const ModuleDef& modDef : sim.getConfig().modules.modules)
{ {
if (modDef.id == pm.moduleId) if (modDef.id == pm.moduleId)
{ {
@@ -109,22 +109,22 @@ static void fillMaterials(Simulation& sim, BuildingId yardId,
TEST_CASE("Ship spawn: no modules leaves base stats unchanged", "[modules]") TEST_CASE("Ship spawn: no modules leaves base stats unchanged", "[modules]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* def = findSchematic(sim.config(), "interceptor"); const ShipDef* def = findSchematic(sim.getConfig(), "interceptor");
REQUIRE(def != nullptr); REQUIRE(def != nullptr);
const float expectedHp = static_cast<float>(def->health.hp); const float expectedHp = static_cast<float>(def->health.hp);
const entt::entity e = sim.ships().spawn("interceptor", const entt::entity e = sim.getShips().spawn("interceptor",
QVector2D(5.0f, 5.0f), false, std::nullopt); QVector2D(5.0f, 5.0f), false, std::nullopt);
REQUIRE(sim.admin().isValid(e)); REQUIRE(sim.getAdmin().isValid(e));
CHECK(sim.admin().get<HealthComponent>(e).maxHp == Approx(expectedHp)); CHECK(sim.getAdmin().get<HealthComponent>(e).maxHp == Approx(expectedHp));
} }
TEST_CASE("Ship spawn: multiplicative HP module applies correctly", "[modules]") TEST_CASE("Ship spawn: multiplicative HP module applies correctly", "[modules]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* def = findSchematic(sim.config(), "interceptor"); const ShipDef* def = findSchematic(sim.getConfig(), "interceptor");
REQUIRE(def != nullptr); REQUIRE(def != nullptr);
const float baseHp = static_cast<float>(def->health.hp); const float baseHp = static_cast<float>(def->health.hp);
@@ -136,23 +136,23 @@ TEST_CASE("Ship spawn: multiplicative HP module applies correctly", "[modules]")
pm.rotation = Rotation::East; pm.rotation = Rotation::East;
layout.placedModules.push_back(pm); layout.placedModules.push_back(pm);
const entt::entity e = sim.ships().spawn("interceptor", const entt::entity e = sim.getShips().spawn("interceptor",
QVector2D(5.0f, 5.0f), false, layout); QVector2D(5.0f, 5.0f), false, layout);
REQUIRE(sim.admin().isValid(e)); REQUIRE(sim.getAdmin().isValid(e));
// armor_plate has multiplied_hp_formula = "1.5" // armor_plate has multiplied_hp_formula = "1.5"
// final = base * (1 + (1.5 - 1)) + 0 = base * 1.5 // final = base * (1 + (1.5 - 1)) + 0 = base * 1.5
CHECK(sim.admin().get<HealthComponent>(e).maxHp == Approx(baseHp * 1.5f)); CHECK(sim.getAdmin().get<HealthComponent>(e).maxHp == Approx(baseHp * 1.5f));
CHECK(sim.admin().get<HealthComponent>(e).hp == sim.admin().get<HealthComponent>(e).maxHp); CHECK(sim.getAdmin().get<HealthComponent>(e).hp == sim.getAdmin().get<HealthComponent>(e).maxHp);
} }
TEST_CASE("Ship spawn: additive sensor module applies correctly", "[modules]") TEST_CASE("Ship spawn: additive sensor module applies correctly", "[modules]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* def = findSchematic(sim.config(), "interceptor"); const ShipDef* def = findSchematic(sim.getConfig(), "interceptor");
REQUIRE(def != nullptr); REQUIRE(def != nullptr);
const float tileSize = static_cast<float>(sim.config().world.tileSize_m); const float tileSize = static_cast<float>(sim.getConfig().world.tileSize_m);
const float baseRange_tiles = static_cast<float>(def->sensor.sensorRange_m) / tileSize; const float baseRange_tiles = static_cast<float>(def->sensor.sensorRange_m) / tileSize;
ShipLayoutConfig layout; ShipLayoutConfig layout;
@@ -162,19 +162,19 @@ TEST_CASE("Ship spawn: additive sensor module applies correctly", "[modules]")
pm.rotation = Rotation::East; pm.rotation = Rotation::East;
layout.placedModules.push_back(pm); layout.placedModules.push_back(pm);
const entt::entity e = sim.ships().spawn("interceptor", const entt::entity e = sim.getShips().spawn("interceptor",
QVector2D(5.0f, 5.0f), false, layout); QVector2D(5.0f, 5.0f), false, layout);
REQUIRE(sim.admin().isValid(e)); REQUIRE(sim.getAdmin().isValid(e));
// sensor_booster has added_sensor_range_m_formula = "100" m → 100/10 = 10 tiles // sensor_booster has added_sensor_range_m_formula = "100" m → 100/10 = 10 tiles
// final = baseRange_tiles * 1.0 + 10 = baseRange_tiles + 10 // final = baseRange_tiles * 1.0 + 10 = baseRange_tiles + 10
CHECK(sim.admin().get<SensorRangeComponent>(e).value_tiles == Approx(baseRange_tiles + 10.0f)); CHECK(sim.getAdmin().get<SensorRangeComponent>(e).value_tiles == Approx(baseRange_tiles + 10.0f));
} }
TEST_CASE("Ship spawn: multiple modules stack correctly", "[modules]") TEST_CASE("Ship spawn: multiple modules stack correctly", "[modules]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* def = findSchematic(sim.config(), "interceptor"); const ShipDef* def = findSchematic(sim.getConfig(), "interceptor");
REQUIRE(def != nullptr); REQUIRE(def != nullptr);
const float baseHp = static_cast<float>(def->health.hp); const float baseHp = static_cast<float>(def->health.hp);
@@ -189,14 +189,14 @@ TEST_CASE("Ship spawn: multiple modules stack correctly", "[modules]")
layout.placedModules.push_back(pm); layout.placedModules.push_back(pm);
} }
const entt::entity e = sim.ships().spawn("interceptor", const entt::entity e = sim.getShips().spawn("interceptor",
QVector2D(5.0f, 5.0f), false, layout); QVector2D(5.0f, 5.0f), false, layout);
REQUIRE(sim.admin().isValid(e)); REQUIRE(sim.getAdmin().isValid(e));
// Two armor_plates: each 1.5 multiplier // Two armor_plates: each 1.5 multiplier
// total_mult = 1 + (1.5 - 1) + (1.5 - 1) = 2.0 // total_mult = 1 + (1.5 - 1) + (1.5 - 1) = 2.0
// final = base * 2.0 // final = base * 2.0
CHECK(sim.admin().get<HealthComponent>(e).maxHp == Approx(baseHp * 2.0f)); CHECK(sim.getAdmin().get<HealthComponent>(e).maxHp == Approx(baseHp * 2.0f));
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -207,7 +207,7 @@ TEST_CASE("Shipyard: setShipLayout reinitializes buffers with module materials",
"[modules][shipyard]") "[modules][shipyard]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const BuildingDef* yardDef = findShipyardDef(sim.config()); const BuildingDef* yardDef = findShipyardDef(sim.getConfig());
REQUIRE(yardDef != nullptr); REQUIRE(yardDef != nullptr);
const BuildingId yardId = placeShipyard(sim, *yardDef); const BuildingId yardId = placeShipyard(sim, *yardDef);
@@ -222,7 +222,7 @@ TEST_CASE("Shipyard: setShipLayout reinitializes buffers with module materials",
SimulationTestAccess::buildings(sim).setShipLayout(yardId, layout); SimulationTestAccess::buildings(sim).setShipLayout(yardId, layout);
const Building* b = sim.buildings().findBuilding(yardId); const Building* b = sim.getBuildings().findBuilding(yardId);
REQUIRE(b != nullptr); REQUIRE(b != nullptr);
// armor_plate needs 2 iron_ingot; interceptor needs 3 iron_ingot + 1 circuit_board // armor_plate needs 2 iron_ingot; interceptor needs 3 iron_ingot + 1 circuit_board
// Total iron_ingot = 5, buffer cap = 2 * 5 = 10 // Total iron_ingot = 5, buffer cap = 2 * 5 = 10
@@ -234,9 +234,9 @@ TEST_CASE("Shipyard: setShipLayout cancels in-progress production",
"[modules][shipyard]") "[modules][shipyard]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* def = findSchematic(sim.config(), "interceptor"); const ShipDef* def = findSchematic(sim.getConfig(), "interceptor");
REQUIRE(def != nullptr); REQUIRE(def != nullptr);
const BuildingDef* yardDef = findShipyardDef(sim.config()); const BuildingDef* yardDef = findShipyardDef(sim.getConfig());
REQUIRE(yardDef != nullptr); REQUIRE(yardDef != nullptr);
const BuildingId yardId = placeShipyard(sim, *yardDef); const BuildingId yardId = placeShipyard(sim, *yardDef);
@@ -247,7 +247,7 @@ TEST_CASE("Shipyard: setShipLayout cancels in-progress production",
fillMaterials(sim, yardId, *def, emptyLayout); fillMaterials(sim, yardId, *def, emptyLayout);
sim.tick(); sim.tick();
const Building* b1 = sim.buildings().findBuilding(yardId); const Building* b1 = sim.getBuildings().findBuilding(yardId);
REQUIRE(b1 != nullptr); REQUIRE(b1 != nullptr);
REQUIRE(b1->production.has_value()); REQUIRE(b1->production.has_value());
@@ -261,7 +261,7 @@ TEST_CASE("Shipyard: setShipLayout cancels in-progress production",
SimulationTestAccess::buildings(sim).setShipLayout(yardId, layout); SimulationTestAccess::buildings(sim).setShipLayout(yardId, layout);
const Building* b2 = sim.buildings().findBuilding(yardId); const Building* b2 = sim.getBuildings().findBuilding(yardId);
REQUIRE(b2 != nullptr); REQUIRE(b2 != nullptr);
CHECK_FALSE(b2->production.has_value()); CHECK_FALSE(b2->production.has_value());
} }
@@ -270,7 +270,7 @@ TEST_CASE("Shipyard: builds a bare hull when no layout is configured",
"[modules][shipyard]") "[modules][shipyard]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* def = findSchematic(sim.config(), "interceptor"); const ShipDef* def = findSchematic(sim.getConfig(), "interceptor");
REQUIRE(def != nullptr); REQUIRE(def != nullptr);
// The schematic carries a weapon in its (wave-only) default loadout. This // The schematic carries a weapon in its (wave-only) default loadout. This
// test pins that a player shipyard with no configured layout does NOT hand // test pins that a player shipyard with no configured layout does NOT hand
@@ -278,7 +278,7 @@ TEST_CASE("Shipyard: builds a bare hull when no layout is configured",
// base-hull materials it was charged. // base-hull materials it was charged.
REQUIRE_FALSE(def->defaultModules.empty()); REQUIRE_FALSE(def->defaultModules.empty());
const BuildingDef* yardDef = findShipyardDef(sim.config()); const BuildingDef* yardDef = findShipyardDef(sim.getConfig());
REQUIRE(yardDef != nullptr); REQUIRE(yardDef != nullptr);
const BuildingId yardId = placeShipyard(sim, *yardDef); const BuildingId yardId = placeShipyard(sim, *yardDef);
@@ -297,23 +297,23 @@ TEST_CASE("Shipyard: builds a bare hull when no layout is configured",
// Locate the freshly built player ship. // Locate the freshly built player ship.
entt::entity built = entt::null; entt::entity built = entt::null;
sim.admin().forEach<ShipIdentityComponent, FactionComponent>( sim.getAdmin().forEach<ShipIdentityComponent, FactionComponent>(
[&](entt::entity e, const ShipIdentityComponent& si, const FactionComponent& fac) [&](entt::entity e, const ShipIdentityComponent& si, const FactionComponent& fac)
{ {
if (!fac.isEnemy && si.schematicId == "interceptor") { built = e; } if (!fac.isEnemy && si.schematicId == "interceptor") { built = e; }
}); });
REQUIRE(sim.admin().isValid(built)); REQUIRE(sim.getAdmin().isValid(built));
// Bare hull: the schematic's default weapon must NOT have been installed. // Bare hull: the schematic's default weapon must NOT have been installed.
const bool hasWeapon = const bool hasWeapon =
findFirstWeaponChild(sim.admin(), built) != entt::null; findFirstWeaponChild(sim.getAdmin(), built) != entt::null;
CHECK_FALSE(hasWeapon); CHECK_FALSE(hasWeapon);
} }
TEST_CASE("Shipyard: setRecipe clears ship layout", "[modules][shipyard]") TEST_CASE("Shipyard: setRecipe clears ship layout", "[modules][shipyard]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const BuildingDef* yardDef = findShipyardDef(sim.config()); const BuildingDef* yardDef = findShipyardDef(sim.getConfig());
REQUIRE(yardDef != nullptr); REQUIRE(yardDef != nullptr);
const BuildingId yardId = placeShipyard(sim, *yardDef); const BuildingId yardId = placeShipyard(sim, *yardDef);
@@ -327,13 +327,13 @@ TEST_CASE("Shipyard: setRecipe clears ship layout", "[modules][shipyard]")
layout.placedModules.push_back(pm); layout.placedModules.push_back(pm);
SimulationTestAccess::buildings(sim).setShipLayout(yardId, layout); SimulationTestAccess::buildings(sim).setShipLayout(yardId, layout);
const Building* b1 = sim.buildings().findBuilding(yardId); const Building* b1 = sim.getBuildings().findBuilding(yardId);
REQUIRE(b1 != nullptr); REQUIRE(b1 != nullptr);
REQUIRE(b1->shipLayout.has_value()); REQUIRE(b1->shipLayout.has_value());
SimulationTestAccess::buildings(sim).setRecipe(yardId,"destroyer"); SimulationTestAccess::buildings(sim).setRecipe(yardId,"destroyer");
const Building* b2 = sim.buildings().findBuilding(yardId); const Building* b2 = sim.getBuildings().findBuilding(yardId);
REQUIRE(b2 != nullptr); REQUIRE(b2 != nullptr);
CHECK_FALSE(b2->shipLayout.has_value()); CHECK_FALSE(b2->shipLayout.has_value());
} }
@@ -342,7 +342,7 @@ TEST_CASE("Shipyard: setRecipe with unchanged recipe keeps ship layout",
"[modules][shipyard]") "[modules][shipyard]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const BuildingDef* yardDef = findShipyardDef(sim.config()); const BuildingDef* yardDef = findShipyardDef(sim.getConfig());
REQUIRE(yardDef != nullptr); REQUIRE(yardDef != nullptr);
const BuildingId yardId = placeShipyard(sim, *yardDef); const BuildingId yardId = placeShipyard(sim, *yardDef);
@@ -356,14 +356,14 @@ TEST_CASE("Shipyard: setRecipe with unchanged recipe keeps ship layout",
layout.placedModules.push_back(pm); layout.placedModules.push_back(pm);
SimulationTestAccess::buildings(sim).setShipLayout(yardId, layout); SimulationTestAccess::buildings(sim).setShipLayout(yardId, layout);
const Building* b1 = sim.buildings().findBuilding(yardId); const Building* b1 = sim.getBuildings().findBuilding(yardId);
REQUIRE(b1 != nullptr); REQUIRE(b1 != nullptr);
REQUIRE(b1->shipLayout.has_value()); REQUIRE(b1->shipLayout.has_value());
// Re-selecting the same recipe must be a no-op and preserve the layout. // Re-selecting the same recipe must be a no-op and preserve the layout.
SimulationTestAccess::buildings(sim).setRecipe(yardId,"interceptor"); SimulationTestAccess::buildings(sim).setRecipe(yardId,"interceptor");
const Building* b2 = sim.buildings().findBuilding(yardId); const Building* b2 = sim.getBuildings().findBuilding(yardId);
REQUIRE(b2 != nullptr); REQUIRE(b2 != nullptr);
REQUIRE(b2->shipLayout.has_value()); REQUIRE(b2->shipLayout.has_value());
REQUIRE(b2->shipLayout->placedModules.size() == 1); REQUIRE(b2->shipLayout->placedModules.size() == 1);
@@ -377,7 +377,7 @@ TEST_CASE("Shipyard: setRecipe with unchanged recipe keeps ship layout",
TEST_CASE("Ship spawn: weapon_primer multiplies attack rate in simulation", "[modules]") TEST_CASE("Ship spawn: weapon_primer multiplies attack rate in simulation", "[modules]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* def = findSchematic(sim.config(), "interceptor"); const ShipDef* def = findSchematic(sim.getConfig(), "interceptor");
REQUIRE(def != nullptr); REQUIRE(def != nullptr);
ShipLayoutConfig layout; ShipLayoutConfig layout;
@@ -390,22 +390,22 @@ TEST_CASE("Ship spawn: weapon_primer multiplies attack rate in simulation", "[mo
layout.placedModules.push_back(pm); layout.placedModules.push_back(pm);
} }
const entt::entity ship = sim.ships().spawn("interceptor", const entt::entity ship = sim.getShips().spawn("interceptor",
QVector2D(5.0f, 5.0f), false, layout); QVector2D(5.0f, 5.0f), false, layout);
const entt::entity weapon = findFirstWeaponChild(sim.admin(), ship); const entt::entity weapon = findFirstWeaponChild(sim.getAdmin(), ship);
REQUIRE(sim.admin().isValid(weapon)); REQUIRE(sim.getAdmin().isValid(weapon));
// base rate = 2.0 hz; weapon_primer multiplier = 1.2 → 2.4 hz // base rate = 2.0 hz; weapon_primer multiplier = 1.2 → 2.4 hz
CHECK(sim.admin().get<WeaponComponent>(weapon).fireRateHz == Approx(2.4f)); CHECK(sim.getAdmin().get<WeaponComponent>(weapon).fireRateHz == Approx(2.4f));
} }
TEST_CASE("Ship spawn: weapon_stabilizer multiplies attack range in simulation", "[modules]") TEST_CASE("Ship spawn: weapon_stabilizer multiplies attack range in simulation", "[modules]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* def = findSchematic(sim.config(), "interceptor"); const ShipDef* def = findSchematic(sim.getConfig(), "interceptor");
REQUIRE(def != nullptr); REQUIRE(def != nullptr);
const float tileSize = static_cast<float>(sim.config().world.tileSize_m); const float tileSize = static_cast<float>(sim.getConfig().world.tileSize_m);
ShipLayoutConfig layout; ShipLayoutConfig layout;
for (const std::string& id : {"laser_cannon", "weapon_stabilizer"}) for (const std::string& id : {"laser_cannon", "weapon_stabilizer"})
@@ -417,22 +417,22 @@ TEST_CASE("Ship spawn: weapon_stabilizer multiplies attack range in simulation",
layout.placedModules.push_back(pm); layout.placedModules.push_back(pm);
} }
const entt::entity ship = sim.ships().spawn("interceptor", const entt::entity ship = sim.getShips().spawn("interceptor",
QVector2D(5.0f, 5.0f), false, layout); QVector2D(5.0f, 5.0f), false, layout);
const entt::entity weapon = findFirstWeaponChild(sim.admin(), ship); const entt::entity weapon = findFirstWeaponChild(sim.getAdmin(), ship);
REQUIRE(sim.admin().isValid(weapon)); REQUIRE(sim.getAdmin().isValid(weapon));
// base range = 50 m / tileSize = 5 tiles; weapon_stabilizer multiplier = 1.5 → 7.5 tiles // base range = 50 m / tileSize = 5 tiles; weapon_stabilizer multiplier = 1.5 → 7.5 tiles
CHECK(sim.admin().get<WeaponComponent>(weapon).range_tiles == Approx(50.0f / tileSize * 1.5f)); CHECK(sim.getAdmin().get<WeaponComponent>(weapon).range_tiles == Approx(50.0f / tileSize * 1.5f));
} }
TEST_CASE("Ship spawn: afterburner additive main_acceleration is converted m/s² to tiles/tick", "[modules]") TEST_CASE("Ship spawn: afterburner additive main_acceleration is converted m/s² to tiles/tick", "[modules]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* def = findSchematic(sim.config(), "interceptor"); const ShipDef* def = findSchematic(sim.getConfig(), "interceptor");
REQUIRE(def != nullptr); REQUIRE(def != nullptr);
const float tileSize = static_cast<float>(sim.config().world.tileSize_m); const float tileSize = static_cast<float>(sim.getConfig().world.tileSize_m);
const float tickRate = static_cast<float>(kTickRateHz); const float tickRate = static_cast<float>(kTickRateHz);
const float base_mpss = static_cast<float>(def->movement.mainAcceleration_mpss); const float base_mpss = static_cast<float>(def->movement.mainAcceleration_mpss);
@@ -443,21 +443,21 @@ TEST_CASE("Ship spawn: afterburner additive main_acceleration is converted m/s²
pm.rotation = Rotation::East; pm.rotation = Rotation::East;
layout.placedModules.push_back(pm); layout.placedModules.push_back(pm);
const entt::entity e = sim.ships().spawn("interceptor", const entt::entity e = sim.getShips().spawn("interceptor",
QVector2D(5.0f, 5.0f), false, layout); QVector2D(5.0f, 5.0f), false, layout);
// added_main_acceleration_mpss = 60; same conversion as base: / tileSize / tickRate // added_main_acceleration_mpss = 60; same conversion as base: / tileSize / tickRate
const float expected = (base_mpss + 60.0f) / tileSize / tickRate; const float expected = (base_mpss + 60.0f) / tileSize / tickRate;
CHECK(sim.admin().get<DynamicBodyComponent>(e).mainAcceleration_tptt == Approx(expected)); CHECK(sim.getAdmin().get<DynamicBodyComponent>(e).mainAcceleration_tptt == Approx(expected));
} }
TEST_CASE("Ship spawn: maneuvering_thrusters additive maneuvering_acceleration is converted m/s² to tiles/tick", "[modules]") TEST_CASE("Ship spawn: maneuvering_thrusters additive maneuvering_acceleration is converted m/s² to tiles/tick", "[modules]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* def = findSchematic(sim.config(), "interceptor"); const ShipDef* def = findSchematic(sim.getConfig(), "interceptor");
REQUIRE(def != nullptr); REQUIRE(def != nullptr);
const float tileSize = static_cast<float>(sim.config().world.tileSize_m); const float tileSize = static_cast<float>(sim.getConfig().world.tileSize_m);
const float tickRate = static_cast<float>(kTickRateHz); const float tickRate = static_cast<float>(kTickRateHz);
const float base_mpss = static_cast<float>(def->movement.maneuveringAcceleration_mpss); const float base_mpss = static_cast<float>(def->movement.maneuveringAcceleration_mpss);
@@ -468,12 +468,12 @@ TEST_CASE("Ship spawn: maneuvering_thrusters additive maneuvering_acceleration i
pm.rotation = Rotation::East; pm.rotation = Rotation::East;
layout.placedModules.push_back(pm); layout.placedModules.push_back(pm);
const entt::entity e = sim.ships().spawn("interceptor", const entt::entity e = sim.getShips().spawn("interceptor",
QVector2D(5.0f, 5.0f), false, layout); QVector2D(5.0f, 5.0f), false, layout);
// added_maneuvering_acceleration_mpss = 10; same conversion as base: / tileSize / tickRate // added_maneuvering_acceleration_mpss = 10; same conversion as base: / tileSize / tickRate
const float expected = (base_mpss + 10.0f) / tileSize / tickRate; const float expected = (base_mpss + 10.0f) / tileSize / tickRate;
CHECK(sim.admin().get<DynamicBodyComponent>(e).maneuveringAcceleration_tptt == Approx(expected)); CHECK(sim.getAdmin().get<DynamicBodyComponent>(e).maneuveringAcceleration_tptt == Approx(expected));
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@@ -56,7 +56,7 @@ static BuildingId placeShipyard(Simulation& sim, const BuildingDef& yardDef)
static int countShips(Simulation& sim) static int countShips(Simulation& sim)
{ {
int n = 0; int n = 0;
sim.admin().forEach<ShipIdentityComponent>( sim.getAdmin().forEach<ShipIdentityComponent>(
[&n](entt::entity /*e*/, const ShipIdentityComponent& /*si*/) { ++n; }); [&n](entt::entity /*e*/, const ShipIdentityComponent& /*si*/) { ++n; });
return n; return n;
} }
@@ -85,9 +85,9 @@ TEST_CASE("Shipyard: spawns a player ship after production cycle completes",
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* def = findAvailableSchematic(sim.config()); const ShipDef* def = findAvailableSchematic(sim.getConfig());
REQUIRE(def != nullptr); REQUIRE(def != nullptr);
const BuildingDef* yardDef = findShipyardDef(sim.config()); const BuildingDef* yardDef = findShipyardDef(sim.getConfig());
REQUIRE(yardDef != nullptr); REQUIRE(yardDef != nullptr);
const int shipsBefore = countShips(sim); const int shipsBefore = countShips(sim);
@@ -115,7 +115,7 @@ TEST_CASE("Shipyard: spawns a player ship after production cycle completes",
REQUIRE(countShips(sim) == shipsBefore + 1); REQUIRE(countShips(sim) == shipsBefore + 1);
bool foundPlayerShip = false; bool foundPlayerShip = false;
sim.admin().forEach<ShipIdentityComponent, FactionComponent>( sim.getAdmin().forEach<ShipIdentityComponent, FactionComponent>(
[&](entt::entity /*e*/, const ShipIdentityComponent& si, const FactionComponent& f) [&](entt::entity /*e*/, const ShipIdentityComponent& si, const FactionComponent& f)
{ {
if (!f.isEnemy && si.schematicId == def->id) if (!f.isEnemy && si.schematicId == def->id)
@@ -130,7 +130,7 @@ TEST_CASE("Shipyard: does not spawn without a schematic set", "[shipyard]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const BuildingDef* yardDef = findShipyardDef(sim.config()); const BuildingDef* yardDef = findShipyardDef(sim.getConfig());
REQUIRE(yardDef != nullptr); REQUIRE(yardDef != nullptr);
const int shipsBefore = countShips(sim); const int shipsBefore = countShips(sim);
@@ -146,9 +146,9 @@ TEST_CASE("Shipyard: does not spawn with insufficient materials", "[shipyard]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* def = findAvailableSchematic(sim.config()); const ShipDef* def = findAvailableSchematic(sim.getConfig());
REQUIRE(def != nullptr); REQUIRE(def != nullptr);
const BuildingDef* yardDef = findShipyardDef(sim.config()); const BuildingDef* yardDef = findShipyardDef(sim.getConfig());
REQUIRE(yardDef != nullptr); REQUIRE(yardDef != nullptr);
const int shipsBefore = countShips(sim); const int shipsBefore = countShips(sim);
@@ -170,9 +170,9 @@ TEST_CASE("Shipyard: spawns a second ship after materials replenished", "[shipya
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
const ShipDef* def = findAvailableSchematic(sim.config()); const ShipDef* def = findAvailableSchematic(sim.getConfig());
REQUIRE(def != nullptr); REQUIRE(def != nullptr);
const BuildingDef* yardDef = findShipyardDef(sim.config()); const BuildingDef* yardDef = findShipyardDef(sim.getConfig());
REQUIRE(yardDef != nullptr); REQUIRE(yardDef != nullptr);
const BuildingId yardId = placeShipyard(sim, *yardDef); const BuildingId yardId = placeShipyard(sim, *yardDef);
@@ -203,7 +203,7 @@ TEST_CASE("Shipyard: spawns a second ship after materials replenished", "[shipya
// Verify the shipyard production field cleared (i.e. the cycle completed // Verify the shipyard production field cleared (i.e. the cycle completed
// and is not still running). // and is not still running).
bool productionCleared = false; bool productionCleared = false;
for (const Building& b : sim.buildings().allBuildings()) for (const Building& b : sim.getBuildings().getAllBuildings())
{ {
if (b.id == yardId) if (b.id == yardId)
{ {

View File

@@ -19,7 +19,7 @@ TEST_CASE("Simulation::currentTick starts at 0", "[simulation]")
{ {
const Simulation sim(loadConfig()); const Simulation sim(loadConfig());
REQUIRE(sim.currentTick() == 0); REQUIRE(sim.getCurrentTick() == 0);
} }
TEST_CASE("Simulation::tick increments currentTick by 1", "[simulation]") TEST_CASE("Simulation::tick increments currentTick by 1", "[simulation]")
@@ -28,7 +28,7 @@ TEST_CASE("Simulation::tick increments currentTick by 1", "[simulation]")
sim.tick(); sim.tick();
REQUIRE(sim.currentTick() == 1); REQUIRE(sim.getCurrentTick() == 1);
} }
TEST_CASE("Simulation::tick 10 times yields currentTick == 10", "[simulation]") TEST_CASE("Simulation::tick 10 times yields currentTick == 10", "[simulation]")
@@ -40,7 +40,7 @@ TEST_CASE("Simulation::tick 10 times yields currentTick == 10", "[simulation]")
sim.tick(); sim.tick();
} }
REQUIRE(sim.currentTick() == 10); REQUIRE(sim.getCurrentTick() == 10);
} }
TEST_CASE("Simulation::drainBeamFiredEvents returns empty initially", "[simulation]") TEST_CASE("Simulation::drainBeamFiredEvents returns empty initially", "[simulation]")

View File

@@ -22,8 +22,8 @@ class BuildingSystem;
// reached via buildings(sim)/belts(sim). // reached via buildings(sim)/belts(sim).
struct SimulationTestAccess struct SimulationTestAccess
{ {
static BuildingSystem& buildings(Simulation& sim) { return sim.buildingsMutable(); } static BuildingSystem& buildings(Simulation& sim) { return sim.getBuildingsMutable(); }
static BeltSystem& belts(Simulation& sim) { return sim.beltsMutable(); } static BeltSystem& belts(Simulation& sim) { return sim.getBeltsMutable(); }
static BuildingId place(Simulation& sim, BuildingType type, QPoint anchor, static BuildingId place(Simulation& sim, BuildingType type, QPoint anchor,
Rotation rotation) Rotation rotation)

View File

@@ -67,7 +67,7 @@ RecipeDef& findRecipe(GameConfig& cfg, const std::string& id)
// tickDeathsAndLoot fires, triggering the push and schematic choices. // tickDeathsAndLoot fires, triggering the push and schematic choices.
void killEnemyStations(Simulation& sim) void killEnemyStations(Simulation& sim)
{ {
sim.admin().forEach<StationBodyComponent, FactionComponent, HealthComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent, HealthComponent>(
[](entt::entity, StationBodyComponent&, FactionComponent& faction, HealthComponent& health) [](entt::entity, StationBodyComponent&, FactionComponent& faction, HealthComponent& health)
{ {
if (faction.isEnemy) if (faction.isEnemy)

View File

@@ -49,7 +49,7 @@ TEST_CASE("WaveSystem: threat accumulates at boss wave counter rate", "[wave]")
ws.tickThreatAccumulation(); ws.tickThreatAccumulation();
} }
REQUIRE(ws.threatLevel() == Approx(1.0)); REQUIRE(ws.getThreatLevel() == Approx(1.0));
} }
TEST_CASE("WaveSystem: threatAccumulationRate matches the rate formula outside quiet windows", TEST_CASE("WaveSystem: threatAccumulationRate matches the rate formula outside quiet windows",
@@ -60,7 +60,7 @@ TEST_CASE("WaveSystem: threatAccumulationRate matches the rate formula outside q
WaveSystem ws(cfg, rng); WaveSystem ws(cfg, rng);
// threat_rate_formula = "x", boss wave counter starts at 1 → rate = 1 threat/s. // threat_rate_formula = "x", boss wave counter starts at 1 → rate = 1 threat/s.
REQUIRE(ws.threatAccumulationRate() == Approx(1.0)); REQUIRE(ws.getThreatAccumulationRate() == Approx(1.0));
} }
TEST_CASE("WaveSystem: threatAccumulationRate is 0 during a quiet window", "[wave]") TEST_CASE("WaveSystem: threatAccumulationRate is 0 during a quiet window", "[wave]")
@@ -71,14 +71,14 @@ TEST_CASE("WaveSystem: threatAccumulationRate is 0 during a quiet window", "[wav
std::mt19937 rng(42); std::mt19937 rng(42);
WaveSystem ws(cfg, rng); WaveSystem ws(cfg, rng);
REQUIRE(ws.threatAccumulationRate() == Approx(0.0)); REQUIRE(ws.getThreatAccumulationRate() == Approx(0.0));
const double before = ws.threatLevel(); const double before = ws.getThreatLevel();
for (int i = 0; i < static_cast<int>(secondsToTicks(1.0)); ++i) for (int i = 0; i < static_cast<int>(secondsToTicks(1.0)); ++i)
{ {
ws.tickThreatAccumulation(); ws.tickThreatAccumulation();
} }
REQUIRE(ws.threatLevel() == Approx(before)); REQUIRE(ws.getThreatLevel() == Approx(before));
} }
TEST_CASE("WaveSystem: generation starts at 0 and increments on station destruction", "[wave]") TEST_CASE("WaveSystem: generation starts at 0 and increments on station destruction", "[wave]")
@@ -87,11 +87,11 @@ TEST_CASE("WaveSystem: generation starts at 0 and increments on station destruct
std::mt19937 rng(42); std::mt19937 rng(42);
WaveSystem ws(cfg, rng); WaveSystem ws(cfg, rng);
REQUIRE(ws.generation() == 0); REQUIRE(ws.getGeneration() == 0);
ws.onEnemyStationsDestroyed(); ws.onEnemyStationsDestroyed();
REQUIRE(ws.generation() == 1); REQUIRE(ws.getGeneration() == 1);
ws.onEnemyStationsDestroyed(); ws.onEnemyStationsDestroyed();
REQUIRE(ws.generation() == 2); REQUIRE(ws.getGeneration() == 2);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -104,7 +104,7 @@ TEST_CASE("WaveSystem: Simulation pre-places HQ + 2 player + 2 enemy stations",
// HQ is still a Building (for belt integration). // HQ is still a Building (for belt integration).
int hqCount = 0; int hqCount = 0;
for (const Building& b : sim.buildings().allBuildings()) for (const Building& b : sim.getBuildings().getAllBuildings())
{ {
if (b.type == BuildingType::Hq) { ++hqCount; } if (b.type == BuildingType::Hq) { ++hqCount; }
} }
@@ -112,7 +112,7 @@ TEST_CASE("WaveSystem: Simulation pre-places HQ + 2 player + 2 enemy stations",
// Stations are ECS entities. // Stations are ECS entities.
int playerCount = 0; int playerCount = 0;
int enemyCount = 0; int enemyCount = 0;
sim.admin().forEach<StationBodyComponent, FactionComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent>(
[&](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f) [&](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f)
{ {
if (f.isEnemy) { ++enemyCount; } if (f.isEnemy) { ++enemyCount; }
@@ -129,10 +129,10 @@ TEST_CASE("WaveSystem: HQ has correct initial HP from config", "[wave]")
const Simulation sim(loadConfig(), 42); const Simulation sim(loadConfig(), 42);
const float expectedHp = const float expectedHp =
static_cast<float>(sim.config().stations.hq.hpFormula.evaluate(0.0)); static_cast<float>(sim.getConfig().stations.hq.hpFormula.evaluate(0.0));
bool found = false; bool found = false;
float actualHp = 0.0f; float actualHp = 0.0f;
sim.admin().forEach<HqProxyComponent, HealthComponent>( sim.getAdmin().forEach<HqProxyComponent, HealthComponent>(
[&](entt::entity /*e*/, const HqProxyComponent& /*hq*/, const HealthComponent& h) [&](entt::entity /*e*/, const HqProxyComponent& /*hq*/, const HealthComponent& h)
{ {
found = true; found = true;
@@ -147,7 +147,7 @@ TEST_CASE("WaveSystem: HQ anchor is at asteroid right edge", "[wave]")
{ {
const Simulation sim(loadConfig(), 42); const Simulation sim(loadConfig(), 42);
for (const Building& b : sim.buildings().allBuildings()) for (const Building& b : sim.getBuildings().getAllBuildings())
{ {
if (b.type != BuildingType::Hq) { continue; } if (b.type != BuildingType::Hq) { continue; }
// Rightmost body cell must be at x = -1 (asteroid right edge). // Rightmost body cell must be at x = -1 (asteroid right edge).
@@ -165,11 +165,11 @@ TEST_CASE("WaveSystem: player stations have weapon set", "[wave]")
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
int armedPlayerStations = 0; int armedPlayerStations = 0;
sim.admin().forEach<WeaponComponent, ModuleOwnerComponent>( sim.getAdmin().forEach<WeaponComponent, ModuleOwnerComponent>(
[&](entt::entity /*e*/, const WeaponComponent& w, const ModuleOwnerComponent& mo) [&](entt::entity /*e*/, const WeaponComponent& w, const ModuleOwnerComponent& mo)
{ {
if (!sim.admin().hasAll<StationBodyComponent>(mo.owner)) { return; } if (!sim.getAdmin().hasAll<StationBodyComponent>(mo.owner)) { return; }
const FactionComponent& f = sim.admin().get<FactionComponent>(mo.owner); const FactionComponent& f = sim.getAdmin().get<FactionComponent>(mo.owner);
if (!f.isEnemy) if (!f.isEnemy)
{ {
++armedPlayerStations; ++armedPlayerStations;
@@ -186,11 +186,11 @@ TEST_CASE("WaveSystem: enemy stations have weapon set", "[wave]")
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
int armedEnemyStations = 0; int armedEnemyStations = 0;
sim.admin().forEach<WeaponComponent, ModuleOwnerComponent>( sim.getAdmin().forEach<WeaponComponent, ModuleOwnerComponent>(
[&](entt::entity /*e*/, const WeaponComponent& w, const ModuleOwnerComponent& mo) [&](entt::entity /*e*/, const WeaponComponent& w, const ModuleOwnerComponent& mo)
{ {
if (!sim.admin().hasAll<StationBodyComponent>(mo.owner)) { return; } if (!sim.getAdmin().hasAll<StationBodyComponent>(mo.owner)) { return; }
const FactionComponent& f = sim.admin().get<FactionComponent>(mo.owner); const FactionComponent& f = sim.getAdmin().get<FactionComponent>(mo.owner);
if (f.isEnemy) if (f.isEnemy)
{ {
++armedEnemyStations; ++armedEnemyStations;
@@ -221,7 +221,7 @@ TEST_CASE("WaveSystem: enemy ships spawn after the initial gap elapses", "[wave]
sim.tick(); sim.tick();
if (!foundEnemyShip) if (!foundEnemyShip)
{ {
sim.admin().forEach<ShipIdentityComponent, FactionComponent>( sim.getAdmin().forEach<ShipIdentityComponent, FactionComponent>(
[&](entt::entity /*e*/, const ShipIdentityComponent& /*si*/, [&](entt::entity /*e*/, const ShipIdentityComponent& /*si*/,
const FactionComponent& f) const FactionComponent& f)
{ {
@@ -253,7 +253,7 @@ TEST_CASE("WaveSystem: destroying both enemy stations triggers a push", "[wave]"
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
// Damage both enemy stations to 0. // Damage both enemy stations to 0.
sim.admin().forEach<StationBodyComponent, FactionComponent, HealthComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent, HealthComponent>(
[](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f, HealthComponent& h) [](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f, HealthComponent& h)
{ {
if (f.isEnemy) { h.hp = -1.0f; } if (f.isEnemy) { h.hp = -1.0f; }
@@ -263,7 +263,7 @@ TEST_CASE("WaveSystem: destroying both enemy stations triggers a push", "[wave]"
// After push: should have 2 new enemy stations. // After push: should have 2 new enemy stations.
int enemyCount = 0; int enemyCount = 0;
sim.admin().forEach<StationBodyComponent, FactionComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent>(
[&](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f) [&](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f)
{ {
if (f.isEnemy) { ++enemyCount; } if (f.isEnemy) { ++enemyCount; }
@@ -275,7 +275,7 @@ TEST_CASE("WaveSystem: push generates pending schematic choices", "[wave]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
sim.admin().forEach<StationBodyComponent, FactionComponent, HealthComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent, HealthComponent>(
[](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f, HealthComponent& h) [](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f, HealthComponent& h)
{ {
if (f.isEnemy) { h.hp = -1.0f; } if (f.isEnemy) { h.hp = -1.0f; }
@@ -293,7 +293,7 @@ TEST_CASE("WaveSystem: push schematic choices have valid ids", "[wave]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
sim.admin().forEach<StationBodyComponent, FactionComponent, HealthComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent, HealthComponent>(
[](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f, HealthComponent& h) [](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f, HealthComponent& h)
{ {
if (f.isEnemy) { h.hp = -1.0f; } if (f.isEnemy) { h.hp = -1.0f; }
@@ -306,20 +306,20 @@ TEST_CASE("WaveSystem: push schematic choices have valid ids", "[wave]")
for (const SchematicChoiceOption& opt : choices) for (const SchematicChoiceOption& opt : choices)
{ {
bool validId = false; bool validId = false;
for (const ShipDef& def : sim.config().ships.ships) for (const ShipDef& def : sim.getConfig().ships.ships)
{ {
if (def.id == opt.schematicId) { validId = true; break; } if (def.id == opt.schematicId) { validId = true; break; }
} }
if (!validId) if (!validId)
{ {
for (const ModuleDef& def : sim.config().modules.modules) for (const ModuleDef& def : sim.getConfig().modules.modules)
{ {
if (def.id == opt.schematicId) { validId = true; break; } if (def.id == opt.schematicId) { validId = true; break; }
} }
} }
if (!validId) if (!validId)
{ {
for (const RecipeDef& def : sim.config().recipes.recipes) for (const RecipeDef& def : sim.getConfig().recipes.recipes)
{ {
if (def.id == opt.schematicId) { validId = true; break; } if (def.id == opt.schematicId) { validId = true; break; }
} }
@@ -332,7 +332,7 @@ TEST_CASE("WaveSystem: schematic choices have no duplicates", "[wave]")
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
sim.admin().forEach<StationBodyComponent, FactionComponent, HealthComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent, HealthComponent>(
[](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f, HealthComponent& h) [](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f, HealthComponent& h)
{ {
if (f.isEnemy) { h.hp = -1.0f; } if (f.isEnemy) { h.hp = -1.0f; }
@@ -352,7 +352,7 @@ TEST_CASE("WaveSystem: applySchematicChoice clears pending and applies", "[wave]
{ {
Simulation sim(loadConfig(), 42); Simulation sim(loadConfig(), 42);
sim.admin().forEach<StationBodyComponent, FactionComponent, HealthComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent, HealthComponent>(
[](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f, HealthComponent& h) [](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f, HealthComponent& h)
{ {
if (f.isEnemy) { h.hp = -1.0f; } if (f.isEnemy) { h.hp = -1.0f; }
@@ -370,7 +370,7 @@ TEST_CASE("WaveSystem: push places new enemy stations further right", "[wave]")
// Record the X position of the initial enemy stations. // Record the X position of the initial enemy stations.
int initialX = std::numeric_limits<int>::min(); int initialX = std::numeric_limits<int>::min();
sim.admin().forEach<StationBodyComponent, FactionComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent>(
[&](entt::entity /*e*/, const StationBodyComponent& sb, const FactionComponent& f) [&](entt::entity /*e*/, const StationBodyComponent& sb, const FactionComponent& f)
{ {
if (f.isEnemy && sb.anchor.x() > initialX) if (f.isEnemy && sb.anchor.x() > initialX)
@@ -379,7 +379,7 @@ TEST_CASE("WaveSystem: push places new enemy stations further right", "[wave]")
} }
}); });
sim.admin().forEach<StationBodyComponent, FactionComponent, HealthComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent, HealthComponent>(
[](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f, HealthComponent& h) [](entt::entity /*e*/, const StationBodyComponent& /*sb*/, const FactionComponent& f, HealthComponent& h)
{ {
if (f.isEnemy) { h.hp = -1.0f; } if (f.isEnemy) { h.hp = -1.0f; }
@@ -387,7 +387,7 @@ TEST_CASE("WaveSystem: push places new enemy stations further right", "[wave]")
sim.tick(); sim.tick();
int newX = std::numeric_limits<int>::min(); int newX = std::numeric_limits<int>::min();
sim.admin().forEach<StationBodyComponent, FactionComponent>( sim.getAdmin().forEach<StationBodyComponent, FactionComponent>(
[&](entt::entity /*e*/, const StationBodyComponent& sb, const FactionComponent& f) [&](entt::entity /*e*/, const StationBodyComponent& sb, const FactionComponent& f)
{ {
if (f.isEnemy && sb.anchor.x() > newX) if (f.isEnemy && sb.anchor.x() > newX)

View File

@@ -211,7 +211,7 @@ void GameWorldView::onFrame()
if (m_replayPlayer->isFinished() if (m_replayPlayer->isFinished()
|| m_sim->isWon() || m_sim->isGameOver()) { break; } || m_sim->isWon() || m_sim->isGameOver()) { break; }
m_sim->tick(); m_sim->tick();
m_replayPlayer->advanceTo(m_sim->currentTick()); m_replayPlayer->advanceTo(m_sim->getCurrentTick());
} }
} }
else else
@@ -263,7 +263,7 @@ void GameWorldView::onFrame()
// Expire old beams. Lifetime is measured in game ticks so beams stay // Expire old beams. Lifetime is measured in game ticks so beams stay
// visible while the simulation is paused or slowed (REQ-SHP-FIRING-BEAM). // visible while the simulation is paused or slowed (REQ-SHP-FIRING-BEAM).
{ {
const Tick now = m_sim->currentTick(); const Tick now = m_sim->getCurrentTick();
std::vector<ActiveBeam> live; std::vector<ActiveBeam> live;
for (const ActiveBeam& b : m_activeBeams) for (const ActiveBeam& b : m_activeBeams)
{ {
@@ -314,11 +314,11 @@ void GameWorldView::onFrame()
// Fire events for any state that changed since the last frame // Fire events for any state that changed since the last frame
{ {
const Tick newTick = m_sim->currentTick(); const Tick newTick = m_sim->getCurrentTick();
const int newBlocks = m_sim->buildingBlocksStock(); const int newBlocks = m_sim->getBuildingBlocksStock();
const int newExpCost = m_sim->currentExpansionCost(); const int newExpCost = m_sim->getCurrentExpansionCost();
const int newBoss = m_sim->bossWaveCounter(); const int newBoss = m_sim->getBossWaveCounter();
const Tick newCountdown = m_sim->bossCountdownTicks(); const Tick newCountdown = m_sim->getBossCountdownTicks();
if (newTick != m_lastTick) if (newTick != m_lastTick)
{ {
@@ -384,16 +384,16 @@ void GameWorldView::onFrame()
// Artifact count is a passive reflection of sim state (not a live-input source // Artifact count is a passive reflection of sim state (not a live-input source
// like the schematic/game-over polls above), so it updates during replay too — // like the schematic/game-over polls above), so it updates during replay too —
// the recorded ApplySchematicChoice drives m_sim->artifactCount() forward and // the recorded ApplySchematicChoice drives m_sim->getArtifactCount() forward and
// the header bar must track it. Fires on the first frame (count 0 vs the -1 // the header bar must track it. Fires on the first frame (count 0 vs the -1
// sentinel), which also populates the win-count max (replacing the "0/?" label). // sentinel), which also populates the win-count max (replacing the "0/?" label).
const int currentArtifactCount = m_sim->artifactCount(); const int currentArtifactCount = m_sim->getArtifactCount();
if (currentArtifactCount != m_lastArtifactCount) if (currentArtifactCount != m_lastArtifactCount)
{ {
m_lastArtifactCount = currentArtifactCount; m_lastArtifactCount = currentArtifactCount;
EventManager::getInstance()->sendEventImmediately( EventManager::getInstance()->sendEventImmediately(
std::make_shared<ArtifactCountChangedEvent>( std::make_shared<ArtifactCountChangedEvent>(
currentArtifactCount, m_sim->config().world.artifacts.artifactWinCount)); currentArtifactCount, m_sim->getConfig().world.artifacts.artifactWinCount));
} }
update(); update();
@@ -432,27 +432,27 @@ void GameWorldView::paintGL()
// Coordinate helpers // Coordinate helpers
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
float GameWorldView::tilePx() const float GameWorldView::getTilePx() const
{ {
if (m_config->world.heightTiles <= 0) { return 1.0f; } if (m_config->world.heightTiles <= 0) { return 1.0f; }
return static_cast<float>(height()) / static_cast<float>(m_config->world.heightTiles); return static_cast<float>(height()) / static_cast<float>(m_config->world.heightTiles);
} }
float GameWorldView::viewportWidthTiles() const float GameWorldView::getViewportWidthTiles() const
{ {
return static_cast<float>(width()) / tilePx(); return static_cast<float>(width()) / getTilePx();
} }
float GameWorldView::viewLeftTiles() const float GameWorldView::getViewLeftTiles() const
{ {
return m_scrollXTiles - viewportWidthTiles() / 2.0f; return m_scrollXTiles - getViewportWidthTiles() / 2.0f;
} }
QPointF GameWorldView::worldToWidget(QVector2D worldPos) const QPointF GameWorldView::worldToWidget(QVector2D worldPos) const
{ {
return QPointF( return QPointF(
static_cast<qreal>((worldPos.x() - viewLeftTiles()) * tilePx()), static_cast<qreal>((worldPos.x() - getViewLeftTiles()) * getTilePx()),
static_cast<qreal>(worldPos.y() * tilePx())); static_cast<qreal>(worldPos.y() * getTilePx()));
} }
QPointF GameWorldView::tileToWidget(QPoint tile) const QPointF GameWorldView::tileToWidget(QPoint tile) const
@@ -463,15 +463,15 @@ QPointF GameWorldView::tileToWidget(QPoint tile) const
QPoint GameWorldView::widgetToTile(QPoint widgetPt) const QPoint GameWorldView::widgetToTile(QPoint widgetPt) const
{ {
const float wx = static_cast<float>(widgetPt.x()) / tilePx() + viewLeftTiles(); const float wx = static_cast<float>(widgetPt.x()) / getTilePx() + getViewLeftTiles();
const float wy = static_cast<float>(widgetPt.y()) / tilePx(); const float wy = static_cast<float>(widgetPt.y()) / getTilePx();
return QPoint(static_cast<int>(std::floor(wx)), static_cast<int>(std::floor(wy))); return QPoint(static_cast<int>(std::floor(wx)), static_cast<int>(std::floor(wy)));
} }
QVector2D GameWorldView::widgetToWorld(QPoint widgetPt) const QVector2D GameWorldView::widgetToWorld(QPoint widgetPt) const
{ {
const float wx = static_cast<float>(widgetPt.x()) / tilePx() + viewLeftTiles(); const float wx = static_cast<float>(widgetPt.x()) / getTilePx() + getViewLeftTiles();
const float wy = static_cast<float>(widgetPt.y()) / tilePx(); const float wy = static_cast<float>(widgetPt.y()) / getTilePx();
return QVector2D(wx, wy); return QVector2D(wx, wy);
} }
@@ -479,22 +479,22 @@ QRectF GameWorldView::tileRect(QPoint tile) const
{ {
const QPointF tl = tileToWidget(tile); const QPointF tl = tileToWidget(tile);
return QRectF(tl.x(), tl.y(), return QRectF(tl.x(), tl.y(),
static_cast<qreal>(tilePx()), static_cast<qreal>(tilePx())); static_cast<qreal>(getTilePx()), static_cast<qreal>(getTilePx()));
} }
QRect GameWorldView::viewportRect() const QRect GameWorldView::getViewportRect() const
{ {
const int left = static_cast<int>(std::floor(viewLeftTiles())) - 1; const int left = static_cast<int>(std::floor(getViewLeftTiles())) - 1;
const int top = 0; const int top = 0;
const int right = static_cast<int>(std::ceil(viewLeftTiles() + viewportWidthTiles())) + 1; const int right = static_cast<int>(std::ceil(getViewLeftTiles() + getViewportWidthTiles())) + 1;
const int bottom = m_config->world.heightTiles; const int bottom = m_config->world.heightTiles;
return QRect(left, top, right - left, bottom - top); return QRect(left, top, right - left, bottom - top);
} }
float GameWorldView::asteroidLeftEdge() const float GameWorldView::getAsteroidLeftEdge() const
{ {
float leftX = -static_cast<float>(m_sim->currentAsteroidWidth_tiles()); float leftX = -static_cast<float>(m_sim->getCurrentAsteroidWidth_tiles());
for (const Building& b : m_sim->buildings().allBuildings()) for (const Building& b : m_sim->getBuildings().getAllBuildings())
{ {
for (const QPoint& cell : b.bodyCells) for (const QPoint& cell : b.bodyCells)
{ {
@@ -507,11 +507,11 @@ float GameWorldView::asteroidLeftEdge() const
return leftX; return leftX;
} }
float GameWorldView::enemyStationRightEdge() const float GameWorldView::getEnemyStationRightEdge() const
{ {
float rightX = static_cast<float>(m_config->world.regions.playerBufferWidth_tiles float rightX = static_cast<float>(m_config->world.regions.playerBufferWidth_tiles
+ m_config->world.regions.contestZoneWidth_tiles); + m_config->world.regions.contestZoneWidth_tiles);
m_sim->admin().forEach<StationBodyComponent, FactionComponent>( m_sim->getAdmin().forEach<StationBodyComponent, FactionComponent>(
[&rightX](entt::entity /*e*/, const StationBodyComponent& sb, const FactionComponent& f) [&rightX](entt::entity /*e*/, const StationBodyComponent& sb, const FactionComponent& f)
{ {
if (!f.isEnemy) { return; } if (!f.isEnemy) { return; }
@@ -546,7 +546,7 @@ float GameWorldView::panSpeedTilesPerSecondAt(float viewCenterXTiles) const
const float fast = static_cast<float>(m_config->world.scroll.panSpeedFast_tps); const float fast = static_cast<float>(m_config->world.scroll.panSpeedFast_tps);
const float half = static_cast<float>(m_config->world.scroll.panRampBandWidth_tiles) / 2.0f; const float half = static_cast<float>(m_config->world.scroll.panRampBandWidth_tiles) / 2.0f;
const float leftEdge = static_cast<float>(m_config->world.regions.playerBufferWidth_tiles); const float leftEdge = static_cast<float>(m_config->world.regions.playerBufferWidth_tiles);
const float rightEdge = enemyStationRightEdge(); const float rightEdge = getEnemyStationRightEdge();
// Rising ramp at the left boundary (slow -> fast) and falling ramp at the right // Rising ramp at the left boundary (slow -> fast) and falling ramp at the right
// boundary (fast -> slow); their minimum yields flat-slow outside, flat-fast in // boundary (fast -> slow); their minimum yields flat-slow outside, flat-fast in
@@ -562,8 +562,8 @@ void GameWorldView::clampScroll()
// m_scrollXTiles is the view center, so the pan limits are the edges themselves: // m_scrollXTiles is the view center, so the pan limits are the edges themselves:
// the view can pan left until the buildable/asteroid edge is centered, and right // the view can pan left until the buildable/asteroid edge is centered, and right
// until the enemy stations are centered (revealing a little space beyond them). // until the enemy stations are centered (revealing a little space beyond them).
const float leftBound = asteroidLeftEdge(); const float leftBound = getAsteroidLeftEdge();
const float rightBound = enemyStationRightEdge(); const float rightBound = getEnemyStationRightEdge();
m_scrollXTiles = std::max(leftBound, std::min(m_scrollXTiles, rightBound)); m_scrollXTiles = std::max(leftBound, std::min(m_scrollXTiles, rightBound));
} }
@@ -586,7 +586,7 @@ bool GameWorldView::isValidPlacement(BuildingType type, QPoint anchor,
// Terrain and world-bounds validity are owned by the simulation // Terrain and world-bounds validity are owned by the simulation
// (REQ-BLD-PLACE-VALID); the presentation layer only adds the occupancy / // (REQ-BLD-PLACE-VALID); the presentation layer only adds the occupancy /
// rotate-in-place check. // rotate-in-place check.
if (!m_sim->buildings().isPlacementValid(type, anchor, rot)) if (!m_sim->getBuildings().isPlacementValid(type, anchor, rot))
{ {
return false; return false;
} }
@@ -598,7 +598,7 @@ bool GameWorldView::isValidPlacement(BuildingType type, QPoint anchor,
bool anyOccupied = false; bool anyOccupied = false;
for (const QPoint& relCell : parsed.bodyCells) for (const QPoint& relCell : parsed.bodyCells)
{ {
if (m_sim->buildings().isTileOccupied(anchor + relCell)) if (m_sim->getBuildings().isTileOccupied(anchor + relCell))
{ {
anyOccupied = true; anyOccupied = true;
break; break;
@@ -607,14 +607,14 @@ bool GameWorldView::isValidPlacement(BuildingType type, QPoint anchor,
if (anyOccupied) if (anyOccupied)
{ {
return m_sim->buildings().findRotateInPlaceTarget(type, anchor, rot).has_value(); return m_sim->getBuildings().findRotateInPlaceTarget(type, anchor, rot).has_value();
} }
return true; return true;
} }
BuildingId 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->getBuildings().getAllBuildings())
{ {
for (const QPoint& cell : b.bodyCells) for (const QPoint& cell : b.bodyCells)
{ {
@@ -629,7 +629,7 @@ BuildingId GameWorldView::buildingAtTile(QPoint tile) const
BuildingId 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->getBuildings().getAllSites())
{ {
for (const QPoint& cell : s.bodyCells) for (const QPoint& cell : s.bodyCells)
{ {
@@ -651,7 +651,7 @@ std::vector<BuildingId> GameWorldView::buildingsInBox(QPoint cornerA, QPoint cor
const int y1 = std::max(cornerA.y(), cornerB.y()); const int y1 = std::max(cornerA.y(), cornerB.y());
std::vector<BuildingId> ids; std::vector<BuildingId> ids;
for (const Building& b : m_sim->buildings().allBuildings()) for (const Building& b : m_sim->getBuildings().getAllBuildings())
{ {
for (const QPoint& cell : b.bodyCells) for (const QPoint& cell : b.bodyCells)
{ {
@@ -663,7 +663,7 @@ std::vector<BuildingId> GameWorldView::buildingsInBox(QPoint cornerA, QPoint cor
} }
} }
} }
for (const ConstructionSite& s : m_sim->buildings().allSites()) for (const ConstructionSite& s : m_sim->getBuildings().getAllSites())
{ {
for (const QPoint& cell : s.bodyCells) for (const QPoint& cell : s.bodyCells)
{ {
@@ -680,11 +680,11 @@ std::vector<BuildingId> GameWorldView::buildingsInBox(QPoint cornerA, QPoint cor
std::optional<QVector2D> GameWorldView::entityPosition(entt::entity entity) const std::optional<QVector2D> GameWorldView::entityPosition(entt::entity entity) const
{ {
if (!m_sim->admin().isValid(entity) || !m_sim->admin().hasAll<PositionComponent>(entity)) if (!m_sim->getAdmin().isValid(entity) || !m_sim->getAdmin().hasAll<PositionComponent>(entity))
{ {
return std::nullopt; return std::nullopt;
} }
return m_sim->admin().get<PositionComponent>(entity).value; return m_sim->getAdmin().get<PositionComponent>(entity).value;
} }
void GameWorldView::clearScrapSelection() void GameWorldView::clearScrapSelection()
@@ -700,7 +700,7 @@ void GameWorldView::pruneDespawnedScrap()
if (m_selectedScrap.empty()) { return; } if (m_selectedScrap.empty()) { return; }
std::vector<entt::entity> live; std::vector<entt::entity> live;
for (const ScrapInfo& info : m_sim->scraps().allScrapInfo()) for (const ScrapInfo& info : m_sim->getScraps().getAllScrapInfo())
{ {
if (std::find(m_selectedScrap.begin(), m_selectedScrap.end(), info.entity) if (std::find(m_selectedScrap.begin(), m_selectedScrap.end(), info.entity)
!= m_selectedScrap.end()) != m_selectedScrap.end())
@@ -747,7 +747,7 @@ void GameWorldView::placeBlueprintAtTile(QPoint center)
int totalCost = 0; int totalCost = 0;
for (const BlueprintBuilding& bb : bp.buildings) for (const BlueprintBuilding& bb : bp.buildings)
{ {
if (m_sim->buildings().findRotateInPlaceTarget( if (m_sim->getBuildings().findRotateInPlaceTarget(
bb.type, center + bb.offset, bb.rotation).has_value()) bb.type, center + bb.offset, bb.rotation).has_value())
{ {
continue; continue;
@@ -755,13 +755,13 @@ void GameWorldView::placeBlueprintAtTile(QPoint center)
const BuildingDef* def = findBuildingDef(bb.type); const BuildingDef* def = findBuildingDef(bb.type);
if (def) { totalCost += def->cost; } if (def) { totalCost += def->cost; }
} }
if (m_sim->buildingBlocksStock() < totalCost) { return; } if (m_sim->getBuildingBlocksStock() < totalCost) { return; }
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<BuildingId> rotateTarget = const std::optional<BuildingId> rotateTarget =
m_sim->buildings().findRotateInPlaceTarget(bb.type, anchor, bb.rotation); m_sim->getBuildings().findRotateInPlaceTarget(bb.type, anchor, bb.rotation);
if (rotateTarget.has_value()) if (rotateTarget.has_value())
{ {
std::shared_ptr<RotateInPlaceCommand> rotateCommand = std::shared_ptr<RotateInPlaceCommand> rotateCommand =
@@ -832,7 +832,7 @@ void GameWorldView::placeAtTile(QPoint tile)
} }
const std::optional<BuildingId> rotateTarget = const std::optional<BuildingId> rotateTarget =
m_sim->buildings().findRotateInPlaceTarget(type, tile, m_ghostRotation); m_sim->getBuildings().findRotateInPlaceTarget(type, tile, m_ghostRotation);
if (rotateTarget.has_value()) if (rotateTarget.has_value())
{ {
std::shared_ptr<RotateInPlaceCommand> command = std::shared_ptr<RotateInPlaceCommand> command =
@@ -853,7 +853,7 @@ void GameWorldView::placeAtTile(QPoint tile)
{ {
return; return;
} }
if (!m_sim->buildings().isTileOccupied(tile) && canAfford(type)) if (!m_sim->getBuildings().isTileOccupied(tile) && canAfford(type))
{ {
enqueuePlaceBuilding(type, tile, m_ghostRotation); enqueuePlaceBuilding(type, tile, m_ghostRotation);
m_beltDragTiles.insert(tile); m_beltDragTiles.insert(tile);
@@ -863,7 +863,7 @@ void GameWorldView::placeAtTile(QPoint tile)
|| type == BuildingType::TunnelEntry || type == BuildingType::TunnelEntry
|| type == BuildingType::TunnelExit) || type == BuildingType::TunnelExit)
{ {
if (!m_sim->buildings().isTileOccupied(tile) && canAfford(type)) if (!m_sim->getBuildings().isTileOccupied(tile) && canAfford(type))
{ {
enqueuePlaceBuilding(type, tile, m_ghostRotation); enqueuePlaceBuilding(type, tile, m_ghostRotation);
if (type == BuildingType::TunnelEntry) if (type == BuildingType::TunnelEntry)
@@ -889,7 +889,7 @@ void GameWorldView::placeAtTile(QPoint tile)
void GameWorldView::drawPortGlyph(QPainter& painter, QPoint bodyTile, void GameWorldView::drawPortGlyph(QPainter& painter, QPoint bodyTile,
Rotation direction, const QColor& color) Rotation direction, const QColor& color)
{ {
const float px = tilePx(); const float px = getTilePx();
const QRectF tr = tileRect(bodyTile); const QRectF tr = tileRect(bodyTile);
const QPointF center(tr.x() + static_cast<qreal>(px) * 0.5, const QPointF center(tr.x() + static_cast<qreal>(px) * 0.5,
tr.y() + static_cast<qreal>(px) * 0.5); tr.y() + static_cast<qreal>(px) * 0.5);
@@ -922,13 +922,13 @@ void GameWorldView::drawPortGlyph(QPainter& painter, QPoint bodyTile,
void GameWorldView::drawTiles(QPainter& painter) void GameWorldView::drawTiles(QPainter& painter)
{ {
const int leftTile = static_cast<int>(std::floor(viewLeftTiles())) - 1; const int leftTile = static_cast<int>(std::floor(getViewLeftTiles())) - 1;
const int rightTile = leftTile + static_cast<int>(std::ceil(viewportWidthTiles())) + 2; const int rightTile = leftTile + static_cast<int>(std::ceil(getViewportWidthTiles())) + 2;
const int bottomTile = m_config->world.heightTiles; const int bottomTile = m_config->world.heightTiles;
// Asteroid columns left of the buildable edge are not yet unlocked by // Asteroid columns left of the buildable edge are not yet unlocked by
// expansion; tint them so the player sees the reachable-but-locked area. // expansion; tint them so the player sees the reachable-but-locked area.
const int buildableLeftX = -m_sim->currentAsteroidWidth_tiles(); const int buildableLeftX = -m_sim->getCurrentAsteroidWidth_tiles();
painter.setPen(Qt::NoPen); painter.setPen(Qt::NoPen);
for (int x = leftTile; x <= rightTile; ++x) for (int x = leftTile; x <= rightTile; ++x)
@@ -951,7 +951,7 @@ void GameWorldView::drawTiles(QPainter& painter)
void GameWorldView::drawBuildings(QPainter& painter) void GameWorldView::drawBuildings(QPainter& painter)
{ {
for (const Building& b : m_sim->buildings().allBuildings()) for (const Building& b : m_sim->getBuildings().getAllBuildings())
{ {
const std::map<BuildingType, BuildingVisuals>::const_iterator it = const std::map<BuildingType, BuildingVisuals>::const_iterator it =
m_visuals->buildings.find(b.type); m_visuals->buildings.find(b.type);
@@ -966,8 +966,8 @@ void GameWorldView::drawBuildings(QPainter& painter)
const QPointF tl = tileToWidget(b.anchor); const QPointF tl = tileToWidget(b.anchor);
const QRectF bboxRect(tl.x(), tl.y(), const QRectF bboxRect(tl.x(), tl.y(),
b.footprint.width() * static_cast<qreal>(tilePx()), b.footprint.width() * static_cast<qreal>(getTilePx()),
b.footprint.height() * static_cast<qreal>(tilePx())); b.footprint.height() * static_cast<qreal>(getTilePx()));
painter.setPen(QPen(bv.outline, 1)); painter.setPen(QPen(bv.outline, 1));
painter.setBrush(Qt::NoBrush); painter.setBrush(Qt::NoBrush);
@@ -988,7 +988,7 @@ void GameWorldView::drawBuildings(QPainter& painter)
// HP bar below the HQ footprint; the HQ's HP lives on its proxy entity. // HP bar below the HQ footprint; the HQ's HP lives on its proxy entity.
if (b.type == BuildingType::Hq) if (b.type == BuildingType::Hq)
{ {
m_sim->admin().forEach<HqProxyComponent, FactionComponent, HealthComponent>( m_sim->getAdmin().forEach<HqProxyComponent, FactionComponent, HealthComponent>(
[&](entt::entity /*e*/, const HqProxyComponent& /*hq*/, [&](entt::entity /*e*/, const HqProxyComponent& /*hq*/,
const FactionComponent& f, const HealthComponent& h) const FactionComponent& f, const HealthComponent& h)
{ {
@@ -1002,7 +1002,7 @@ void GameWorldView::drawBuildings(QPainter& painter)
} }
painter.setOpacity(0.5); painter.setOpacity(0.5);
for (const ConstructionSite& s : m_sim->buildings().allSites()) for (const ConstructionSite& s : m_sim->getBuildings().getAllSites())
{ {
const std::map<BuildingType, BuildingVisuals>::const_iterator it = const std::map<BuildingType, BuildingVisuals>::const_iterator it =
m_visuals->buildings.find(s.type); m_visuals->buildings.find(s.type);
@@ -1016,8 +1016,8 @@ void GameWorldView::drawBuildings(QPainter& painter)
const QPointF tl = tileToWidget(s.anchor); const QPointF tl = tileToWidget(s.anchor);
const QRectF bboxRect(tl.x(), tl.y(), const QRectF bboxRect(tl.x(), tl.y(),
s.footprint.width() * static_cast<qreal>(tilePx()), s.footprint.width() * static_cast<qreal>(getTilePx()),
s.footprint.height() * static_cast<qreal>(tilePx())); s.footprint.height() * static_cast<qreal>(getTilePx()));
painter.setPen(QPen(bv.outline, 1, Qt::DashLine)); painter.setPen(QPen(bv.outline, 1, Qt::DashLine));
painter.setBrush(Qt::NoBrush); painter.setBrush(Qt::NoBrush);
painter.drawRect(bboxRect); painter.drawRect(bboxRect);
@@ -1030,7 +1030,7 @@ void GameWorldView::drawBuildings(QPainter& painter)
int pct = 0; int pct = 0;
if (s.completesAt > 0 && durationTicks > 0) if (s.completesAt > 0 && durationTicks > 0)
{ {
const Tick elapsed = m_sim->currentTick() const Tick elapsed = m_sim->getCurrentTick()
- (s.completesAt - durationTicks); - (s.completesAt - durationTicks);
pct = static_cast<int>( pct = static_cast<int>(
std::max(Tick(0), std::min(durationTicks, elapsed)) std::max(Tick(0), std::min(durationTicks, elapsed))
@@ -1079,12 +1079,12 @@ std::optional<QRectF> GameWorldView::footprintWidgetRect(BuildingId id) const
std::optional<QPoint> anchor; std::optional<QPoint> anchor;
std::optional<QSize> footprint; std::optional<QSize> footprint;
if (const Building* b = m_sim->buildings().findBuilding(id)) if (const Building* b = m_sim->getBuildings().findBuilding(id))
{ {
anchor = b->anchor; anchor = b->anchor;
footprint = b->footprint; footprint = b->footprint;
} }
else if (const ConstructionSite* s = m_sim->buildings().findSite(id)) else if (const ConstructionSite* s = m_sim->getBuildings().findSite(id))
{ {
anchor = s->anchor; anchor = s->anchor;
footprint = s->footprint; footprint = s->footprint;
@@ -1093,8 +1093,8 @@ std::optional<QRectF> GameWorldView::footprintWidgetRect(BuildingId id) const
const QPointF tl = tileToWidget(*anchor); const QPointF tl = tileToWidget(*anchor);
return QRectF(tl.x(), tl.y(), return QRectF(tl.x(), tl.y(),
footprint->width() * static_cast<qreal>(tilePx()), footprint->width() * static_cast<qreal>(getTilePx()),
footprint->height() * static_cast<qreal>(tilePx())); footprint->height() * static_cast<qreal>(getTilePx()));
} }
void GameWorldView::drawSelectionHighlights(QPainter& painter) void GameWorldView::drawSelectionHighlights(QPainter& painter)
@@ -1111,11 +1111,11 @@ void GameWorldView::drawSelectionHighlights(QPainter& painter)
} }
// A ring around each selected scrap pile, sitting just outside the pile's // A ring around each selected scrap pile, sitting just outside the pile's
// rendered circle (radius tilePx()*0.2, matching drawScrap) (REQ-UI-SCRAP-CLICK-SELECT). // rendered circle (radius getTilePx()*0.2, matching drawScrap) (REQ-UI-SCRAP-CLICK-SELECT).
if (!m_selectedScrap.empty()) if (!m_selectedScrap.empty())
{ {
const qreal outlineRadius = static_cast<qreal>(tilePx() * 0.2f) + 3.0; const qreal outlineRadius = static_cast<qreal>(getTilePx() * 0.2f) + 3.0;
for (const ScrapInfo& scrap : m_sim->scraps().allScrapInfo()) for (const ScrapInfo& scrap : m_sim->getScraps().getAllScrapInfo())
{ {
if (std::find(m_selectedScrap.begin(), m_selectedScrap.end(), scrap.entity) if (std::find(m_selectedScrap.begin(), m_selectedScrap.end(), scrap.entity)
== m_selectedScrap.end()) { continue; } == m_selectedScrap.end()) { continue; }
@@ -1136,13 +1136,13 @@ void GameWorldView::drawCopyConfigFeedback(QPainter& painter)
painter.setPen(Qt::NoPen); painter.setPen(Qt::NoPen);
painter.setBrush(color); painter.setBrush(color);
const BuildingType type = m_copiedConfig->type; const BuildingType type = m_copiedConfig->type;
for (const Building& b : m_sim->buildings().allBuildings()) for (const Building& b : m_sim->getBuildings().getAllBuildings())
{ {
if (b.type != type) { continue; } if (b.type != type) { continue; }
const std::optional<QRectF> rect = footprintWidgetRect(b.id); const std::optional<QRectF> rect = footprintWidgetRect(b.id);
if (rect.has_value()) { painter.drawRect(*rect); } if (rect.has_value()) { painter.drawRect(*rect); }
} }
for (const ConstructionSite& s : m_sim->buildings().allSites()) for (const ConstructionSite& s : m_sim->getBuildings().getAllSites())
{ {
if (s.type != type) { continue; } if (s.type != type) { continue; }
const std::optional<QRectF> rect = footprintWidgetRect(s.id); const std::optional<QRectF> rect = footprintWidgetRect(s.id);
@@ -1163,7 +1163,7 @@ void GameWorldView::drawCopyConfigFeedback(QPainter& painter)
void GameWorldView::drawPortItems(QPainter& painter) void GameWorldView::drawPortItems(QPainter& painter)
{ {
const float halfPx = tilePx() * 0.5f * 0.5f; const float halfPx = getTilePx() * 0.5f * 0.5f;
// Port items are drawn over the buildings (drawBuildings runs first) but clipped // Port items are drawn over the buildings (drawBuildings runs first) but clipped
// to a thin margin at each machine's edges: the clip region is the whole view // to a thin margin at each machine's edges: the clip region is the whole view
@@ -1174,10 +1174,10 @@ void GameWorldView::drawPortItems(QPainter& painter)
// (REQ-MAT-DIRECT-COUPLE). Transport tiles are not machines and never occlude, so // (REQ-MAT-DIRECT-COUPLE). Transport tiles are not machines and never occlude, so
// items on belts stay fully visible. // items on belts stay fully visible.
constexpr double kPortMarginTiles = 0.2; constexpr double kPortMarginTiles = 0.2;
const double margin = kPortMarginTiles * static_cast<double>(tilePx()); const double margin = kPortMarginTiles * static_cast<double>(getTilePx());
QRegion clip(rect()); QRegion clip(rect());
for (const Building& b : m_sim->buildings().allBuildings()) for (const Building& b : m_sim->getBuildings().getAllBuildings())
{ {
if (b.type == BuildingType::Belt || b.type == BuildingType::Splitter if (b.type == BuildingType::Belt || b.type == BuildingType::Splitter
|| b.type == BuildingType::TunnelEntry || b.type == BuildingType::TunnelExit) || b.type == BuildingType::TunnelEntry || b.type == BuildingType::TunnelExit)
@@ -1218,17 +1218,17 @@ void GameWorldView::drawPortItems(QPainter& painter)
painter.save(); painter.save();
painter.setClipRegion(clip); painter.setClipRegion(clip);
m_sim->buildings().forEachEmergingItem(drawItem); m_sim->getBuildings().forEachEmergingItem(drawItem);
m_sim->buildings().forEachIncomingItem(drawItem); m_sim->getBuildings().forEachIncomingItem(drawItem);
painter.restore(); painter.restore();
} }
void GameWorldView::drawBeltItems(QPainter& painter) void GameWorldView::drawBeltItems(QPainter& painter)
{ {
const float halfPx = tilePx() * 0.5f * 0.5f; const float halfPx = getTilePx() * 0.5f * 0.5f;
const QRect vr = viewportRect(); const QRect vr = getViewportRect();
m_sim->belts().forEachVisualItem(vr, [&](const VisualItem& vi) m_sim->getBelts().forEachVisualItem(vr, [&](const VisualItem& vi)
{ {
const std::map<std::string, ItemVisuals>::const_iterator it = const std::map<std::string, ItemVisuals>::const_iterator it =
m_visuals->items.find(vi.type.id); m_visuals->items.find(vi.type.id);
@@ -1248,8 +1248,8 @@ void GameWorldView::drawBeltItems(QPainter& painter)
void GameWorldView::drawScrap(QPainter& painter) void GameWorldView::drawScrap(QPainter& painter)
{ {
const float r = tilePx() * 0.2f; const float r = getTilePx() * 0.2f;
for (const ScrapInfo& scrap : m_sim->scraps().allScrapInfo()) for (const ScrapInfo& scrap : m_sim->getScraps().getAllScrapInfo())
{ {
const QPointF center = worldToWidget(scrap.position); const QPointF center = worldToWidget(scrap.position);
painter.setBrush(QColor(128, 110, 90)); painter.setBrush(QColor(128, 110, 90));
@@ -1261,7 +1261,7 @@ void GameWorldView::drawScrap(QPainter& painter)
void GameWorldView::drawStations(QPainter& painter) void GameWorldView::drawStations(QPainter& painter)
{ {
m_sim->admin().forEach<StationBodyComponent, FactionComponent, HealthComponent>( m_sim->getAdmin().forEach<StationBodyComponent, FactionComponent, HealthComponent>(
[&](entt::entity e, const StationBodyComponent& sb, const FactionComponent& f, [&](entt::entity e, const StationBodyComponent& sb, const FactionComponent& f,
const HealthComponent& h) const HealthComponent& h)
{ {
@@ -1281,8 +1281,8 @@ void GameWorldView::drawStations(QPainter& painter)
const QPointF tl = tileToWidget(QPoint(sb.anchor.x(), sb.anchor.y())); const QPointF tl = tileToWidget(QPoint(sb.anchor.x(), sb.anchor.y()));
const QRectF bboxRect(tl.x(), tl.y(), const QRectF bboxRect(tl.x(), tl.y(),
sb.footprint.width() * static_cast<qreal>(tilePx()), sb.footprint.width() * static_cast<qreal>(getTilePx()),
sb.footprint.height() * static_cast<qreal>(tilePx())); sb.footprint.height() * static_cast<qreal>(getTilePx()));
painter.setPen(QPen(bv.outline, 1)); painter.setPen(QPen(bv.outline, 1));
painter.setBrush(Qt::NoBrush); painter.setBrush(Qt::NoBrush);
@@ -1306,7 +1306,7 @@ void GameWorldView::drawStations(QPainter& painter)
void GameWorldView::drawShips(QPainter& painter) void GameWorldView::drawShips(QPainter& painter)
{ {
m_sim->admin().forEach<ShipIdentityComponent, PositionComponent, FacingComponent, m_sim->getAdmin().forEach<ShipIdentityComponent, PositionComponent, FacingComponent,
FactionComponent, HealthComponent>( FactionComponent, HealthComponent>(
[&](entt::entity e, const ShipIdentityComponent& si, [&](entt::entity e, const ShipIdentityComponent& si,
const PositionComponent& pos, const FacingComponent& facing, const PositionComponent& pos, const FacingComponent& facing,
@@ -1320,8 +1320,8 @@ void GameWorldView::drawShips(QPainter& painter)
const QVector2D dir(std::cos(facing.radians), std::sin(facing.radians)); const QVector2D dir(std::cos(facing.radians), std::sin(facing.radians));
const QVector2D perp(-dir.y(), dir.x()); const QVector2D perp(-dir.y(), dir.x());
const float fwd = tilePx() * 0.45f; const float fwd = getTilePx() * 0.45f;
const float side = tilePx() * 0.25f; const float side = getTilePx() * 0.25f;
QPolygonF tri; QPolygonF tri;
tri << QPointF(center.x() + static_cast<qreal>(dir.x() * fwd), tri << QPointF(center.x() + static_cast<qreal>(dir.x() * fwd),
@@ -1356,7 +1356,7 @@ void GameWorldView::drawShips(QPainter& painter)
void GameWorldView::drawHpBar(QPainter& painter, qreal left, qreal top, qreal width, void GameWorldView::drawHpBar(QPainter& painter, qreal left, qreal top, qreal width,
float fraction, bool isEnemy) float fraction, bool isEnemy)
{ {
const qreal barH = static_cast<qreal>(tilePx()) * 0.12; const qreal barH = static_cast<qreal>(getTilePx()) * 0.12;
const float clamped = std::max(0.0f, fraction); const float clamped = std::max(0.0f, fraction);
painter.fillRect(QRectF(left, top, width, barH), QColor(60, 60, 60)); painter.fillRect(QRectF(left, top, width, barH), QColor(60, 60, 60));
painter.fillRect(QRectF(left, top, width * static_cast<qreal>(clamped), barH), painter.fillRect(QRectF(left, top, width * static_cast<qreal>(clamped), barH),
@@ -1366,7 +1366,7 @@ void GameWorldView::drawHpBar(QPainter& painter, qreal left, qreal top, qreal wi
void GameWorldView::drawDebugSensorRanges(QPainter& painter) void GameWorldView::drawDebugSensorRanges(QPainter& painter)
{ {
painter.setBrush(Qt::NoBrush); painter.setBrush(Qt::NoBrush);
m_sim->admin().forEach<ShipIdentityComponent, PositionComponent, FacingComponent, m_sim->getAdmin().forEach<ShipIdentityComponent, PositionComponent, FacingComponent,
FactionComponent, SensorRangeComponent>( FactionComponent, SensorRangeComponent>(
[&](entt::entity /*e*/, const ShipIdentityComponent& si, [&](entt::entity /*e*/, const ShipIdentityComponent& si,
const PositionComponent& pos, const FacingComponent& /*facing*/, const PositionComponent& pos, const FacingComponent& /*facing*/,
@@ -1378,7 +1378,7 @@ void GameWorldView::drawDebugSensorRanges(QPainter& painter)
const QPointF center = worldToWidget(pos.value); const QPointF center = worldToWidget(pos.value);
const qreal radiusPx = static_cast<qreal>(sensor.value_tiles) const qreal radiusPx = static_cast<qreal>(sensor.value_tiles)
* static_cast<qreal>(tilePx()); * static_cast<qreal>(getTilePx());
QColor circleColor = it->second.outline; QColor circleColor = it->second.outline;
circleColor.setAlpha(77); circleColor.setAlpha(77);
painter.setPen(QPen(circleColor, 1)); painter.setPen(QPen(circleColor, 1));
@@ -1404,7 +1404,7 @@ void GameWorldView::drawDebugTargetLines(QPainter& painter)
painter.drawLine(worldToWidget(from), worldToWidget(to)); painter.drawLine(worldToWidget(from), worldToWidget(to));
}; };
m_sim->admin().forEach<ShipIdentityComponent, PositionComponent, AttackBehavior>( m_sim->getAdmin().forEach<ShipIdentityComponent, PositionComponent, AttackBehavior>(
[&](entt::entity /*e*/, const ShipIdentityComponent& si, [&](entt::entity /*e*/, const ShipIdentityComponent& si,
const PositionComponent& pos, const AttackBehavior& attack) const PositionComponent& pos, const AttackBehavior& attack)
{ {
@@ -1417,7 +1417,7 @@ void GameWorldView::drawDebugTargetLines(QPainter& painter)
drawTargetLine(si.schematicId, pos.value, *targetPos); drawTargetLine(si.schematicId, pos.value, *targetPos);
}); });
m_sim->admin().forEach<ShipIdentityComponent, PositionComponent, RepairBehavior>( m_sim->getAdmin().forEach<ShipIdentityComponent, PositionComponent, RepairBehavior>(
[&](entt::entity /*e*/, const ShipIdentityComponent& si, [&](entt::entity /*e*/, const ShipIdentityComponent& si,
const PositionComponent& pos, const RepairBehavior& repair) const PositionComponent& pos, const RepairBehavior& repair)
{ {
@@ -1430,7 +1430,7 @@ void GameWorldView::drawDebugTargetLines(QPainter& painter)
drawTargetLine(si.schematicId, pos.value, *targetPos); drawTargetLine(si.schematicId, pos.value, *targetPos);
}); });
m_sim->admin().forEach<ShipIdentityComponent, PositionComponent, SalvageScrapBehavior>( m_sim->getAdmin().forEach<ShipIdentityComponent, PositionComponent, SalvageScrapBehavior>(
[&](entt::entity /*e*/, const ShipIdentityComponent& si, [&](entt::entity /*e*/, const ShipIdentityComponent& si,
const PositionComponent& pos, const SalvageScrapBehavior& salvage) const PositionComponent& pos, const SalvageScrapBehavior& salvage)
{ {
@@ -1446,15 +1446,15 @@ void GameWorldView::drawDebugOverlay(QPainter& painter)
const QStringList lines = { const QStringList lines = {
tr("Accumulated Threat Level: %1") tr("Accumulated Threat Level: %1")
.arg(m_sim->threatLevel(), 0, 'f', 1), .arg(m_sim->getThreatLevel(), 0, 'f', 1),
tr("Time until Wave: %1s") tr("Time until Wave: %1s")
.arg(ticksToSeconds(m_sim->normalGapRemainingTicks()), 0, 'f', 1), .arg(ticksToSeconds(m_sim->getNormalGapRemainingTicks()), 0, 'f', 1),
tr("Threat Accumulation Rate: %1 threat/s") tr("Threat Accumulation Rate: %1 threat/s")
.arg(m_sim->threatAccumulationRate(), 0, 'f', 1), .arg(m_sim->getThreatAccumulationRate(), 0, 'f', 1),
tr("Max Factory Production: %1 threat/s") tr("Max Factory Production: %1 threat/s")
.arg(m_sim->maxFactoryProductionThreatRate(), 0, 'f', 1), .arg(m_sim->getMaxFactoryProductionThreatRate(), 0, 'f', 1),
tr("Current Factory Production: %1 threat/s") tr("Current Factory Production: %1 threat/s")
.arg(m_sim->currentFactoryProductionThreatRate(), 0, 'f', 1), .arg(m_sim->getCurrentFactoryProductionThreatRate(), 0, 'f', 1),
}; };
QFont font = painter.font(); QFont font = painter.font();
@@ -1582,12 +1582,12 @@ void GameWorldView::drawOverlays(QPainter& painter)
{ {
for (BuildingId id : buildingsInBox(m_boxStartTile, m_boxCurrentTile)) for (BuildingId id : buildingsInBox(m_boxStartTile, m_boxCurrentTile))
{ {
const Building* b = m_sim->buildings().findBuilding(id); const Building* b = m_sim->getBuildings().findBuilding(id);
if (b && b->type == BuildingType::Hq) { continue; } if (b && b->type == BuildingType::Hq) { continue; }
const std::vector<QPoint>* cells = nullptr; const std::vector<QPoint>* cells = nullptr;
const ConstructionSite* s = nullptr; const ConstructionSite* s = nullptr;
if (b) { cells = &b->bodyCells; } if (b) { cells = &b->bodyCells; }
else if ((s = m_sim->buildings().findSite(id))) { cells = &s->bodyCells; } else if ((s = m_sim->getBuildings().findSite(id))) { cells = &s->bodyCells; }
if (cells) if (cells)
{ {
for (const QPoint& cell : *cells) for (const QPoint& cell : *cells)
@@ -1599,7 +1599,7 @@ void GameWorldView::drawOverlays(QPainter& painter)
} }
else if (m_demolishMode && m_demolishHoverBuildingId != kInvalidBuildingId) else if (m_demolishMode && m_demolishHoverBuildingId != kInvalidBuildingId)
{ {
const Building* b = m_sim->buildings().findBuilding(m_demolishHoverBuildingId); const Building* b = m_sim->getBuildings().findBuilding(m_demolishHoverBuildingId);
if (b) if (b)
{ {
for (const QPoint& cell : b->bodyCells) for (const QPoint& cell : b->bodyCells)
@@ -1663,8 +1663,8 @@ void GameWorldView::drawBuildingGhost(QPainter& painter, BuildingType type,
const QPointF tl = tileToWidget(anchorTile + minCell); const QPointF tl = tileToWidget(anchorTile + minCell);
const QRectF bboxRect(tl.x(), tl.y(), const QRectF bboxRect(tl.x(), tl.y(),
(maxCell.x() - minCell.x() + 1) * static_cast<qreal>(tilePx()), (maxCell.x() - minCell.x() + 1) * static_cast<qreal>(getTilePx()),
(maxCell.y() - minCell.y() + 1) * static_cast<qreal>(tilePx())); (maxCell.y() - minCell.y() + 1) * static_cast<qreal>(getTilePx()));
painter.setPen(QPen(lineColor, 1)); painter.setPen(QPen(lineColor, 1));
painter.setBrush(Qt::NoBrush); painter.setBrush(Qt::NoBrush);
@@ -1932,7 +1932,7 @@ void GameWorldView::mousePressEvent(QMouseEvent* event)
} }
const QVector2D worldPos = widgetToWorld(event->pos()); const QVector2D worldPos = widgetToWorld(event->pos());
const entt::entity hitEntity = entityAtWorldPos(m_sim->admin(), worldPos); const entt::entity hitEntity = entityAtWorldPos(m_sim->getAdmin(), worldPos);
if (hitEntity != entt::null) if (hitEntity != entt::null)
{ {
@@ -1983,7 +1983,7 @@ void GameWorldView::mousePressEvent(QMouseEvent* event)
std::make_shared<SelectionChangedEvent>(m_selectedBuildingIds)); std::make_shared<SelectionChangedEvent>(m_selectedBuildingIds));
} }
else if (const entt::entity scrapHit = else if (const entt::entity scrapHit =
scrapAtWorldPos(m_sim->admin(), worldPos); scrapHit != entt::null) scrapAtWorldPos(m_sim->getAdmin(), worldPos); scrapHit != entt::null)
{ {
// Scrap forms its own selection category; picking it clears any // Scrap forms its own selection category; picking it clears any
// building selection (REQ-UI-SCRAP-CLICK-SELECT, REQ-UI-SCRAP-MULTI-SELECT). // building selection (REQ-UI-SCRAP-CLICK-SELECT, REQ-UI-SCRAP-MULTI-SELECT).
@@ -2081,7 +2081,7 @@ void GameWorldView::mouseReleaseEvent(QMouseEvent* event)
// (REQ-BLD-DEMOLISH, REQ-BLD-DEMOLISH-BOX). // (REQ-BLD-DEMOLISH, REQ-BLD-DEMOLISH-BOX).
for (BuildingId id : boxIds) for (BuildingId id : boxIds)
{ {
const Building* b = m_sim->buildings().findBuilding(id); const Building* b = m_sim->getBuildings().findBuilding(id);
if (b && b->type == BuildingType::Hq) { continue; } if (b && b->type == BuildingType::Hq) { continue; }
std::shared_ptr<DemolishCommand> command = std::shared_ptr<DemolishCommand> command =
std::make_shared<DemolishCommand>(); std::make_shared<DemolishCommand>();
@@ -2123,7 +2123,7 @@ void GameWorldView::mouseReleaseEvent(QMouseEvent* event)
// No buildings in the box: a scrap-only box selects the scrap it covers // No buildings in the box: a scrap-only box selects the scrap it covers
// (REQ-UI-SCRAP-MULTI-SELECT). // (REQ-UI-SCRAP-MULTI-SELECT).
const std::vector<entt::entity> boxScrap = const std::vector<entt::entity> boxScrap =
scrapInBox(m_sim->admin(), m_boxStartTile, m_boxCurrentTile); scrapInBox(m_sim->getAdmin(), m_boxStartTile, m_boxCurrentTile);
if (!boxScrap.empty()) if (!boxScrap.empty())
{ {
if (!m_selectedBuildingIds.empty()) if (!m_selectedBuildingIds.empty())
@@ -2260,7 +2260,7 @@ void GameWorldView::pasteConfigTo(BuildingId id)
{ {
// Operational splitters are configured by tile; sites by BuildingId // Operational splitters are configured by tile; sites by BuildingId
// (mirrors SelectedBuildingPanel::onSplitterFilterChanged). // (mirrors SelectedBuildingPanel::onSplitterFilterChanged).
if (const Building* building = m_sim->buildings().findBuilding(id)) if (const Building* building = m_sim->getBuildings().findBuilding(id))
{ {
std::shared_ptr<SetSplitterFiltersCommand> command = std::shared_ptr<SetSplitterFiltersCommand> command =
std::make_shared<SetSplitterFiltersCommand>(); std::make_shared<SetSplitterFiltersCommand>();
@@ -2338,7 +2338,7 @@ void GameWorldView::exitBuilderMode()
std::make_shared<BuilderModeExitedEvent>()); std::make_shared<BuilderModeExitedEvent>());
} }
double GameWorldView::gameSpeed() const double GameWorldView::getGameSpeed() const
{ {
return m_gameSpeedMultiplier; return m_gameSpeedMultiplier;
} }
@@ -2402,17 +2402,17 @@ void GameWorldView::handleEvent(std::shared_ptr<const BeamFiredEvent> event)
{ {
// Endpoint offset is a fraction of the target's visual size (REQ-SHP-FIRING-BEAM): // Endpoint offset is a fraction of the target's visual size (REQ-SHP-FIRING-BEAM):
// half a ship's rendered radius, half a station's shorter footprint side, or // half a ship's rendered radius, half a station's shorter footprint side, or
// half a scrap pile's rendered radius (scrap is drawn at tilePx()*0.2). // half a scrap pile's rendered radius (scrap is drawn at getTilePx()*0.2).
float maxRadius = 0.125f; float maxRadius = 0.125f;
if (m_sim->admin().isValid(event->target) if (m_sim->getAdmin().isValid(event->target)
&& m_sim->admin().hasAll<StationBodyComponent>(event->target)) && m_sim->getAdmin().hasAll<StationBodyComponent>(event->target))
{ {
const StationBodyComponent& sb = m_sim->admin().get<StationBodyComponent>(event->target); const StationBodyComponent& sb = m_sim->getAdmin().get<StationBodyComponent>(event->target);
const int shorter = std::min(sb.footprint.width(), sb.footprint.height()); const int shorter = std::min(sb.footprint.width(), sb.footprint.height());
maxRadius = shorter / 2.0f; maxRadius = shorter / 2.0f;
} }
else if (m_sim->admin().isValid(event->target) else if (m_sim->getAdmin().isValid(event->target)
&& m_sim->admin().hasAll<ScrapDataComponent>(event->target)) && m_sim->getAdmin().hasAll<ScrapDataComponent>(event->target))
{ {
maxRadius = 0.1f; maxRadius = 0.1f;
} }
@@ -2488,5 +2488,5 @@ bool GameWorldView::canAfford(BuildingType type) const
{ {
const BuildingDef* def = findBuildingDef(type); const BuildingDef* def = findBuildingDef(type);
if (!def) { return false; } if (!def) { return false; }
return m_sim->buildingBlocksStock() >= def->cost; return m_sim->getBuildingBlocksStock() >= def->cost;
} }

View File

@@ -76,7 +76,7 @@ public:
const ParsedReplay* replay, QWidget* parent = nullptr); const ParsedReplay* replay, QWidget* parent = nullptr);
~GameWorldView() override; ~GameWorldView() override;
double gameSpeed() const; double getGameSpeed() const;
bool isDebugDrawEnabled() const; bool isDebugDrawEnabled() const;
void resetFrameTimer(); void resetFrameTimer();
void setGameSpeed(double multiplier); void setGameSpeed(double multiplier);
@@ -133,23 +133,23 @@ private:
void drawScreenSpace(QPainter& painter); void drawScreenSpace(QPainter& painter);
void drawReplayOverlay(QPainter& painter); void drawReplayOverlay(QPainter& painter);
float tilePx() const; float getTilePx() const;
float viewportWidthTiles() const; float getViewportWidthTiles() const;
// World-X (tiles) at the left edge of the viewport. m_scrollXTiles stores the // World-X (tiles) at the left edge of the viewport. m_scrollXTiles stores the
// view center; this derives the left edge the world<->widget conversions need. // view center; this derives the left edge the world<->widget conversions need.
float viewLeftTiles() const; float getViewLeftTiles() const;
QPointF worldToWidget(QVector2D worldPos) const; QPointF worldToWidget(QVector2D worldPos) const;
QPointF tileToWidget(QPoint tile) const; QPointF tileToWidget(QPoint tile) const;
QPoint widgetToTile(QPoint widgetPt) const; QPoint widgetToTile(QPoint widgetPt) const;
QRectF tileRect(QPoint tile) const; QRectF tileRect(QPoint tile) const;
QRect viewportRect() const; QRect getViewportRect() const;
// Widget-space rectangle covering a building or construction site's footprint, // Widget-space rectangle covering a building or construction site's footprint,
// or nullopt if the id resolves to neither. Shared by the selection highlight // or nullopt if the id resolves to neither. Shared by the selection highlight
// and the copy-settings feedback (REQ-BLD-COPY-CONFIG-FEEDBACK). // and the copy-settings feedback (REQ-BLD-COPY-CONFIG-FEEDBACK).
std::optional<QRectF> footprintWidgetRect(BuildingId id) const; std::optional<QRectF> footprintWidgetRect(BuildingId id) const;
float asteroidLeftEdge() const; float getAsteroidLeftEdge() const;
float enemyStationRightEdge() const; float getEnemyStationRightEdge() const;
// Horizontal pan speed at a given view-center X, in tiles/s (REQ-UI-SCROLL-SPEED). // Horizontal pan speed at a given view-center X, in tiles/s (REQ-UI-SCROLL-SPEED).
float panSpeedTilesPerSecondAt(float viewCenterXTiles) const; float panSpeedTilesPerSecondAt(float viewCenterXTiles) const;
void clampScroll(); void clampScroll();
@@ -222,7 +222,7 @@ private:
std::mt19937 m_rng; std::mt19937 m_rng;
double m_gameSpeedMultiplier; double m_gameSpeedMultiplier;
double m_prevNonZeroSpeed; double m_prevNonZeroSpeed;
// World-X (tiles) at the center of the viewport (see viewLeftTiles()). // World-X (tiles) at the center of the viewport (see getViewLeftTiles()).
float m_scrollXTiles; float m_scrollXTiles;
QTimer* m_renderTimer; QTimer* m_renderTimer;

View File

@@ -42,9 +42,9 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir,
setWindowTitle(tr("Dota Factory")); setWindowTitle(tr("Dota Factory"));
resize(1280, 768); resize(1280, 768);
m_headerBar = new HeaderBar(&sim->config(), this); m_headerBar = new HeaderBar(&sim->getConfig(), this);
m_gameWorldView = new GameWorldView(sim, &sim->config(), &m_visuals, m_configDir, m_gameWorldView = new GameWorldView(sim, &sim->getConfig(), &m_visuals, m_configDir,
m_replay.get(), this); m_replay.get(), this);
m_sidePanel = new QWidget(this); m_sidePanel = new QWidget(this);
@@ -52,9 +52,9 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir,
sideLayout->setContentsMargins(1, 1, 1, 1); sideLayout->setContentsMargins(1, 1, 1, 1);
sideLayout->setSpacing(1); sideLayout->setSpacing(1);
m_selectedBuildingPanel = new SelectedBuildingPanel(sim, &sim->config(), m_sidePanel); m_selectedBuildingPanel = new SelectedBuildingPanel(sim, &sim->getConfig(), m_sidePanel);
m_buildButtonGrid = new BuildButtonGrid(&sim->config(), m_sidePanel); m_buildButtonGrid = new BuildButtonGrid(&sim->getConfig(), m_sidePanel);
m_blueprintPanel = new BlueprintPanel(sim, &sim->config(), m_sidePanel); m_blueprintPanel = new BlueprintPanel(sim, &sim->getConfig(), m_sidePanel);
sideLayout->addWidget(m_selectedBuildingPanel, 1); sideLayout->addWidget(m_selectedBuildingPanel, 1);
sideLayout->addWidget(m_buildButtonGrid, 1); sideLayout->addWidget(m_buildButtonGrid, 1);
@@ -158,11 +158,11 @@ void MainWindow::handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> e
void MainWindow::handleEvent(std::shared_ptr<const SchematicChoicesAvailableEvent> event) void MainWindow::handleEvent(std::shared_ptr<const SchematicChoicesAvailableEvent> event)
{ {
const double prevSpeed = m_gameWorldView->gameSpeed(); const double prevSpeed = m_gameWorldView->getGameSpeed();
m_gameWorldView->setGameSpeed(0.0); m_gameWorldView->setGameSpeed(0.0);
ModalDimScope dim(*m_dimOverlay); ModalDimScope dim(*m_dimOverlay);
SchematicChoiceDialog dialog(event->choices, m_sim->config().recipes, this); SchematicChoiceDialog dialog(event->choices, m_sim->getConfig().recipes, this);
dialog.exec(); dialog.exec();
std::shared_ptr<ApplySchematicChoiceCommand> command = std::shared_ptr<ApplySchematicChoiceCommand> command =
@@ -177,7 +177,7 @@ void MainWindow::handleEvent(std::shared_ptr<const SchematicChoicesAvailableEven
void MainWindow::handleEvent(std::shared_ptr<const EscapeMenuRequestedEvent> /*event*/) void MainWindow::handleEvent(std::shared_ptr<const EscapeMenuRequestedEvent> /*event*/)
{ {
const double prevSpeed = m_gameWorldView->gameSpeed(); const double prevSpeed = m_gameWorldView->getGameSpeed();
m_gameWorldView->setGameSpeed(0.0); m_gameWorldView->setGameSpeed(0.0);
ModalDimScope dim(*m_dimOverlay); ModalDimScope dim(*m_dimOverlay);
@@ -232,11 +232,11 @@ void MainWindow::openShipLayoutDialog(BuildingId shipyardId,
const std::string& schematicId, const std::string& schematicId,
const ShipLayoutConfig& currentLayout) const ShipLayoutConfig& currentLayout)
{ {
const double prevSpeed = m_gameWorldView->gameSpeed(); const double prevSpeed = m_gameWorldView->getGameSpeed();
m_gameWorldView->setGameSpeed(0.0); m_gameWorldView->setGameSpeed(0.0);
std::set<std::string> unlockedModuleIds; std::set<std::string> unlockedModuleIds;
for (const ModuleDef& def : m_sim->config().modules.modules) for (const ModuleDef& def : m_sim->getConfig().modules.modules)
{ {
if (m_sim->isModuleSchematicUnlocked(def.id)) if (m_sim->isModuleSchematicUnlocked(def.id))
{ {
@@ -245,17 +245,17 @@ void MainWindow::openShipLayoutDialog(BuildingId shipyardId,
} }
ModalDimScope dim(*m_dimOverlay); ModalDimScope dim(*m_dimOverlay);
ShipLayoutDialog dialog(&m_sim->config(), schematicId, currentLayout, ShipLayoutDialog dialog(&m_sim->getConfig(), schematicId, currentLayout,
m_layoutBlueprints, m_layoutBlueprints,
std::move(unlockedModuleIds), std::move(unlockedModuleIds),
m_gameWorldView->isDebugDrawEnabled(), m_gameWorldView->isDebugDrawEnabled(),
this); this);
if (dialog.exec() == QDialog::Accepted && dialog.result().has_value()) if (dialog.exec() == QDialog::Accepted && dialog.getResult().has_value())
{ {
std::shared_ptr<SetShipLayoutCommand> command = std::shared_ptr<SetShipLayoutCommand> command =
std::make_shared<SetShipLayoutCommand>(); std::make_shared<SetShipLayoutCommand>();
command->id = shipyardId; command->id = shipyardId;
command->layout = *dialog.result(); command->layout = *dialog.getResult();
EventManager::getInstance()->sendEventImmediately( EventManager::getInstance()->sendEventImmediately(
std::make_shared<CommandRequestedEvent>(command)); std::make_shared<CommandRequestedEvent>(command));
} }
@@ -268,9 +268,9 @@ void MainWindow::handleEvent(std::shared_ptr<const LayoutDialogRequestedEvent> e
{ {
// A construction site has no Building yet; fall back to its site record so // A construction site has no Building yet; fall back to its site record so
// the shipyard layout can be configured before it is built (REQ-BLD-SITE-CONFIG). // the shipyard layout can be configured before it is built (REQ-BLD-SITE-CONFIG).
const Building* b = m_sim->buildings().findBuilding(event->shipyardId); const Building* b = m_sim->getBuildings().findBuilding(event->shipyardId);
const ConstructionSite* s = const ConstructionSite* s =
b ? nullptr : m_sim->buildings().findSite(event->shipyardId); b ? nullptr : m_sim->getBuildings().findSite(event->shipyardId);
if (!b && !s) if (!b && !s)
{ {
return; return;
@@ -291,14 +291,14 @@ void MainWindow::handleEvent(std::shared_ptr<const LayoutDialogRequestedEvent> e
void MainWindow::handleEvent(std::shared_ptr<const RecipeSelectionRequestedEvent> event) void MainWindow::handleEvent(std::shared_ptr<const RecipeSelectionRequestedEvent> event)
{ {
const double prevSpeed = m_gameWorldView->gameSpeed(); const double prevSpeed = m_gameWorldView->getGameSpeed();
m_gameWorldView->setGameSpeed(0.0); m_gameWorldView->setGameSpeed(0.0);
// A construction site has no Building yet; fall back to its site record so // A construction site has no Building yet; fall back to its site record so
// the recipe/schematic can be chosen before it is built (REQ-BLD-SITE-CONFIG). // the recipe/schematic can be chosen before it is built (REQ-BLD-SITE-CONFIG).
const Building* b = m_sim->buildings().findBuilding(event->buildingId); const Building* b = m_sim->getBuildings().findBuilding(event->buildingId);
const ConstructionSite* s = const ConstructionSite* s =
b ? nullptr : m_sim->buildings().findSite(event->buildingId); b ? nullptr : m_sim->getBuildings().findSite(event->buildingId);
if (!b && !s) if (!b && !s)
{ {
m_gameWorldView->setGameSpeed(prevSpeed); m_gameWorldView->setGameSpeed(prevSpeed);
@@ -316,7 +316,7 @@ void MainWindow::handleEvent(std::shared_ptr<const RecipeSelectionRequestedEvent
// dereferenced after dialog.exec() returns. // dereferenced after dialog.exec() returns.
const std::string oldSchematic = b ? b->recipeId : s->recipeId; const std::string oldSchematic = b ? b->recipeId : s->recipeId;
const std::vector<RecipeSelectionOption> options = const std::vector<RecipeSelectionOption> options =
buildRecipeSelectionOptions(type, *m_sim, m_sim->config()); buildRecipeSelectionOptions(type, *m_sim, m_sim->getConfig());
const QString title = (type == BuildingType::Shipyard) const QString title = (type == BuildingType::Shipyard)
? tr("Select Schematic") ? tr("Select Schematic")
: tr("Select Recipe"); : tr("Select Recipe");
@@ -356,7 +356,7 @@ void MainWindow::handleEvent(std::shared_ptr<const RecipeSelectionRequestedEvent
void MainWindow::handleEvent(std::shared_ptr<const GameOverEvent> /*event*/) void MainWindow::handleEvent(std::shared_ptr<const GameOverEvent> /*event*/)
{ {
const Tick tick = m_sim->currentTick(); const Tick tick = m_sim->getCurrentTick();
const int totalSeconds = static_cast<int>(ticksToSeconds(tick)); const int totalSeconds = static_cast<int>(ticksToSeconds(tick));
const int minutes = totalSeconds / 60; const int minutes = totalSeconds / 60;
const int seconds = totalSeconds % 60; const int seconds = totalSeconds % 60;
@@ -403,7 +403,7 @@ void MainWindow::handleEvent(std::shared_ptr<const GameOverEvent> /*event*/)
void MainWindow::handleEvent(std::shared_ptr<const WinEvent> /*event*/) void MainWindow::handleEvent(std::shared_ptr<const WinEvent> /*event*/)
{ {
const Tick tick = m_sim->currentTick(); const Tick tick = m_sim->getCurrentTick();
const int totalSeconds = static_cast<int>(ticksToSeconds(tick)); const int totalSeconds = static_cast<int>(ticksToSeconds(tick));
const int minutes = totalSeconds / 60; const int minutes = totalSeconds / 60;
const int seconds = totalSeconds % 60; const int seconds = totalSeconds % 60;

View File

@@ -274,8 +274,8 @@ void SelectedBuildingPanel::buildSingle(BuildingId id)
m_singleBuildingId = id; m_singleBuildingId = id;
hideAllWidgets(); hideAllWidgets();
const Building* b = m_sim->buildings().findBuilding(id); const Building* b = m_sim->getBuildings().findBuilding(id);
const ConstructionSite* s = b ? nullptr : m_sim->buildings().findSite(id); const ConstructionSite* s = b ? nullptr : m_sim->getBuildings().findSite(id);
if (!b && !s) if (!b && !s)
{ {
buildEmpty(); buildEmpty();
@@ -353,12 +353,12 @@ void SelectedBuildingPanel::buildSingle(BuildingId id)
std::optional<BeltSystem::SplitterInfo> info; std::optional<BeltSystem::SplitterInfo> info;
if (m_singleIsSite) if (m_singleIsSite)
{ {
info = m_sim->buildings().getSiteSplitterInfo(id); info = m_sim->getBuildings().getSiteSplitterInfo(id);
} }
else else
{ {
m_splitterTile = anchor; m_splitterTile = anchor;
info = m_sim->belts().getSplitterInfo(m_splitterTile); info = m_sim->getBelts().getSplitterInfo(m_splitterTile);
} }
buildSplitterFilters(info); buildSplitterFilters(info);
} }
@@ -397,7 +397,7 @@ void SelectedBuildingPanel::refreshSiteProgress(const ConstructionSite* s)
if (def && def->constructionTimeSeconds > 0) if (def && def->constructionTimeSeconds > 0)
{ {
const Tick duration = secondsToTicks(def->constructionTimeSeconds); const Tick duration = secondsToTicks(def->constructionTimeSeconds);
const Tick elapsed = m_sim->currentTick() - (s->completesAt - duration); const Tick elapsed = m_sim->getCurrentTick() - (s->completesAt - duration);
const int pct = static_cast<int>( const int pct = static_cast<int>(
std::max(Tick(0), std::min(duration, elapsed)) * 100 / duration); std::max(Tick(0), std::min(duration, elapsed)) * 100 / duration);
progress = tr("%1% complete").arg(pct); progress = tr("%1% complete").arg(pct);
@@ -554,7 +554,7 @@ void SelectedBuildingPanel::refreshBuffers(const Building* b)
{ {
const Tick cycleTicks = secondsToTicks(durationSeconds); const Tick cycleTicks = secondsToTicks(durationSeconds);
const Tick completesAt = b->production->completesAt; const Tick completesAt = b->production->completesAt;
const Tick currentTick = m_sim->currentTick(); const Tick currentTick = m_sim->getCurrentTick();
const Tick elapsed = currentTick - (completesAt - cycleTicks); const Tick elapsed = currentTick - (completesAt - cycleTicks);
const int pct = static_cast<int>( const int pct = static_cast<int>(
std::max(Tick(0), std::min(cycleTicks, elapsed)) * 100 / cycleTicks); std::max(Tick(0), std::min(cycleTicks, elapsed)) * 100 / cycleTicks);
@@ -673,7 +673,7 @@ void SelectedBuildingPanel::refreshSelectionDisplay(RefreshReason reason)
} }
if (m_singleBuildingId == kInvalidBuildingId) { return; } if (m_singleBuildingId == kInvalidBuildingId) { return; }
const Building* b = m_sim->buildings().findBuilding(m_singleBuildingId); const Building* b = m_sim->getBuildings().findBuilding(m_singleBuildingId);
if (b) if (b)
{ {
if (m_titleLabel->text().startsWith(tr("(Building) "))) if (m_titleLabel->text().startsWith(tr("(Building) ")))
@@ -686,7 +686,7 @@ void SelectedBuildingPanel::refreshSelectionDisplay(RefreshReason reason)
} }
return; return;
} }
const ConstructionSite* s = m_sim->buildings().findSite(m_singleBuildingId); const ConstructionSite* s = m_sim->getBuildings().findSite(m_singleBuildingId);
if (s) if (s)
{ {
// A periodic tick only advances construction progress, so update just the // A periodic tick only advances construction progress, so update just the
@@ -720,13 +720,13 @@ void SelectedBuildingPanel::buildMulti(const std::vector<BuildingId>& ids)
std::map<BuildingType, int> counts; std::map<BuildingType, int> counts;
for (BuildingId id : ids) for (BuildingId id : ids)
{ {
const Building* b = m_sim->buildings().findBuilding(id); const Building* b = m_sim->getBuildings().findBuilding(id);
if (b) if (b)
{ {
counts[b->type]++; counts[b->type]++;
continue; continue;
} }
const ConstructionSite* s = m_sim->buildings().findSite(id); const ConstructionSite* s = m_sim->getBuildings().findSite(id);
if (s) if (s)
{ {
counts[s->type]++; counts[s->type]++;
@@ -791,7 +791,7 @@ void SelectedBuildingPanel::buildSplitterFilters(
return; return;
} }
const std::vector<std::string> items = allItemIds(); const std::vector<std::string> items = getAllItemIds();
auto populateList = [&](QListWidget* list, QLabel* label, auto populateList = [&](QListWidget* list, QLabel* label,
const QString& dirLabel, const QString& dirLabel,
@@ -866,7 +866,7 @@ void SelectedBuildingPanel::onSplitterFilterChanged()
} }
} }
std::vector<std::string> SelectedBuildingPanel::allItemIds() const std::vector<std::string> SelectedBuildingPanel::getAllItemIds() const
{ {
std::set<std::string> seen; std::set<std::string> seen;
for (const RecipeDef& recipe : m_config->recipes.recipes) for (const RecipeDef& recipe : m_config->recipes.recipes)
@@ -888,7 +888,7 @@ void SelectedBuildingPanel::onClearBelt()
std::vector<QPoint> tiles; std::vector<QPoint> tiles;
for (BuildingId id : m_selectedBuildingIds) for (BuildingId id : m_selectedBuildingIds)
{ {
const Building* b = m_sim->buildings().findBuilding(id); const Building* b = m_sim->getBuildings().findBuilding(id);
if (b && isBeltLike(b->type)) if (b && isBeltLike(b->type))
{ {
for (const QPoint& cell : b->bodyCells) for (const QPoint& cell : b->bodyCells)
@@ -918,7 +918,7 @@ void SelectedBuildingPanel::handleEvent(std::shared_ptr<const EntitySelectedEven
m_scrapLabel->hide(); m_scrapLabel->hide();
clearContent(); clearContent();
EntityAdmin& admin = m_sim->admin(); EntityAdmin& admin = m_sim->getAdmin();
entt::entity entity = *m_selectedEntity; entt::entity entity = *m_selectedEntity;
if (!admin.isValid(entity)) if (!admin.isValid(entity))
@@ -944,7 +944,7 @@ void SelectedBuildingPanel::handleEvent(std::shared_ptr<const EntitySelectedEven
void SelectedBuildingPanel::buildEntityShip(entt::entity entity) void SelectedBuildingPanel::buildEntityShip(entt::entity entity)
{ {
EntityAdmin& admin = m_sim->admin(); EntityAdmin& admin = m_sim->getAdmin();
const ShipIdentityComponent& identity = admin.get<ShipIdentityComponent>(entity); const ShipIdentityComponent& identity = admin.get<ShipIdentityComponent>(entity);
const HealthComponent& health = admin.get<HealthComponent>(entity); const HealthComponent& health = admin.get<HealthComponent>(entity);
@@ -976,7 +976,7 @@ void SelectedBuildingPanel::buildEntityShip(entt::entity entity)
void SelectedBuildingPanel::buildEntityStation(entt::entity entity) void SelectedBuildingPanel::buildEntityStation(entt::entity entity)
{ {
EntityAdmin& admin = m_sim->admin(); EntityAdmin& admin = m_sim->getAdmin();
const HealthComponent& health = admin.get<HealthComponent>(entity); const HealthComponent& health = admin.get<HealthComponent>(entity);
const bool isEnemy = admin.hasAll<FactionComponent>(entity) const bool isEnemy = admin.hasAll<FactionComponent>(entity)
@@ -1019,7 +1019,7 @@ void SelectedBuildingPanel::refreshEntityStats()
{ {
if (!m_selectedEntity.has_value()) { return; } if (!m_selectedEntity.has_value()) { return; }
EntityAdmin& admin = m_sim->admin(); EntityAdmin& admin = m_sim->getAdmin();
entt::entity entity = *m_selectedEntity; entt::entity entity = *m_selectedEntity;
if (!admin.isValid(entity)) if (!admin.isValid(entity))
@@ -1098,7 +1098,7 @@ void SelectedBuildingPanel::refreshScrapTotal()
{ {
// Sum the remaining amounts of the still-living selected piles (REQ-UI-SCRAP-PANEL). // Sum the remaining amounts of the still-living selected piles (REQ-UI-SCRAP-PANEL).
int total = 0; int total = 0;
for (const ScrapInfo& info : m_sim->scraps().allScrapInfo()) for (const ScrapInfo& info : m_sim->getScraps().getAllScrapInfo())
{ {
if (std::find(m_selectedScrap.begin(), m_selectedScrap.end(), info.entity) if (std::find(m_selectedScrap.begin(), m_selectedScrap.end(), info.entity)
!= m_selectedScrap.end()) != m_selectedScrap.end())

View File

@@ -90,7 +90,7 @@ private:
void buildSplitterFilters(const std::optional<BeltSystem::SplitterInfo>& info); void buildSplitterFilters(const std::optional<BeltSystem::SplitterInfo>& info);
const RecipeDef* findRecipe(const Building* b) const; const RecipeDef* findRecipe(const Building* b) const;
const ShipDef* findShipDef(const std::string& id) const; const ShipDef* findShipDef(const std::string& id) const;
std::vector<std::string> allItemIds() const; std::vector<std::string> getAllItemIds() const;
Simulation* m_sim; Simulation* m_sim;
const GameConfig* m_config; const GameConfig* m_config;

View File

@@ -578,7 +578,7 @@ ShipLayoutDialog::ShipLayoutDialog(const GameConfig* config,
}); });
} }
std::optional<ShipLayoutConfig> ShipLayoutDialog::result() const std::optional<ShipLayoutConfig> ShipLayoutDialog::getResult() const
{ {
return m_result; return m_result;
} }

View File

@@ -30,7 +30,7 @@ public:
bool debugDraw, bool debugDraw,
QWidget* parent = nullptr); QWidget* parent = nullptr);
std::optional<ShipLayoutConfig> result() const; std::optional<ShipLayoutConfig> getResult() const;
protected: protected:
void keyPressEvent(QKeyEvent* event) override; void keyPressEvent(QKeyEvent* event) override;