ui/phase-20: ship-group inspector actions

Eight ship-group operations land on the inspector behind a single
inline-form panel: split, send, load, unload, modernize, dismantle,
transfer, join fleet. Each action either appends a typed command to
the local order draft or surfaces a tooltip explaining the
disabled state. Partial-ship operations emit an implicit
breakShipGroup command before the targeted action so the engine
sees a clean (Break, Action) pair on the wire.

`pkg/calc.BlockUpgradeCost` migrates from
`game/internal/controller/ship_group_upgrade.go` so the calc
bridge can wrap a pure pkg/calc formula; the controller now
imports it. The bridge surfaces the function as
`core.blockUpgradeCost`, which the inspector calls once per ship
block to render the modernize cost preview.

`GameReport.otherRaces` is decoded from the report's player block
(non-extinct, ≠ self) and feeds the transfer-to-race picker. The
planet inspector's stationed-ship rows become clickable for own
groups so the actions panel is reachable from the standard click
flow (the renderer continues to hide on-planet groups).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-10 16:27:55 +02:00
parent f7109af55c
commit 3626998a33
36 changed files with 4033 additions and 89 deletions
+56
View File
@@ -195,6 +195,14 @@ const ru: Record<keyof typeof en, string> = {
"game.sidebar.order.label.cargo_route_remove": "удалить маршрут {loadType} с планеты {source}",
"game.sidebar.order.label.ship_class_create": "сконструировать класс корабля {name}",
"game.sidebar.order.label.ship_class_remove": "удалить класс корабля {name}",
"game.sidebar.order.label.ship_group_break": "разделить группу {group} → новая группа из {quantity} кораблей",
"game.sidebar.order.label.ship_group_send": "отправить группу {group} → планета {destination}",
"game.sidebar.order.label.ship_group_load": "загрузить {cargo} × {quantity} в группу {group}",
"game.sidebar.order.label.ship_group_unload": "выгрузить × {quantity} из группы {group}",
"game.sidebar.order.label.ship_group_upgrade": "модернизация группы {group} {tech} → {level}",
"game.sidebar.order.label.ship_group_dismantle": "разобрать группу {group}",
"game.sidebar.order.label.ship_group_transfer": "передать группу {group} → {acceptor}",
"game.sidebar.order.label.ship_group_join_fleet": "включить группу {group} → флот {fleet}",
"game.table.ship_classes.title": "классы кораблей",
"game.table.ship_classes.column.name": "название",
"game.table.ship_classes.column.drive": "двигатель",
@@ -277,6 +285,54 @@ const ru: Record<keyof typeof en, string> = {
"game.inspector.ship_group.fleet.none": "—",
"game.inspector.ship_group.unidentified_no_data": "данных нет — известны только координаты",
"game.inspector.ship_group.action.split": "разделить",
"game.inspector.ship_group.action.send": "отправить",
"game.inspector.ship_group.action.load": "загрузить",
"game.inspector.ship_group.action.unload": "выгрузить",
"game.inspector.ship_group.action.modernize": "модернизировать",
"game.inspector.ship_group.action.dismantle": "разобрать",
"game.inspector.ship_group.action.transfer": "передать",
"game.inspector.ship_group.action.join_fleet": "во флот",
"game.inspector.ship_group.action.confirm": "подтвердить",
"game.inspector.ship_group.action.cancel": "отмена",
"game.inspector.ship_group.action.confirm_destroy": "подтвердить — колонисты погибнут",
"game.inspector.ship_group.action.disabled.not_in_orbit": "корабли заняты ({state}); действия доступны только на орбите",
"game.inspector.ship_group.action.disabled.no_reach": "в радиусе двигателей нет планет",
"game.inspector.ship_group.action.disabled.no_drive": "у класса корабля нет блока двигателей",
"game.inspector.ship_group.action.disabled.no_cargo_block": "у класса корабля нет грузового отсека",
"game.inspector.ship_group.action.disabled.no_planet": "планета орбиты не видна",
"game.inspector.ship_group.action.disabled.foreign_planet": "действие доступно только над вашей или ничейной планетой",
"game.inspector.ship_group.action.disabled.empty_cargo": "трюм пуст",
"game.inspector.ship_group.action.disabled.foreign_unload_col": "колонистов нельзя высадить на чужой планете",
"game.inspector.ship_group.action.disabled.no_headroom": "технологии группы уже на вашем расовом уровне",
"game.inspector.ship_group.action.disabled.no_planet_stock": "на планете нет такого ресурса",
"game.inspector.ship_group.action.disabled.full_load": "трюм полностью заполнен",
"game.inspector.ship_group.action.disabled.no_other_races": "нет других нерасправленных рас для передачи",
"game.inspector.ship_group.action.disabled.unknown_class": "класс корабля не найден в отчёте",
"game.inspector.ship_group.action.field.ships": "кораблей (всего {max})",
"game.inspector.ship_group.action.field.cargo": "тип груза",
"game.inspector.ship_group.action.field.quantity": "количество",
"game.inspector.ship_group.action.field.level": "уровень технологии",
"game.inspector.ship_group.action.field.tech": "технология",
"game.inspector.ship_group.action.field.acceptor": "получатель",
"game.inspector.ship_group.action.field.fleet": "имя флота",
"game.inspector.ship_group.action.field.destination": "планета назначения",
"game.inspector.ship_group.action.tech.all": "все блоки",
"game.inspector.ship_group.action.tech.drive": "двигатели",
"game.inspector.ship_group.action.tech.weapons": "оружие",
"game.inspector.ship_group.action.tech.shields": "защита",
"game.inspector.ship_group.action.tech.cargo": "груз",
"game.inspector.ship_group.action.send.pick_prompt": "выберите планету на карте (Esc — отмена)",
"game.inspector.ship_group.action.send.no_destination": "планета не выбрана",
"game.inspector.ship_group.action.modernize.cost": "ожидаемая стоимость: {cost}",
"game.inspector.ship_group.action.modernize.cost_unavailable": "предпросмотр недоступен",
"game.inspector.ship_group.action.dismantle.warning": "группа над чужой планетой везёт колонистов — они погибнут",
"game.inspector.ship_group.action.fleet.create_new": "+ новый флот",
"game.inspector.ship_group.action.invalid.ship_count": "число кораблей должно быть в диапазоне 1…{max}",
"game.inspector.ship_group.action.invalid.quantity": "количество должно быть больше нуля",
"game.inspector.ship_group.action.invalid.level": "уровень должен быть в ({current}, {max}]",
"game.inspector.ship_group.action.invalid.fleet_name": "имя флота не соответствует правилам имён сущностей",
"game.inspector.planet.ship_groups.title": "корабли на орбите",
"game.inspector.planet.ship_groups.row.count": "{count} кораблей",
"game.inspector.planet.ship_groups.row.mass": "масса {mass}",