Commit Graph

358 Commits

Author SHA1 Message Date
2c9433cea6 move the shared TOML helpers into the utility namespace
The names are generic (makeError, requireInt, parseFile), and at global scope
with external linkage they would form an overload set with the same-named
anonymous-namespace helpers in VisualsLoader.cpp and BalancingConfig.cpp the
moment either file includes TomlHelpers.h — silently, since the signatures
differ. Namespacing keeps that door shut.

Call sites are qualified explicitly rather than pulled in with a using
directive, matching how utility::getRandomInt and friends are already called.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
2026-08-04 09:27:43 +02:00
21eb6ad096 extract loadUnlocks into ConfigLoaderUnlocks.cpp
Finishes the ConfigLoader.cpp domain split. ConfigLoader.cpp now holds
only the cross-domain validateUnlocks pass and loadFromDirectory
orchestrator, as intended — everything else lives in its own
ConfigLoader<Domain>.cpp. Pure move; no logic change.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
2026-08-03 22:38:10 +02:00
bf579bb76e extract loadModules into ConfigLoaderModules.cpp
Continues the ConfigLoader.cpp domain split. StatEntry/kKnownStats are
only used by loadModules, so they move along as a domain-local
anonymous-namespace table rather than into TomlHelpers. Pure move; no
logic change.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
2026-08-03 22:36:08 +02:00
6bde69dc33 extract loadStations into ConfigLoaderStations.cpp
Continues the ConfigLoader.cpp domain split. Pure move of loadStations;
no domain-specific helpers to relocate here.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
2026-08-03 22:33:40 +02:00
bf99cd0694 extract loadShips into ConfigLoaderShips.cpp
Continues the ConfigLoader.cpp domain split. parseRotationString and
parsePlacedModules are only used by loadShips, so they move along as
domain-local anonymous-namespace helpers rather than into TomlHelpers.
Pure move; no logic change.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
2026-08-03 22:31:39 +02:00
6f107e3479 extract loadRecipes into ConfigLoaderRecipes.cpp
Continues the ConfigLoader.cpp domain split. parseRecipeOutputs is only
used by loadRecipes, so it moves along as a domain-local anonymous-
namespace helper rather than into TomlHelpers. Pure move; no logic
change.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
2026-08-03 22:29:17 +02:00
8f42519911 extract loadBuildings into ConfigLoaderBuildings.cpp
Continues the ConfigLoader.cpp domain split. Pure move of loadBuildings;
no domain-specific helpers to relocate here.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
2026-08-03 22:27:05 +02:00
bb7b90f9ea extract loadWorld into ConfigLoaderWorld.cpp
Continues the ConfigLoader.cpp domain split: world.toml parsing has no
domain-specific helpers of its own, so this is a straight move of
loadWorld with no logic change.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
2026-08-03 22:25:14 +02:00
e702c01005 extract shared TOML helpers into TomlHelpers.h/.cpp
ConfigLoader.cpp had grown to 877 lines by mixing generic TOML-parsing
helpers (used by every per-file loader) with per-domain parsing logic.
Splitting the file per config domain first requires pulling out the
helpers shared by two or more domains, so each domain .cpp can include
them without duplication. Pure move: no logic, message, or ordering
changes.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
2026-08-03 22:22:48 +02:00
b1720dc2b3 drop the now-dead payloads from the sim-backed state-change events
TickAdvanced, BuildingBlocksChanged, ExpansionCostChanged, BossWaveUpdated and
ArtifactCountChanged all duplicated state the Simulation already owns. With
every subscriber re-reading from the sim, the fields had no readers left, so
the five events become payload-free refresh signals and the emitters keep the
values only as locals for change detection.

This makes the convention uniform: a state-change event backed by the
simulation carries nothing. Events whose state lives in the view (selection,
game speed, deconstruct and debug-draw modes) keep their payloads, since there
is no sim getter behind them.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
2026-08-03 21:56:47 +02:00
099f0b55fc make HeaderBar read the tick, artifacts and boss wave from the simulation
The last three payloads HeaderBar still consumed as truth. All are backed by
Simulation getters (getCurrentTick, getArtifactCount, getBossWaveCounter,
getBossCountdownTicks) and the win count by world.artifacts.artifactWinCount,
so the handlers now re-read rather than trust the event.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
2026-08-03 21:54:02 +02:00
b133a21914 make BlueprintPanel read the block stock from the simulation
BlueprintPanel was the second panel caching BuildingBlocksChangedEvent's
payload as truth; it already held a Simulation*, so refreshButtonStates()
now re-reads getBuildingBlocksStock() at the point of use, per the "events
are refresh signals" rule.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
2026-08-03 21:53:19 +02:00
69848eb9f8 remove the last duplicate findModuleDef from ShipLayoutPreview
ShipLayoutPreview was the one widget the findFooDef sweep missed: it held a
bare const std::vector<ModuleDef>* rather than a config, so the shared
ModulesConfig::findModuleDef was not a drop-in and the file-local copy
survived. Hold the ModulesConfig instead and call the shared finder.

The sole caller already had the ModulesConfig one dereference away.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHcUerKAZKWNvSKJxYKbnG
2026-08-03 21:28:53 +02:00
993325d97c remove duplicate findBuildingDef from BuildingSystem
BuildingSystem::findBuildingDef was a byte-equivalent re-implementation of
BuildingsConfig::findBuildingDef. Same cleanup as the GameWorldView copy;
this one sits in the sim layer, so it was missed by both earlier passes.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 21:34:24 +02:00
75f306f650 route the win-path restart through ResetCommand
The Restart button on the Win dialog called Simulation::reset() directly,
while the escape-menu and Game Over restarts enqueue a ResetCommand. That
bypassed the command chokepoint every sim mutation is supposed to flow
through (docs/replay_design.md), so a post-win restart was never recorded
into the replay stream, and it had UI code calling a sim mutator directly.

Mirror the Game Over path instead. The manual resetForNewGame() call goes
away with it: GameWorldView::onFrame already resets the view when it drains
a Reset command.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 21:31:27 +02:00
0eb9c97e5d dedupe AttackExecutor and RepairExecutor via executeOrbitAndAssign
The two executors were line-for-line duplicates: orbit the behavior target,
then hand it to the owner's in-range modules. Both now call a templated
executeOrbitAndAssign<Behavior, ModuleComponent>; the view types, iteration
order, and sequence of component writes are unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 21:16:15 +02:00
28d0416458 add ModalPauseScope for the pause-around-modal idiom
Four MainWindow sites hand-rolled snapshot speed / setGameSpeed(0) / modal /
restore + resetFrameTimer, with the restore duplicated on early-return paths.
ModalPauseScope does it via RAII, with restore()/release() for the two sites
that must restore early or not at all.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 21:12:53 +02:00
59fde8dbbc extract MainWindow::reloadConfig
The three restart paths each repeated the same config + visuals reload with
its own try/catch and error dialog. Only that shared part is extracted; each
site keeps its own follow-up (ResetCommand vs. direct Simulation::reset) and
its own error-path cleanup.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 21:06:41 +02:00
5355f9f77d drop EntityAdmin::add in favour of addComponent
The private add<T> template was identical to the public addComponent<T>;
the spawn factory methods now use the public one.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 21:04:03 +02:00
f678dab387 share a single ItemIconCache across the UI
Four separate caches rasterized the same item SVGs, one of them rebuilt on
every recipe-dialog open. MainWindow now owns one cache and hands a
non-owning pointer to HeaderBar, BuildButtonGrid, GameWorldView and
RecipeSelectionDialog.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 21:00:19 +02:00
ebee62166d lift the shared Centroid helper into ai/Centroid.h
AdvanceExecutor and StandbyExecutor each carried a verbatim copy of the
struct in an anonymous namespace; it now sits next to OrbitMath.h.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 20:55:29 +02:00
3c549a160c share one loadTestConfig() helper across the tests
19 test translation units each defined an identical local loadConfig().
They now include src/test/TestConfig.h, which lives off the lib/ui/app
include path like SimulationTestAccess.h.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 20:53:21 +02:00
dc58f6ea32 make HeaderBar read block stock and expansion cost from the simulation
HeaderBar was the only panel caching event payloads as truth. It now holds
a const Simulation* and re-reads getBuildingBlocksStock() /
getCurrentExpansionCost() in the handlers, per the "events are refresh
signals" rule.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 20:49:38 +02:00
5bd804601c dedupe tunnel lookup and key tunnel tiles by QPoint
The identical 7-line TunnelLookup lambda existed in updateTunnelGhost and
drawSelectedTunnelConnections; it is now GameWorldView::makeTunnelLookup.
The tile key moved from std::pair<int, int> to QPoint with the existing
QPointCompare comparator, dropping the manual packing at every site.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 20:47:28 +02:00
92a4f02cef extract Simulation::initializeSubsystems
The constructor and reset() held a character-for-character identical
26-line subsystem construction block, including three capturing lambdas.
Both run before the first tick, so the closures can be shared. Order is
unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 20:44:43 +02:00
84d32b6c16 add findShipDef/findModuleDef/findRecipeDef to config structs
Ships/Modules/RecipesConfig now carry lookup helpers mirroring
BuildingsConfig::findBuildingDef. The hand-rolled linear scans in
BuildingSystem, ShipSystem, ShipStatsCalculator, ThreatCostCalculator,
ShipLayoutDialog, SelectedBuildingPanel and SchematicChoiceDialog now
call them instead.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 20:42:24 +02:00
d31ff68ab7 remove duplicate findBuildingDef from GameWorldView
GameWorldView::findBuildingDef was a byte-equivalent re-implementation of
BuildingsConfig::findBuildingDef. All call sites now use the config helper,
matching SelectedBuildingPanel and BlueprintPanel.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 20:34:56 +02:00
b722955f7e fix splitter filters being lost when rotating in place
rotateInPlace re-implemented the belt-tile re-registration switch inline
instead of calling reregisterBeltTile, and its splitter branch omitted the
setSplitterFilters call the canonical version has. Since an operational
splitter keeps its filters only in BeltSystem, removeTile discarded them and
rotating a configured splitter silently reset it to "accept all".

Replace the duplicated switch with a call to reregisterBeltTile, capturing
the filters beforehand via getSplitterInfo — the same idiom deconstruct
already uses. This removes the second copy of the switch that allowed the
two to drift apart in the first place.

Add a regression test; the existing [rotate-in-place] cases covered belt
tiles only, which is why this went unnoticed.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GH8ZMRY3vhxxXcaUxBqxkk
2026-08-02 20:22:53 +02:00
370a3036c1 fix issue where HP bar is drawn below belts 2026-08-02 15:57:44 +02:00
f60f111ccc move claude project files into git repo 2026-08-02 15:57:26 +02:00
2518f4f14a Make railgun S/M/L distinct via barrel count (1/2/3) 2026-07-23 21:31:26 +02:00
561c95d0dd make belt darker so that there is more contrast to the item icons 2026-07-23 21:30:48 +02:00
b4be06ed5e make item icons larger 2026-07-23 21:30:18 +02:00
d1051607b2 add spacing between items in header bar 2026-07-23 21:20:56 +02:00
79b79ab7c3 Show building_block icon in header stock, expand button and build costs 2026-07-23 21:13:37 +02:00
0bba7686e6 Add item icon art for all 41 item types 2026-07-23 20:56:38 +02:00
f766ae4a86 Allow to draw produced-item icons in recipe dialog and game world 2026-07-23 20:54:04 +02:00
8b71fe1a03 Rename ship/station scrap drop entities to "debris" 2026-07-23 20:51:05 +02:00
11daa61714 Add refund-percentage tooltip to Deconstruct button 2026-07-23 20:46:39 +02:00
60d6767d93 draw building icons in the game world 2026-07-23 20:45:50 +02:00
7c1455b8a0 add icons for build buttons 2026-07-22 21:44:20 +02:00
e20a0bba67 Rename Demolish to Deconstruct 2026-07-22 21:40:42 +02:00
b2ce20e6ad Add deconstruction queue 2026-07-22 21:37:56 +02:00
a9082c57f3 Implement config-driven unlock groups so that multiple things can be unlocked at once (including buildings) 2026-07-22 21:34:59 +02:00
a8a6a04f1e Highlight tunnel connections in green when selected 2026-07-21 21:16:21 +02:00
a75222f111 Never rotate tunnels in place 2026-07-21 21:14:27 +02:00
9b63af6ccb Unify tunnel build mode into a single Tunnel button 2026-07-21 21:12:06 +02:00
4ca5b332cd Snap belt-drag end tile to a building's input edge 2026-07-21 21:09:07 +02:00
0c4eb480be Update belt drag L-path immediately on rotate 2026-07-21 21:06:54 +02:00
b2c1ea34fd Implement deferred L-shaped belt drag placement 2026-07-21 21:05:31 +02:00