feat: #65 sea control — 11th ability (v0.43.0)
CI / build + unit + e2e (pull_request) Successful in 2m33s
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:
+22
-2
@@ -100,6 +100,14 @@ export interface StubPayload {
|
||||
* deterministicTurn), so the industry path is covered by unit tests only.
|
||||
*/
|
||||
industry?: Array<{ regionKey: string; type: string }>;
|
||||
/**
|
||||
* (v0.43.0, #65) The currently active sea-zone control
|
||||
* (`{ zone, by }` — fixed sea-zone id + controlling nation id), emitted by
|
||||
* the engine's user prompt (always, even when empty). The stub ignores this
|
||||
* field — it never claims, contests or re-claims a sea zone (see
|
||||
* deterministicTurn), so the sea path is covered by unit tests only.
|
||||
*/
|
||||
seaZones?: Array<{ zone: string; by: string }>;
|
||||
}
|
||||
|
||||
function truncate(s: string, n: number): string {
|
||||
@@ -173,6 +181,18 @@ function truncate(s: string, n: number): string {
|
||||
* (v0.39.0, #62) The stub likewise NEVER changes a nation's ideology (it
|
||||
* always returns `ideology: { changes: [] }`) — the ideology path is covered
|
||||
* by unit tests only, keeping the e2e assertions untouched.
|
||||
*
|
||||
* (v0.41.0, #63) The stub likewise NEVER declares a disaster or pandemic (it
|
||||
* always returns `disasters: { events: [] }`) — the disasters path is covered
|
||||
* by unit tests only, keeping the e2e assertions untouched.
|
||||
*
|
||||
* (v0.42.0, #64) The stub likewise NEVER declares a migration / refugee flow
|
||||
* (it always returns `migration: { ops: [] }`) — the migration path is
|
||||
* covered by unit tests only, keeping the e2e assertions untouched.
|
||||
*
|
||||
* (v0.43.0, #65) The stub likewise NEVER claims, contests or re-claims a sea
|
||||
* zone (it always returns `sea: { control: [] }`) — the sea-control path is
|
||||
* covered by unit tests only, keeping the e2e assertions untouched.
|
||||
*/
|
||||
export function deterministicTurn(p: StubPayload): TurnResult {
|
||||
const state = p.state;
|
||||
@@ -252,13 +272,13 @@ export function deterministicTurn(p: StubPayload): TurnResult {
|
||||
nationOps: [], // the stub never proposes nation ops (see doc comment)
|
||||
};
|
||||
|
||||
// The 9 ability fields, filled by the registry in its canonical order. The
|
||||
// The 11 ability fields, filled by the registry in its canonical order. The
|
||||
// stub is ability-inert: every ability contributes its own no-op default
|
||||
// (each ability's `stub()` — see the per-ability doc comments above), so the
|
||||
// e2e assertions are unaffected. The insertion order here (ABILITIES) is the
|
||||
// historical key order pinned by the stub's deterministic output
|
||||
// (takeovers → wars → hybrid → economy → industry → nuclear → leaders →
|
||||
// ideology → disasters), which must stay byte-identical.
|
||||
// ideology → disasters → migration → sea), which must stay byte-identical.
|
||||
const abilities = {} as Record<AbilityField, unknown>;
|
||||
for (const a of ABILITIES) abilities[a.field] = a.stub();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user