share BuildingSystem's free functions instead of copying them

This commit is contained in:
2026-08-04 18:24:38 +02:00
parent bd344e4fbe
commit 3990351a16
7 changed files with 80 additions and 85 deletions

View File

@@ -38,3 +38,17 @@ std::string buildingTypeId(BuildingType type)
} }
return ""; return "";
} }
bool isAutoRecipeBuildingType(BuildingType type)
{
return type == BuildingType::Smelter
|| type == BuildingType::ReprocessingPlant;
}
bool isBeltSubsystemType(BuildingType type)
{
return type == BuildingType::Belt
|| type == BuildingType::Splitter
|| type == BuildingType::TunnelEntry
|| type == BuildingType::TunnelExit;
}

View File

@@ -29,3 +29,13 @@ std::optional<BuildingType> parseBuildingType(const std::string& id);
// Canonical id string for a BuildingType. The inverse of parseBuildingType. // Canonical id string for a BuildingType. The inverse of parseBuildingType.
std::string buildingTypeId(BuildingType type); std::string buildingTypeId(BuildingType type);
// Smelter and Reprocessing Plant have no player-selected recipe
// (REQ-BLD-SMELTER, REQ-BLD-REPROCESSING). They auto-process whatever inputs
// they receive, matching against every recipe of their building type.
bool isAutoRecipeBuildingType(BuildingType type);
// Belts, splitters, and tunnel ends keep their runtime data in the belt subsystem
// rather than in the Building instance, so placing/removing them must register or
// unregister a tile with BeltSystem.
bool isBeltSubsystemType(BuildingType type);

View File

@@ -9,6 +9,7 @@ SET(HDRS
${CMAKE_CURRENT_SOURCE_DIR}/ItemType.h ${CMAKE_CURRENT_SOURCE_DIR}/ItemType.h
${CMAKE_CURRENT_SOURCE_DIR}/Item.h ${CMAKE_CURRENT_SOURCE_DIR}/Item.h
${CMAKE_CURRENT_SOURCE_DIR}/Port.h ${CMAKE_CURRENT_SOURCE_DIR}/Port.h
${CMAKE_CURRENT_SOURCE_DIR}/PortGeometry.h
${CMAKE_CURRENT_SOURCE_DIR}/SchematicChoiceOption.h ${CMAKE_CURRENT_SOURCE_DIR}/SchematicChoiceOption.h
${CMAKE_CURRENT_SOURCE_DIR}/DisplayName.h ${CMAKE_CURRENT_SOURCE_DIR}/DisplayName.h
${CMAKE_CURRENT_SOURCE_DIR}/BeltDragPath.h ${CMAKE_CURRENT_SOURCE_DIR}/BeltDragPath.h

View File

@@ -0,0 +1,45 @@
#pragma once
#include <QPoint>
#include "Rotation.h"
// Geometry of a building's input/output ports. A Port names the tile *outside* the
// building together with the direction items flow across it; these helpers give the
// building body tile on the other side of that edge, which is where the virtual
// input/output belt lives.
//
// Shared by the simulation (which moves items across the edge) and the renderer
// (which draws the virtual belt), so the two cannot disagree about which tile a
// port belongs to.
// The building body tile that owns an output port, given the port's outside tile
// (port.tile) and its facing direction. The virtual output belt occupies this tile
// and flows toward port.tile (REQ-MAT-OUTPUT-EMERGE).
inline QPoint outputBodyTile(QPoint portTile, Rotation direction)
{
switch (direction)
{
case Rotation::East: return portTile + QPoint(-1, 0);
case Rotation::West: return portTile + QPoint( 1, 0);
case Rotation::North: return portTile + QPoint( 0, 1);
case Rotation::South: return portTile + QPoint( 0, -1);
}
return portTile;
}
// The building body tile an input port feeds into, given the port's outside belt
// tile (port.tile) and its inward flow direction. The virtual input belt occupies
// this tile and flows from the outer edge (progress 0.0) to the centre (0.5)
// (REQ-MAT-INPUT-INTAKE).
inline QPoint inputBodyTile(QPoint portTile, Rotation inwardDirection)
{
switch (inwardDirection)
{
case Rotation::East: return portTile + QPoint( 1, 0);
case Rotation::West: return portTile + QPoint(-1, 0);
case Rotation::North: return portTile + QPoint( 0, -1);
case Rotation::South: return portTile + QPoint( 0, 1);
}
return portTile;
}

View File

@@ -6,63 +6,13 @@
#include <random> #include <random>
#include <set> #include <set>
#include "PortGeometry.h"
#include "StateChecksum.h" #include "StateChecksum.h"
#include "SurfaceMask.h" #include "SurfaceMask.h"
#include "tracing.h" #include "tracing.h"
namespace namespace
{ {
// Smelter and Reprocessing Plant have no player-selected recipe
// (REQ-BLD-SMELTER, REQ-BLD-REPROCESSING). They auto-process whatever inputs
// they receive, matching against every recipe of their building type.
bool isAutoRecipeBuildingType(BuildingType type)
{
return type == BuildingType::Smelter
|| type == BuildingType::ReprocessingPlant;
}
// Belts, splitters, and tunnel ends keep their runtime data in the belt subsystem
// rather than in the Building instance, so placing/removing them must register or
// unregister a tile with BeltSystem.
bool isBeltSubsystemType(BuildingType type)
{
return type == BuildingType::Belt
|| type == BuildingType::Splitter
|| type == BuildingType::TunnelEntry
|| type == BuildingType::TunnelExit;
}
// The building body tile that owns an output port, given the port's outside tile
// (port.tile) and its facing direction. The virtual output belt occupies this tile
// and flows toward port.tile (REQ-MAT-OUTPUT-EMERGE).
QPoint outputBodyTile(QPoint portTile, Rotation direction)
{
switch (direction)
{
case Rotation::East: return portTile + QPoint(-1, 0);
case Rotation::West: return portTile + QPoint( 1, 0);
case Rotation::North: return portTile + QPoint( 0, 1);
case Rotation::South: return portTile + QPoint( 0, -1);
}
return portTile;
}
// The building body tile an input port feeds into, given the port's outside belt
// tile (port.tile) and its inward flow direction. The virtual input belt occupies
// this tile and flows from the outer edge (progress 0.0) to the centre (0.5)
// (REQ-MAT-INPUT-INTAKE).
QPoint inputBodyTile(QPoint portTile, Rotation inwardDirection)
{
switch (inwardDirection)
{
case Rotation::East: return portTile + QPoint( 1, 0);
case Rotation::West: return portTile + QPoint(-1, 0);
case Rotation::North: return portTile + QPoint( 0, -1);
case Rotation::South: return portTile + QPoint( 0, 1);
}
return portTile;
}
// An input belt accepts a new item at progress 0.0 only when it holds fewer than // An input belt accepts a new item at progress 0.0 only when it holds fewer than
// three items and the entry slot is clear (nothing within a quarter tile of 0.0), // three items and the entry slot is clear (nothing within a quarter tile of 0.0),
// matching the belt packing used elsewhere (REQ-GW-BELT-CAPACITY). // matching the belt packing used elsewhere (REQ-GW-BELT-CAPACITY).

View File

@@ -50,6 +50,7 @@
#include "HealthComponent.h" #include "HealthComponent.h"
#include "HqProxyComponent.h" #include "HqProxyComponent.h"
#include "ItemIconCache.h" #include "ItemIconCache.h"
#include "PortGeometry.h"
#include "PositionComponent.h" #include "PositionComponent.h"
#include "RepairBehavior.h" #include "RepairBehavior.h"
#include "SalvageScrapBehavior.h" #include "SalvageScrapBehavior.h"
@@ -166,18 +167,6 @@ Rotation rotateCounterClockwise(Rotation r)
return Rotation::East; return Rotation::East;
} }
QPoint portBodyTile(QPoint portTile, Rotation direction)
{
switch (direction)
{
case Rotation::East: return portTile + QPoint(-1, 0);
case Rotation::West: return portTile + QPoint( 1, 0);
case Rotation::North: return portTile + QPoint( 0, 1);
case Rotation::South: return portTile + QPoint( 0, -1);
}
return portTile;
}
// Fill color for a building's status light per its production state // Fill color for a building's status light per its production state
// (REQ-UI-STATUS-LIGHT). // (REQ-UI-STATUS-LIGHT).
QColor statusLightFill(ProductionStatus status, const StatusLightVisuals& sl) QColor statusLightFill(ProductionStatus status, const StatusLightVisuals& sl)
@@ -1341,7 +1330,7 @@ void GameWorldView::drawBuildings(QPainter& painter)
for (const Port& port : b.outputPorts) for (const Port& port : b.outputPorts)
{ {
drawPortGlyph(painter, portBodyTile(port.tile, port.direction), drawPortGlyph(painter, outputBodyTile(port.tile, port.direction),
port.direction, bv.outline, /*centered*/ false); port.direction, bv.outline, /*centered*/ false);
} }
@@ -1441,7 +1430,7 @@ void GameWorldView::drawBuildings(QPainter& painter)
for (const Port& port : siteMask.outputPorts) for (const Port& port : siteMask.outputPorts)
{ {
const QPoint absBody = s.anchor const QPoint absBody = s.anchor
+ portBodyTile(port.tile, port.direction); + outputBodyTile(port.tile, port.direction);
drawPortGlyph(painter, absBody, port.direction, bv.outline, drawPortGlyph(painter, absBody, port.direction, bv.outline,
/*centered*/ false); /*centered*/ false);
} }
@@ -2215,7 +2204,7 @@ void GameWorldView::drawBuildingGhost(QPainter& painter, BuildingType type,
for (const Port& port : parsed.outputPorts) for (const Port& port : parsed.outputPorts)
{ {
drawPortGlyph(painter, anchorTile + portBodyTile(port.tile, port.direction), drawPortGlyph(painter, anchorTile + outputBodyTile(port.tile, port.direction),
port.direction, lineColor, /*centered*/ false); port.direction, lineColor, /*centered*/ false);
} }

View File

@@ -84,20 +84,6 @@ bool hasRecipeSelection(BuildingType type)
|| type == BuildingType::Shipyard; || type == BuildingType::Shipyard;
} }
// Auto-recipe buildings have no selected recipe; their production is driven by
// whatever inputs they receive.
bool isAutoRecipeBuilding(BuildingType type)
{
return type == BuildingType::Smelter
|| type == BuildingType::ReprocessingPlant;
}
bool isBeltLike(BuildingType type)
{
return type == BuildingType::Belt || type == BuildingType::Splitter
|| type == BuildingType::TunnelEntry || type == BuildingType::TunnelExit;
}
QString rotationLabel(Rotation r) QString rotationLabel(Rotation r)
{ {
switch (r) switch (r)
@@ -313,7 +299,7 @@ void SelectedBuildingPanel::buildSingle(BuildingId id)
// Belt "Clear" removes items from a live belt tile; a construction site has // Belt "Clear" removes items from a live belt tile; a construction site has
// none and is not registered with BeltSystem yet, so hide it for sites. // none and is not registered with BeltSystem yet, so hide it for sites.
if (isBeltLike(type) && !m_singleIsSite) if (isBeltSubsystemType(type) && !m_singleIsSite)
{ {
m_clearBeltBtn->show(); m_clearBeltBtn->show();
} }
@@ -394,7 +380,7 @@ void SelectedBuildingPanel::refreshBuffers(const Building* b)
// Auto-recipe buildings (Smelter, Reprocessing Plant) have no selected // Auto-recipe buildings (Smelter, Reprocessing Plant) have no selected
// recipe; while a cycle runs, resolve the recipe actually in production so // recipe; while a cycle runs, resolve the recipe actually in production so
// the cycle time and progress can be shown (REQ-UI-PRODUCTION-PROGRESS). // the cycle time and progress can be shown (REQ-UI-PRODUCTION-PROGRESS).
if (!recipe && isAutoRecipeBuilding(b->type) && b->production.has_value()) if (!recipe && isAutoRecipeBuildingType(b->type) && b->production.has_value())
{ {
recipe = m_config->recipes.findRecipeDef(b->production->recipeId, b->type); recipe = m_config->recipes.findRecipeDef(b->production->recipeId, b->type);
} }
@@ -488,7 +474,7 @@ void SelectedBuildingPanel::refreshBuffers(const Building* b)
} }
if (isProductionBuilding(b->type) if (isProductionBuilding(b->type)
&& (recipe || shipDef || isAutoRecipeBuilding(b->type))) && (recipe || shipDef || isAutoRecipeBuildingType(b->type)))
{ {
if (recipe || shipDef) if (recipe || shipDef)
{ {
@@ -683,7 +669,7 @@ void SelectedBuildingPanel::buildMulti(const std::vector<BuildingId>& ids)
{ {
text += buildingTypeName(entry.first) + " x " text += buildingTypeName(entry.first) + " x "
+ QString::number(entry.second) + "\n"; + QString::number(entry.second) + "\n";
if (isBeltLike(entry.first)) if (isBeltSubsystemType(entry.first))
{ {
hasBelt = true; hasBelt = true;
} }
@@ -832,7 +818,7 @@ void SelectedBuildingPanel::onClearBelt()
for (BuildingId id : m_selectedBuildingIds) for (BuildingId id : m_selectedBuildingIds)
{ {
const Building* b = m_sim->getBuildings().findBuilding(id); const Building* b = m_sim->getBuildings().findBuilding(id);
if (b && isBeltLike(b->type)) if (b && isBeltSubsystemType(b->type))
{ {
for (const QPoint& cell : b->bodyCells) for (const QPoint& cell : b->bodyCells)
{ {