feat(ui): Phase 30 ship-class calculator with goal-seek and reach circles
Tests · UI / test (push) Successful in 2m14s
Tests · Go / test (push) Successful in 2m25s

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:
Ilia Denisov
2026-05-21 19:52:08 +02:00
parent 00159ddf7c
commit 9ae7b88b89
53 changed files with 3748 additions and 1298 deletions
+59
View File
@@ -338,6 +338,65 @@ const ru: Record<keyof typeof en, string> = {
"game.designer.ship_class.preview.cargo_capacity": "грузоподъёмность одного корабля",
"game.designer.ship_class.preview.unavailable": "—",
"game.calculator.title": "калькулятор классов кораблей",
"game.calculator.mode.ship": "калькулятор",
"game.calculator.mode.modernization": "модернизация",
"game.calculator.name.placeholder": "имя нового класса",
"game.calculator.name.existing": "ваши классы кораблей",
"game.calculator.action.create": "создать",
"game.calculator.action.delete": "удалить",
"game.calculator.col.ship": "корабль",
"game.calculator.col.tech": "технологии",
"game.calculator.field.drive": "двигатель",
"game.calculator.field.armament": "вооружённость",
"game.calculator.field.weapons": "оружие",
"game.calculator.field.shields": "защита",
"game.calculator.field.cargo": "трюм",
"game.calculator.load.label": "загрузка",
"game.calculator.load.empty": "пусто",
"game.calculator.load.full": "полная",
"game.calculator.load.custom": "своя",
"game.calculator.col.empty": "пустой",
"game.calculator.col.loaded": "гружёный",
"game.calculator.out.mass": "масса",
"game.calculator.out.speed": "скорость",
"game.calculator.out.attack": "атака",
"game.calculator.out.defense": "защита",
"game.calculator.out.bombing": "бомбардировка",
"game.calculator.out.cargo_capacity": "грузоподъёмность",
"game.calculator.planet.title": "планета",
"game.calculator.planet.none": "выберите свою планету на карте",
"game.calculator.planet.label": "планета {name} (#{number})",
"game.calculator.planet.mat": "MAT",
"game.calculator.planet.ships_per_turn": "кораблей / ход",
"game.calculator.planet.turns_per_ship": "ходов / корабль",
"game.calculator.lock.reset": "зафиксировано — нажмите, чтобы вернуть вычисляемое значение",
"game.calculator.lock.infeasible": "эта цель недостижима при текущих параметрах",
"game.calculator.lock.max": "сначала снимите фиксацию с другого результата — по одному за раз",
"game.calculator.tech.reset": "переопределено — нажмите, чтобы вернуть ваши текущие технологии",
"game.calculator.mat.reset": "переопределено — нажмите, чтобы вернуть значение планеты",
"game.calculator.modern.current": "текущий",
"game.calculator.modern.target": "целевой",
"game.calculator.modern.cost": "стоимость апгрейда",
"game.calculator.modern.total": "суммарная стоимость апгрейда",
"game.calculator.unavailable": "—",
"game.calculator.invalid.empty": "имя не может быть пустым",
"game.calculator.invalid.too_long": "имя слишком длинное (максимум 30 символов)",
"game.calculator.invalid.starts_with_special": "имя не может начинаться со спецсимвола",
"game.calculator.invalid.ends_with_special": "имя не может заканчиваться спецсимволом",
"game.calculator.invalid.consecutive_specials": "слишком много спецсимволов подряд",
"game.calculator.invalid.whitespace": "имя не может содержать пробелы",
"game.calculator.invalid.disallowed_character": "имя содержит недопустимые символы",
"game.calculator.invalid.duplicate_name": "класс корабля с таким именем уже существует",
"game.calculator.invalid.drive_value": "двигатель должен быть 0 или ≥ 1",
"game.calculator.invalid.armament_value": "вооружённость должна быть 0 или положительным целым",
"game.calculator.invalid.armament_not_integer": "вооружённость должна быть целым числом",
"game.calculator.invalid.weapons_value": "оружие должно быть 0 или ≥ 1",
"game.calculator.invalid.shields_value": "защита должна быть 0 или ≥ 1",
"game.calculator.invalid.cargo_value": "трюм должен быть 0 или ≥ 1",
"game.calculator.invalid.armament_weapons_pair": "вооружённость и оружие должны быть оба нулевыми или оба ненулевыми",
"game.calculator.invalid.all_zero": "хотя бы одно значение должно быть ненулевым",
"game.table.sciences.title": "науки",
"game.table.sciences.column.name": "название",
"game.table.sciences.column.drive": "двигатель %",