5 Commits

Author SHA1 Message Date
3d4c0445d1 Add config-defined tooltip to header building blocks stock
Implement REQ-UI-BLOCKS-TOOLTIP: an optional world.toml
[world].building_blocks_tooltip, threaded into HeaderBar via a new
const GameConfig* parameter and shown as the building blocks stock label's
hover tooltip. Omitted when unset. Author the text in the app config and
extend ConfigLoaderTest to cover the field.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZR44tA8sn4dPqDzAVXyps
2026-07-12 20:37:22 +02:00
cd8bf1a8b3 Add requirement for config-defined building blocks tooltip
Introduce REQ-UI-BLOCKS-TOOLTIP: an optional world.toml
[world].building_blocks_tooltip shown as the header bar's building blocks
stock hover tooltip. Note the optional field in the world.toml description.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZR44tA8sn4dPqDzAVXyps
2026-07-12 18:23:51 +02:00
c4d696c79e Add config-defined tooltips to build and module buttons
Implement REQ-UI-BUILD-TOOLTIP and REQ-MOD-UI-MODULE-TOOLTIP: an optional
tooltip string on BuildingDef and ModuleDef, parsed from buildings.toml and
modules.toml and shown as the build/module button's hover tooltip. Omitted
when unset. Author descriptions for all buildings and modules in the app
config, and extend ConfigLoaderTest to cover the optional field.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZR44tA8sn4dPqDzAVXyps
2026-07-12 17:56:09 +02:00
1add02eafa Add requirements for config-defined build/module button tooltips
Introduce REQ-UI-BUILD-TOOLTIP and REQ-MOD-UI-MODULE-TOOLTIP, and note
the optional tooltip fields in buildings.toml and modules.toml.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZR44tA8sn4dPqDzAVXyps
2026-07-12 16:35:05 +02:00
129200ff4f Rename UI "Blocks" labels to "Building Blocks"
Make user-visible terminology consistent across the header bar, build
button grid, and blueprint panel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DZR44tA8sn4dPqDzAVXyps
2026-07-12 15:15:41 +02:00
18 changed files with 113 additions and 11 deletions

View File

@@ -1,5 +1,6 @@
[[building]]
id = "belt"
tooltip = "Transports items one tile at a time in the direction it faces."
cost = 2
player_placeable = true
construction_time_seconds = 0.2
@@ -7,6 +8,7 @@ surface_mask = ["A>"]
[[building]]
id = "splitter"
tooltip = "Splits an incoming item stream between two outputs, with optional per-output filters."
cost = 3
player_placeable = true
construction_time_seconds = 0.5
@@ -14,6 +16,7 @@ surface_mask = ["<A>"]
[[building]]
id = "tunnel_entry"
tooltip = "Sends items underground to a matching tunnel exit, letting belts cross."
cost = 5
player_placeable = true
construction_time_seconds = 0.5
@@ -21,6 +24,7 @@ surface_mask = ["A>"]
[[building]]
id = "tunnel_exit"
tooltip = "Receives items from a matching tunnel entry and pushes them onward."
cost = 5
player_placeable = true
construction_time_seconds = 0.5
@@ -28,6 +32,7 @@ surface_mask = ["A>"]
[[building]]
id = "miner"
tooltip = "Extracts a selected ore from the asteroid; every tile yields any ore."
cost = 15
player_placeable = true
construction_time_seconds = 1
@@ -37,6 +42,7 @@ surface_mask = [
[[building]]
id = "smelter"
tooltip = "Melts ore or scrap into basic materials. No recipe selection needed."
cost = 20
player_placeable = true
construction_time_seconds = 1
@@ -47,6 +53,7 @@ surface_mask = [
[[building]]
id = "assembler"
tooltip = "Crafts a selected recipe from the production tree into intermediate or final parts."
cost = 35
player_placeable = true
construction_time_seconds = 1
@@ -57,6 +64,7 @@ surface_mask = [
[[building]]
id = "reprocessing_plant"
tooltip = "Consumes scrap and yields one random higher-tier product per cycle."
cost = 40
player_placeable = true
construction_time_seconds = 1
@@ -68,6 +76,7 @@ surface_mask = [
[[building]]
id = "shipyard"
tooltip = "Builds autonomous combat ships from a selected schematic and module layout."
cost = 60
player_placeable = true
construction_time_seconds = 1
@@ -78,6 +87,7 @@ surface_mask = [
[[building]]
id = "salvage_bay"
tooltip = "Drop-off point where salvage ships unload collected scrap onto belts."
cost = 25
player_placeable = true
construction_time_seconds = 1

View File

@@ -32,6 +32,7 @@
[[module]]
id = "railgun_s"
tooltip = "Small railgun. Fast-firing, short range, low damage; fits any hull."
unlock_at_station_level = -1
surface_mask = ["O"]
materials = [{item = "railgun_s_module", amount = 1}]
@@ -47,6 +48,7 @@ attack_rate_hz = 2.0
[[module]]
id = "railgun_m"
tooltip = "Medium railgun. Higher damage at longer range; needs a 2x2 slot."
unlock_at_station_level = 2
surface_mask = [
"OO",
@@ -64,6 +66,7 @@ attack_rate_hz = 1.5
[[module]]
id = "railgun_l"
tooltip = "Large railgun. Heavy damage at long range; needs a 3x3 slot."
unlock_at_station_level = 6
unlock_requires = ["railgun_m"]
surface_mask = [
@@ -86,6 +89,7 @@ attack_rate_hz = 0.8
[[module]]
id = "salvager"
tooltip = "Collects scrap from wrecks and stores it in the ship's cargo hold."
unlock_at_station_level = -1
surface_mask = ["O"]
materials = [{item = "salvager_module", amount = 1}]
@@ -101,6 +105,7 @@ collection_rate_hz = 0.5
[[module]]
id = "repair_tool"
tooltip = "Repairs damaged friendly ships and defence stations within range."
unlock_at_station_level = 0
surface_mask = ["O"]
materials = [{item = "repair_tool_module", amount = 1}]
@@ -119,6 +124,7 @@ repair_range_m = 80
[[module]]
id = "afterburner"
tooltip = "Greatly boosts top speed and forward acceleration."
unlock_at_station_level = 2
surface_mask = ["OOO"]
materials = [{item = "afterburner_module", amount = 1}]
@@ -133,6 +139,7 @@ added_main_acceleration_mpss = 60
[[module]]
id = "maneuvering_thrusters"
tooltip = "Improves top speed and lateral/braking acceleration."
unlock_at_station_level = 1
surface_mask = ["OO"]
materials = [{item = "maneuvering_thrusters_module", amount = 1}]
@@ -150,6 +157,7 @@ added_maneuvering_acceleration_mpss = 10
[[module]]
id = "armor_plates"
tooltip = "Adds a large flat bonus to the ship's hit points."
unlock_at_station_level = 0
surface_mask = ["OO"]
materials = [{item = "armor_plates_module", amount = 1}]
@@ -163,6 +171,7 @@ added_hp = 1200
[[module]]
id = "sensor_booster"
tooltip = "Extends the ship's sensor range."
unlock_at_station_level = 1
surface_mask = ["OO"]
materials = [{item = "sensor_booster_module", amount = 1}]
@@ -179,6 +188,7 @@ added_sensor_range_m = 50
[[module]]
id = "weapon_upgrade"
tooltip = "Increases the damage of all weapons on the ship."
unlock_at_station_level = 4
surface_mask = [
"OO",
@@ -195,6 +205,7 @@ multiplied_damage = 1.2
[[module]]
id = "weapon_primer"
tooltip = "Increases the fire rate of all weapons on the ship."
unlock_at_station_level = 4
surface_mask = [
"OO",
@@ -211,6 +222,7 @@ multiplied_attack_rate_hz = 1.2
[[module]]
id = "weapon_stabilizer"
tooltip = "Extends weapon range at the cost of some fire rate."
unlock_at_station_level = 3
surface_mask = [
"OO",
@@ -234,6 +246,7 @@ multiplied_attack_rate_hz = 0.8
[[module]]
id = "drone_bay"
tooltip = "Drone launch bay (capability not yet implemented)."
unlock_at_station_level = 5
surface_mask = [
"OO",
@@ -246,6 +259,7 @@ glyph = "Db"
[[module]]
id = "drone_hangar"
tooltip = "Large drone hangar (capability not yet implemented)."
unlock_at_station_level = 9
surface_mask = [
"OOOOOO",

View File

@@ -10,6 +10,7 @@ tunnel_max_distance_tiles = 10
departure_interval_seconds = 20
orbit_factor = 0.8
rally_orbit_radius_tiles = 5.0
building_blocks_tooltip = "Building blocks are the currency for construction. Spend them to place buildings and to expand the asteroid. Produce building blocks in your factory and deliver them to the HQ on a belt to grow your stock."
[regions]
asteroid_width_tiles = 60

View File

@@ -84,6 +84,7 @@ cost = 25
player_placeable = true
construction_time_seconds = 15
output_buffer_capacity = 20
tooltip = "Drop-off point for salvage ships."
surface_mask = [
"SAA",
"SAA>",

View File

@@ -1,5 +1,6 @@
[[module]]
id = "armor_plate"
tooltip = "Adds a large flat bonus to hit points."
unlock_at_station_level = -1
surface_mask = ["OO"]
materials = [{item = "iron_ingot", amount = 2}]

View File

@@ -10,6 +10,7 @@ tunnel_max_distance_tiles = 10
departure_interval_seconds = 20
orbit_factor = 0.8
rally_orbit_radius_tiles = 5.0
building_blocks_tooltip = "Spend building blocks to build; deliver them to the HQ to gain more."
[regions]
asteroid_width_tiles = 40

View File

@@ -4,11 +4,11 @@
Config files use the TOML format. The following config files drive game parameters:
- **world.toml** — world dimensions, region widths, expansion amounts, building refund percentage, wave timing, boss wave timing, belt speed, starting building blocks, departure interval, ship orbit factor, rally orbit radius, scrap-per-threat conversion, combat target-selection parameters (target score formula, overclaim penalty formula, target hysteresis), artifact chance formula, artifact win count, and view pan speeds (slow and fast horizontal pan speed and pan ramp band width).
- **buildings.toml** — building block cost and construction time per building type.
- **world.toml** — world dimensions, region widths, expansion amounts, building refund percentage, wave timing, boss wave timing, belt speed, starting building blocks, departure interval, ship orbit factor, rally orbit radius, scrap-per-threat conversion, combat target-selection parameters (target score formula, overclaim penalty formula, target hysteresis), artifact chance formula, artifact win count, view pan speeds (slow and fast horizontal pan speed and pan ramp band width), and an optional building blocks tooltip string (shown as the header bar's building blocks stock hover tooltip, REQ-UI-BLOCKS-TOOLTIP; omitted when unset).
- **buildings.toml** — building block cost and construction time per building type, plus an optional tooltip description string per building type (shown as the build button's hover tooltip, REQ-UI-BUILD-TOOLTIP; omitted when unset).
- **recipes.toml** — crafting recipes: inputs, outputs, quantities, durations, and reprocessing plant probabilities. Assembler recipe entries may optionally define `unlock_at_station_level` (integer): -1 means the recipe is explicitly unlocked at game start; a value ≥ 0 means the recipe starts locked and a schematic for it can be awarded via defence station destruction (see REQ-LOCK-EXPLICIT, REQ-DEF-SCHEMATIC-DROP). An assembler recipe schematic entry may also define an optional `unlock_requires` list of prerequisite schematic ids (REQ-LOCK-PREREQ).
- **ships.toml** — per schematic: a human-readable display name (used in the UI), hull stats (HP, max linear speed, sensor range, main acceleration, maneuvering acceleration, angular acceleration, max rotation speed) as plain values, required build materials, the station level at which the schematic becomes available for unlock (`unlock_at_station_level`; -1 means the player starts with the schematic already unlocked), an optional `unlock_requires` prerequisite list (REQ-LOCK-PREREQ), a layout grid defining the ship's module slots, and a `default_modules` list used for enemy wave ships (see REQ-WAV-DEFAULT-MODULES).
- **modules.toml** — per module type: id, surface mask, materials list, production time, fill color, glyph, the station level at which the schematic becomes available for unlock (`unlock_at_station_level`; -1 means the player starts with the module schematic already unlocked), an optional `unlock_requires` prerequisite list (REQ-LOCK-PREREQ), and an optional capability section and/or stat modifier formulas. A module with a capability section (`[module.weapon]`, `[module.salvage]`, or `[module.repair]`) containing base stat formulas is a **capability module** that grants the ship a weapon, salvage bay, or repair tool per instance (see REQ-MOD-CONFIG for the full list of formulas per capability type). A module with only `added_*`/`multiplied_*` formulas is a **passive module** that modifies stats on the ship or on capability module instances (see REQ-MOD-STAT-CALC).
- **modules.toml** — per module type: id, surface mask, materials list, production time, fill color, glyph, an optional tooltip description string (shown as the module selection button's hover tooltip, REQ-MOD-UI-MODULE-TOOLTIP; omitted when unset), the station level at which the schematic becomes available for unlock (`unlock_at_station_level`; -1 means the player starts with the module schematic already unlocked), an optional `unlock_requires` prerequisite list (REQ-LOCK-PREREQ), and an optional capability section and/or stat modifier formulas. A module with a capability section (`[module.weapon]`, `[module.salvage]`, or `[module.repair]`) containing base stat formulas is a **capability module** that grants the ship a weapon, salvage bay, or repair tool per instance (see REQ-MOD-CONFIG for the full list of formulas per capability type). A module with only `added_*`/`multiplied_*` formulas is a **passive module** that modifies stats on the ship or on capability module instances (see REQ-MOD-STAT-CALC).
- **stations.toml** — HP, damage, range, fire rate, and scrap drop for player and enemy defence stations, defined as formulas of station level.
- **visuals.toml** — rendering-only config (not game parameters): fill and outline colors and glyphs for every building type, item type, ship schematic, and station type; a distinct beam color per tool type (weapon, repair, salvage) and beam width; overlay and toast colors. Loaded by the UI at startup; the simulation does not read it.
- **ship_layouts.toml** — named layout blueprints per ship type; written and read by the application to persist the layout blueprint panel (REQ-MOD-UI-BLUEPRINT-PANEL through REQ-MOD-UI-BLUEPRINT-FILE-LOAD). Not a game parameter file; the simulation does not read it.
@@ -269,6 +269,8 @@ Modules in `modules.toml` define a `surface_mask` — a list of strings that des
- **Right** (below the grid): The layout blueprint panel (see REQ-MOD-UI-BLUEPRINT-PANEL through REQ-MOD-UI-BLUEPRINT-FILE-LOAD).
- **Bottom**: A "Confirm" button and a "Cancel" button. Cancel discards all changes made in this dialog session and closes the dialog. Confirm applies the changes: the shipyard's configured layout is updated, the required materials and cycle time displayed in the selected building panel are recalculated, and the ship layout preview is refreshed.
- REQ-MOD-UI-MODULE-TOOLTIP: Each module selection button in the layout configuration dialog (REQ-MOD-UI-DIALOG) shows a hover tooltip with the descriptive text defined for that module type in `modules.toml` (the optional per-module tooltip field). If a module type defines no tooltip text, its button shows no tooltip. The "Remove" button is not a module type and has no config-defined tooltip.
- REQ-MOD-UI-STATS-PANEL: The **ship stats panel** in the layout configuration dialog shows the stats of the currently configured ship layout as they would be computed, incorporating all passive module modifiers per REQ-MOD-STAT-CALC. The panel updates in real time whenever modules are placed or removed in the layout grid.
The panel always shows all hull stats as final computed values:
@@ -401,6 +403,7 @@ The screen is divided into two columns: a main column (75% width) containing the
```
- REQ-UI-HEADER: The header bar spans the width of the game world column (75% of the screen width) and always shows the elapsed survival time, the current global building blocks stock, and the artifact count (REQ-WIN-ARTIFACT-COUNT) displayed as `Artifacts: x/y` (where `x` is the current artifact count and `y` is `world.toml [world].artifact_win_count`) on the left, the boss wave counter and boss countdown (REQ-UI-BOSS-STATUS) and an asteroid expansion button (REQ-UI-EXPAND-BUTTON) to the left of the speed buttons, and game speed controls on the right.
- REQ-UI-BLOCKS-TOOLTIP: The header bar's building blocks stock display (REQ-UI-HEADER) shows a hover tooltip with the descriptive text defined in `world.toml [world].building_blocks_tooltip` — intended to tell the player what building blocks are used for and how to obtain them. If the field is unset, the stock display shows no tooltip. This tooltip is distinct from the build/module button tooltips (REQ-UI-BUILD-TOOLTIP, REQ-MOD-UI-MODULE-TOOLTIP).
- REQ-UI-BOSS-STATUS: The header bar displays, to the left of the speed buttons, the current boss wave counter (REQ-WAV-BOSS-COUNTER) and the time remaining on the boss countdown (REQ-WAV-BOSS-COUNTDOWN). The boss wave counter is shown as `Boss Wave #<x>` and the countdown as `Next boss: <M:SS>`, where `<M:SS>` is the remaining seconds formatted as whole minutes and two-digit seconds. Both values update continuously as the simulation runs.
- REQ-UI-SPEED: The game speed controls in the header bar are buttons for 0×, 0.5×, 1×, 2×, and 4× speed. The currently active speed is shown as selected. All game simulation (production, movement, threat accumulation, wave timing) scales with the selected speed. 0× pauses the game.
- REQ-UI-EXPAND-BUTTON: The header bar shows an asteroid expansion button captioned `Expand: <x> Blocks`, where `<x>` is the current expansion cost computed from `world.toml [expansion].cost_building_blocks_formula` at the current number of purchased expansions (REQ-EXP-COST). Clicking the button unlocks the next asteroid expansion (REQ-EXP-UNLOCK, REQ-GW-ASTEROID-EXPAND), spending that many building blocks from the global stock. The button is disabled when the player cannot currently afford the cost (consistent with REQ-UI-BUILD-DISABLED). The caption updates as the cost changes with each purchased expansion.
@@ -473,6 +476,7 @@ The screen is divided into two columns: a main column (75% width) containing the
- REQ-UI-BUILD-GRID: All placeable building types are shown as a flat grid of buttons with no grouping.
- REQ-UI-BUILD-COST: Each button caption shows the building name and its building block cost, e.g. "Belt: 2 Blocks".
- REQ-UI-BUILD-TOOLTIP: Each building-type button shows a hover tooltip with the descriptive text defined for that building type in `buildings.toml` (the optional per-building tooltip field). This tooltip is distinct from the recipe/schematic selection tooltip (REQ-UI-SELECT-TOOLTIP). If a building type defines no tooltip text, its button shows no tooltip. The Demolish button (REQ-UI-DEMOLISH-BUTTON) is not a building type and has no config-defined tooltip.
- REQ-UI-BUILD-DISABLED: Buttons for buildings the player cannot currently afford are shown as disabled.
- REQ-UI-DEMOLISH-BUTTON: A dedicated **Demolish** button is shown in the build button grid. Clicking it toggles demolish mode on and off, equivalent to the Q demolish toggle (REQ-UI-HOTKEYS). The button is shown in a visually active/pressed state while demolish mode is active.

View File

@@ -23,6 +23,9 @@ struct BuildingDef
// Output-buffer holding size for buildings without a recipe-driven buffer.
// Only the Salvage Bay sets this (REQ-BLD-SALVAGE-BAY).
std::optional<int> outputBufferCapacity;
// Optional hover-tooltip text for the build button (REQ-UI-BUILD-TOOLTIP).
std::optional<std::string> tooltip;
};
struct BuildingsConfig

View File

@@ -273,6 +273,12 @@ WorldConfig ConfigLoader::loadWorld(const std::string& path)
cfg.orbitFactor = requireDouble(tbl["world"]["orbit_factor"], file, "world.orbit_factor");
cfg.rallyOrbitRadius_tiles = requireDouble(tbl["world"]["rally_orbit_radius_tiles"], file, "world.rally_orbit_radius_tiles");
if (const std::optional<std::string> tip =
tbl["world"]["building_blocks_tooltip"].value<std::string>())
{
cfg.buildingBlocksTooltip = *tip;
}
cfg.regions.asteroidWidth_tiles = static_cast<int>(requireInt(tbl["regions"]["asteroid_width_tiles"], file, "regions.asteroid_width_tiles"));
cfg.regions.playerBufferWidth_tiles = static_cast<int>(requireInt(tbl["regions"]["player_buffer_width_tiles"], file, "regions.player_buffer_width_tiles"));
cfg.regions.contestZoneWidth_tiles = static_cast<int>(requireInt(tbl["regions"]["contest_zone_width_tiles"], file, "regions.contest_zone_width_tiles"));
@@ -343,6 +349,11 @@ BuildingsConfig ConfigLoader::loadBuildings(const std::string& path)
requireInt(mt["output_buffer_capacity"], file, elemPath + ".output_buffer_capacity"));
}
if (mt.contains("tooltip"))
{
def.tooltip = requireString(mt["tooltip"], file, elemPath + ".tooltip");
}
const std::optional<BuildingType> parsedType = parseBuildingType(def.id);
if (!parsedType)
{
@@ -603,6 +614,11 @@ ModulesConfig ConfigLoader::loadModules(const std::string& path)
def.fillColor = requireString(mt["fill_color"], file, elemPath + ".fill_color");
def.glyph = requireString(mt["glyph"], file, elemPath + ".glyph");
if (mt.contains("tooltip"))
{
def.tooltip = requireString(mt["tooltip"], file, elemPath + ".tooltip");
}
// Materials
{
const toml::array& materials = requireArray(mt["materials"], file, elemPath + ".materials");

View File

@@ -54,6 +54,10 @@ struct ModuleDef
std::optional<ModuleWeaponCapability> weaponCapability;
std::optional<ModuleSalvageCapability> salvageCapability;
std::optional<ModuleRepairCapability> repairCapability;
// Optional hover-tooltip text for the module selection button
// (REQ-MOD-UI-MODULE-TOOLTIP).
std::optional<std::string> tooltip;
};
struct ModulesConfig

View File

@@ -1,5 +1,8 @@
#pragma once
#include <optional>
#include <string>
#include "Formula.h"
// Region widths are in tiles (REQ-GW-REGIONS).
@@ -75,6 +78,10 @@ struct WorldConfig
double orbitFactor; // REQ-SHP-ORBIT (multiplies tool range for orbit radius)
double rallyOrbitRadius_tiles; // REQ-SHP-ORBIT (fixed orbit radius around the rally point)
// Optional hover-tooltip for the header building blocks stock display
// (REQ-UI-BLOCKS-TOOLTIP). Presentation-only; the simulation ignores it.
std::optional<std::string> buildingBlocksTooltip;
WorldRegions regions;
WorldExpansion expansion;
WorldPush push;

View File

@@ -83,6 +83,11 @@ TEST_CASE("ConfigLoader loads the committed bin/config/ configs end-to-end", "[c
REQUIRE(cfg.world.rallyOrbitRadius_tiles == Approx(5.0));
REQUIRE(cfg.world.scrapPerThreat == Approx(1.0));
// Optional header building blocks tooltip (REQ-UI-BLOCKS-TOOLTIP).
REQUIRE(cfg.world.buildingBlocksTooltip.has_value());
REQUIRE(*cfg.world.buildingBlocksTooltip ==
"Spend building blocks to build; deliver them to the HQ to gain more.");
// Spot-check that a config-derived formula computes as expected.
// threat_rate_formula = "x": evaluates to the input value.
REQUIRE(cfg.world.waves.threatRateFormula.evaluate(1.0) == Approx(1.0));
@@ -113,6 +118,12 @@ TEST_CASE("ConfigLoader loads the committed bin/config/ configs end-to-end", "[c
REQUIRE(salvageBayIt->outputBufferCapacity.has_value());
REQUIRE(*salvageBayIt->outputBufferCapacity == 20);
// Optional per-building tooltip (REQ-UI-BUILD-TOOLTIP): the Salvage Bay
// defines one; the Miner leaves it unset.
REQUIRE(salvageBayIt->tooltip.has_value());
REQUIRE(*salvageBayIt->tooltip == "Drop-off point for salvage ships.");
REQUIRE_FALSE(minerIt->tooltip.has_value());
// recipes.toml — reprocessing cycle has three weighted outputs.
const auto reproIt = std::find_if(
cfg.recipes.recipes.begin(), cfg.recipes.recipes.end(),
@@ -144,6 +155,21 @@ TEST_CASE("ConfigLoader loads the committed bin/config/ configs end-to-end", "[c
REQUIRE(salvageShipIt != cfg.ships.ships.end());
REQUIRE(salvageShipIt->defaultModules.empty());
// modules.toml — optional per-module tooltip (REQ-MOD-UI-MODULE-TOOLTIP):
// armor_plate defines one; salvager leaves it unset.
const auto armorPlateIt = std::find_if(
cfg.modules.modules.begin(), cfg.modules.modules.end(),
[](const ModuleDef& m) { return m.id == "armor_plate"; });
REQUIRE(armorPlateIt != cfg.modules.modules.end());
REQUIRE(armorPlateIt->tooltip.has_value());
REQUIRE(*armorPlateIt->tooltip == "Adds a large flat bonus to hit points.");
const auto salvagerModuleIt = std::find_if(
cfg.modules.modules.begin(), cfg.modules.modules.end(),
[](const ModuleDef& m) { return m.id == "salvager"; });
REQUIRE(salvagerModuleIt != cfg.modules.modules.end());
REQUIRE_FALSE(salvagerModuleIt->tooltip.has_value());
// stations.toml
REQUIRE(cfg.stations.playerStation.level == 5);
REQUIRE(cfg.stations.playerStation.hpFormula.evaluate(5.0) == Approx(500.0)); // 300 + 40*5

View File

@@ -239,7 +239,7 @@ void BlueprintPanel::rebuildButtons()
{
const Blueprint& bp = m_blueprints[static_cast<std::size_t>(i)];
const int cost = computeBlueprintCost(bp);
const QString label = bp.name + "\n" + tr("%1 Blocks").arg(cost);
const QString label = bp.name + "\n" + tr("%1 Building Blocks").arg(cost);
QWidget* row = new QWidget(m_buttonsContainer);
QHBoxLayout* rowLayout = new QHBoxLayout(row);

View File

@@ -38,10 +38,14 @@ BuildButtonGrid::BuildButtonGrid(const GameConfig* config, QWidget* parent)
m_costs[def.type] = def.cost;
const QString label = QString::fromStdString(toDisplayName(def.id))
+ "\n" + tr("%1 Blocks").arg(def.cost);
+ "\n" + tr("%1 Building Blocks").arg(def.cost);
QPushButton* btn = new QPushButton(label, this);
btn->setCheckable(true);
btn->setFixedHeight(48);
if (def.tooltip)
{
btn->setToolTip(QString::fromStdString(*def.tooltip));
}
layout->addWidget(btn, row, col);
const int idx = static_cast<int>(m_buttons.size());

View File

@@ -17,7 +17,7 @@
const double HeaderBar::kSpeeds[] = { 0.0, 0.5, 1.0, 2.0, 10.0 };
const int HeaderBar::kSpeedCount = 5;
HeaderBar::HeaderBar(QWidget* parent)
HeaderBar::HeaderBar(const GameConfig* config, QWidget* parent)
: QWidget(parent)
{
QHBoxLayout* layout = new QHBoxLayout(this);
@@ -25,7 +25,12 @@ HeaderBar::HeaderBar(QWidget* parent)
layout->setSpacing(8);
m_timeLabel = new QLabel("00:00", this);
m_blocksLabel = new QLabel(tr("Blocks: 0"), this);
m_blocksLabel = new QLabel(tr("Building Blocks: 0"), this);
if (config->world.buildingBlocksTooltip)
{
m_blocksLabel->setToolTip(
QString::fromStdString(*config->world.buildingBlocksTooltip));
}
m_artifactsLabel = new QLabel(tr("Artifacts: 0/?"), this);
m_bossLabel = new QLabel(tr("Boss Wave #1 Next boss: 5:00"), this);
layout->addWidget(m_timeLabel);
@@ -81,7 +86,7 @@ void HeaderBar::handleEvent(std::shared_ptr<const TickAdvancedEvent> event)
void HeaderBar::handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event)
{
m_blocks = event->blocks;
m_blocksLabel->setText(tr("Blocks: %1").arg(event->blocks));
m_blocksLabel->setText(tr("Building Blocks: %1").arg(event->blocks));
updateExpandButton();
}
@@ -93,7 +98,7 @@ void HeaderBar::handleEvent(std::shared_ptr<const ExpansionCostChangedEvent> eve
void HeaderBar::updateExpandButton()
{
m_expandButton->setText(tr("Expand: %1 Blocks").arg(m_expansionCost));
m_expandButton->setText(tr("Expand: %1 Building Blocks").arg(m_expansionCost));
m_expandButton->setEnabled(m_blocks >= m_expansionCost);
}

View File

@@ -9,6 +9,7 @@
#include "BuildingBlocksChangedEvent.h"
#include "EventHandler.h"
#include "ExpansionCostChangedEvent.h"
#include "GameConfig.h"
#include "GameSpeedChangedEvent.h"
#include "Tick.h"
#include "TickAdvancedEvent.h"
@@ -27,7 +28,7 @@ class HeaderBar : public QWidget,
Q_OBJECT
public:
explicit HeaderBar(QWidget* parent = nullptr);
explicit HeaderBar(const GameConfig* config, QWidget* parent = nullptr);
~HeaderBar() override;
private slots:

View File

@@ -42,7 +42,7 @@ MainWindow::MainWindow(Simulation* sim, const std::string& configDir,
setWindowTitle(tr("Dota Factory"));
resize(1280, 768);
m_headerBar = new HeaderBar(this);
m_headerBar = new HeaderBar(&sim->config(), this);
m_gameWorldView = new GameWorldView(sim, &sim->config(), &m_visuals, m_configDir,
m_replay.get(), this);

View File

@@ -461,6 +461,10 @@ ShipLayoutDialog::ShipLayoutDialog(const GameConfig* config,
QPushButton* btn = new QPushButton(label, this);
btn->setCheckable(true);
btn->setFixedHeight(48);
if (def.tooltip)
{
btn->setToolTip(QString::fromStdString(*def.tooltip));
}
buttonGrid->addWidget(btn, row, col);
m_moduleButtons.push_back(btn);