ui/phase-21: sciences CRUD list, designer, and production-picker integration

Lights up the player-defined sciences feature: a table view with sort
and filter, a designer with four percent inputs and a strict
sum-equals-100 gate, and a Research-sub-row integration so the
planet production picker lists the user's sciences alongside the
four tech buttons. Phase 21 decisions are baked back into ui/PLAN.md
(no UpdateScience on the wire — write-once via createScience +
removeScience; percentages instead of fractions; sciences live under
the existing Research segment).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-10 21:32:37 +02:00
parent 0509f2cde2
commit 7bea22b0b5
31 changed files with 2751 additions and 71 deletions
+41 -1
View File
@@ -16,6 +16,8 @@ import {
CommandPlanetRename,
CommandPlanetRouteRemove,
CommandPlanetRouteSet,
CommandScienceCreate,
CommandScienceRemove,
CommandShipClassCreate,
CommandShipClassRemove,
PlanetProduction,
@@ -82,13 +84,29 @@ export interface RemoveShipClassResultFixture extends CommandResultFixtureBase {
name: string;
}
export interface CreateScienceResultFixture extends CommandResultFixtureBase {
kind: "createScience";
name: string;
drive: number;
weapons: number;
shields: number;
cargo: number;
}
export interface RemoveScienceResultFixture extends CommandResultFixtureBase {
kind: "removeScience";
name: string;
}
export type CommandResultFixture =
| PlanetRenameResultFixture
| SetProductionTypeResultFixture
| SetCargoRouteResultFixture
| RemoveCargoRouteResultFixture
| CreateShipClassResultFixture
| RemoveShipClassResultFixture;
| RemoveShipClassResultFixture
| CreateScienceResultFixture
| RemoveScienceResultFixture;
export function buildOrderResponsePayload(
gameId: string,
@@ -215,6 +233,28 @@ function encodeItem(builder: Builder, c: CommandResultFixture): number {
payloadType = CommandPayload.CommandShipClassRemove;
break;
}
case "createScience": {
const nameOffset = builder.createString(c.name);
inner = CommandScienceCreate.createCommandScienceCreate(
builder,
nameOffset,
c.drive,
c.weapons,
c.shields,
c.cargo,
);
payloadType = CommandPayload.CommandScienceCreate;
break;
}
case "removeScience": {
const nameOffset = builder.createString(c.name);
inner = CommandScienceRemove.createCommandScienceRemove(
builder,
nameOffset,
);
payloadType = CommandPayload.CommandScienceRemove;
break;
}
}
CommandItem.startCommandItem(builder);
CommandItem.addCmdId(builder, cmdIdOffset);