feat: #65 sea control — 11th ability (v0.43.0)
CI / build + unit + e2e (pull_request) Successful in 2m33s

Adds the sea ability: a fixed set of 12 named sea zones with sole-control
semantics, contest-by-higher-military, and a deterministic per-turn
+1 military/+1 economy bonus for each claimed zone. Durable (owns
GameState.seaZones), additive migration, stub-inert (e2e unaffected).

Fixes #65

Design note: Gitea #65 sketched a free-form 'naval' layer; the implemented
approved design is this richer 'sea' layer with a fixed zone set.
This commit is contained in:
2026-10-16 12:50:22 +00:00
parent 13f91845fd
commit c77e81c45b
24 changed files with 1060 additions and 58 deletions
+31
View File
@@ -249,6 +249,23 @@ export interface IndustryProject {
type: IndustryType;
}
/**
* (v0.43.0, #65) One sea-zone claim: which nation controls one of the fixed
* sea zones (see `SEA_ZONES` in `shared/protocol.ts`). The world keeps at
* most ONE claim per zone — a new op on an already-claimed zone REPLACES the
* controller in place (the zone's entry is updated, never duplicated), and if
* a turn declares the same zone for two different resolved nations the higher
* current `stats.military` wins (a tie: the op listed earlier in the turn's
* `control` array). Sea control is fully parallel to but INDEPENDENT of land:
* it never touches `territory` / `unowned`.
*/
export interface SeaZoneClaim {
/** The sea zone (one of `SEA_ZONE_IDS`). */
zone: string;
/** The id of the nation that controls it (resolved, not a name). */
by: string;
}
/**
* (v0.33.0, #56) A first-class **war** — a named, ongoing armed conflict
* between two or more nations. Unlike the boolean `war` relation (which a
@@ -443,6 +460,20 @@ export interface GameState {
* with this defaulted to `[]` (see server/db.ts) — additive, no data wipe.
*/
industry: IndustryProject[];
/**
* (v0.43.0, #65) Sea-zone control (see {@link SeaZoneClaim}): one entry per
* controlled sea zone — which of the 12 fixed zones (`SEA_ZONES`) each
* nation controls. At most ONE entry per zone (unique by `zone`); a turn's
* `sea.control` ops upsert entries (a re-claim by a different nation
* replaces the controller in place; a same-zone contest goes to the higher
* current `stats.military`, a tie to the earlier-listed op). Every
* committed turn each claim's controller earns a small deterministic
* military/economy bonus (`SEA_ZONE_BONUS`). Sea control never moves land
* (`territory` / `unowned` are untouched). Always `[]` on a fresh game;
* rows saved before v0.43 load with this defaulted to `[]` (see
* server/db.ts) — additive, no data wipe.
*/
seaZones: SeaZoneClaim[];
}
/**