feat(ui): Phase 30 ship-class calculator with goal-seek and reach circles
Fuse the standalone ship-class designer (Phases 17/18) into a sidebar calculator: live mass/speed/attack/defence/bombing results, a planet build-rate readout, single-target goal-seek, a modernization-cost mode, and auto reach circles on the map for the selected planet. pkg/calc becomes the single source for the new math (no mirroring): extract BombingPower from the engine model and the per-turn ship-production loop from controller.ProduceShip into pkg/calc (engine now delegates), and add inverse goal-seek solvers in pkg/calc/solve.go. Thin-bridge the combat, planet-build, and solver functions through ui/core/calc + ui/wasm and rebuild core.wasm. Remove the standalone designer view/route; the ship-classes table and the view/bottom menus open the calculator via a shared request store. Docs: rewrite ui/PLAN.md Phase 30, adjust Phase 34 (realistic forecast + CAP/COL ownership), add ui/docs/calculator-ux.md, extend calc-bridge.md, fix navigation.md; remove ui/CALCULATOR.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -337,6 +337,65 @@ const en = {
|
||||
"game.designer.ship_class.preview.cargo_capacity": "cargo capacity per ship",
|
||||
"game.designer.ship_class.preview.unavailable": "—",
|
||||
|
||||
"game.calculator.title": "ship class calculator",
|
||||
"game.calculator.mode.ship": "calculator",
|
||||
"game.calculator.mode.modernization": "modernization",
|
||||
"game.calculator.name.placeholder": "new class name",
|
||||
"game.calculator.name.existing": "your ship classes",
|
||||
"game.calculator.action.create": "create",
|
||||
"game.calculator.action.delete": "delete",
|
||||
"game.calculator.col.ship": "ship",
|
||||
"game.calculator.col.tech": "tech",
|
||||
"game.calculator.field.drive": "drive",
|
||||
"game.calculator.field.armament": "armament",
|
||||
"game.calculator.field.weapons": "weapons",
|
||||
"game.calculator.field.shields": "shields",
|
||||
"game.calculator.field.cargo": "cargo",
|
||||
"game.calculator.load.label": "load",
|
||||
"game.calculator.load.empty": "empty",
|
||||
"game.calculator.load.full": "full",
|
||||
"game.calculator.load.custom": "custom",
|
||||
"game.calculator.col.empty": "empty",
|
||||
"game.calculator.col.loaded": "loaded",
|
||||
"game.calculator.out.mass": "mass",
|
||||
"game.calculator.out.speed": "speed",
|
||||
"game.calculator.out.attack": "attack",
|
||||
"game.calculator.out.defense": "defense",
|
||||
"game.calculator.out.bombing": "bombing",
|
||||
"game.calculator.out.cargo_capacity": "cargo capacity",
|
||||
"game.calculator.planet.title": "planet",
|
||||
"game.calculator.planet.none": "select one of your planets on the map",
|
||||
"game.calculator.planet.label": "planet {name} (#{number})",
|
||||
"game.calculator.planet.mat": "MAT",
|
||||
"game.calculator.planet.ships_per_turn": "ships / turn",
|
||||
"game.calculator.planet.turns_per_ship": "turns / ship",
|
||||
"game.calculator.lock.reset": "locked — click to release to the computed value",
|
||||
"game.calculator.lock.infeasible": "this target cannot be reached with the current design",
|
||||
"game.calculator.lock.max": "release the locked result first — one result at a time",
|
||||
"game.calculator.tech.reset": "overridden — click to reset to your current tech",
|
||||
"game.calculator.mat.reset": "overridden — click to reset to the planet value",
|
||||
"game.calculator.modern.current": "current",
|
||||
"game.calculator.modern.target": "target",
|
||||
"game.calculator.modern.cost": "upgrade cost",
|
||||
"game.calculator.modern.total": "total upgrade cost",
|
||||
"game.calculator.unavailable": "—",
|
||||
"game.calculator.invalid.empty": "name cannot be empty",
|
||||
"game.calculator.invalid.too_long": "name is too long (30 characters max)",
|
||||
"game.calculator.invalid.starts_with_special": "name cannot start with a special character",
|
||||
"game.calculator.invalid.ends_with_special": "name cannot end with a special character",
|
||||
"game.calculator.invalid.consecutive_specials": "too many special characters in a row",
|
||||
"game.calculator.invalid.whitespace": "name cannot contain spaces",
|
||||
"game.calculator.invalid.disallowed_character": "name contains disallowed characters",
|
||||
"game.calculator.invalid.duplicate_name": "a ship class with this name already exists",
|
||||
"game.calculator.invalid.drive_value": "drive must be 0 or ≥ 1",
|
||||
"game.calculator.invalid.armament_value": "armament must be 0 or a positive integer",
|
||||
"game.calculator.invalid.armament_not_integer": "armament must be an integer",
|
||||
"game.calculator.invalid.weapons_value": "weapons must be 0 or ≥ 1",
|
||||
"game.calculator.invalid.shields_value": "shields must be 0 or ≥ 1",
|
||||
"game.calculator.invalid.cargo_value": "cargo must be 0 or ≥ 1",
|
||||
"game.calculator.invalid.armament_weapons_pair": "armament and weapons must be both zero or both nonzero",
|
||||
"game.calculator.invalid.all_zero": "at least one value must be nonzero",
|
||||
|
||||
"game.table.sciences.title": "sciences",
|
||||
"game.table.sciences.column.name": "name",
|
||||
"game.table.sciences.column.drive": "drive %",
|
||||
|
||||
Reference in New Issue
Block a user