feat(api): jump + explore endpoints queue tasks with lead + helpers instead of resolving instantly (#44)
This commit is contained in:
+33
-20
@@ -1,4 +1,5 @@
|
||||
import pkg from '@/package.json';
|
||||
import { MAX_TEAM_SIZE } from './game/crew';
|
||||
|
||||
// OpenAPI 3.1 document for the app's public JSON API, kept in code so it can be
|
||||
// served machine-readable at /api/openapi (see AGENTS.md "## API"). Must be updated
|
||||
@@ -8,7 +9,7 @@ export const openApiSpec = {
|
||||
info: {
|
||||
title: 'SpaceWanderer API',
|
||||
description:
|
||||
'JSON API for SpaceWanderer — a single-player turn-based space adventure (one save, no accounts). World endpoints: read the generated world state and jump between solar systems within range (adjacent by default; two hops once NAVIGATION AI is researched).',
|
||||
'JSON API for SpaceWanderer — a single-player turn-based space adventure (one save, no accounts). World endpoints: read the generated world state. Jump and exploration queue a crew team (lead + helpers) and their effects land when the task completes on the turn tick — queueing spends no turn (jump range is adjacent by default, two hops once NAVIGATION AI is researched); ship work, research and mission accept still resolve instantly, each costing a turn.',
|
||||
// Sourced from package.json so it stays in sync with every version bump.
|
||||
version: pkg.version,
|
||||
},
|
||||
@@ -52,9 +53,9 @@ export const openApiSpec = {
|
||||
},
|
||||
'/api/jump': {
|
||||
post: {
|
||||
summary: 'Jump to a solar system within range',
|
||||
summary: 'Queue a jump to a solar system within range',
|
||||
description:
|
||||
'Validates that the target is within jump range of the current system — one hop away, or two hops once NAVIGATION AI is researched (#35) — sets it as current (discovering it if new and generating its neighbours), advances the turn counter by the hop count and writes a jump event. Returns the fresh world state.',
|
||||
'Queues a JUMP task with the given crew team (lead + helpers): validates that the target is within jump range of the current system (one hop away, or two hops once NAVIGATION AI is researched — #35) and that the team is free, then the move — target becomes current, discovered if new with its neighbours generated, jump event — lands when the task completes on the turn tick. Queueing spends no turn. Returns the fresh world state.',
|
||||
operationId: 'jumpToSystem',
|
||||
requestBody: {
|
||||
required: true,
|
||||
@@ -66,7 +67,7 @@ export const openApiSpec = {
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Fresh world state after the jump',
|
||||
description: 'Fresh world state — the jump itself lands when the task completes on the turn tick',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/WorldState' },
|
||||
@@ -74,7 +75,7 @@ export const openApiSpec = {
|
||||
},
|
||||
},
|
||||
400: {
|
||||
description: 'Malformed body or non-integer systemId',
|
||||
description: 'Malformed body, a non-integer systemId/leadCrewId, a non-integer-array helperCrewIds, duplicate crew ids, or a team over the size cap',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
@@ -82,7 +83,7 @@ export const openApiSpec = {
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: 'Unknown system id',
|
||||
description: 'Unknown system id or unknown crew member',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
@@ -90,7 +91,7 @@ export const openApiSpec = {
|
||||
},
|
||||
},
|
||||
409: {
|
||||
description: 'Target is outside jump range of the current system — more than one hop away, or more than two hops without NAVIGATION AI researched (or is the current system itself)',
|
||||
description: 'Target is outside jump range of the current system (more than one hop away, or more than two without NAVIGATION AI; or is the current system itself) — or the crew team is blocked (a member committed to a pending task, a helper already busy, a jump in transit, or a jump already queued)',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
@@ -120,9 +121,9 @@ export const openApiSpec = {
|
||||
},
|
||||
'/api/explore': {
|
||||
post: {
|
||||
summary: 'Explore a planet or moon',
|
||||
summary: 'Queue a scan of a planet or moon',
|
||||
description:
|
||||
'Scans one body of the save with a deterministic haul (a resource and/or a part, or nothing), marks it explored, increments the turn counter, accumulates finds into inventory and writes an explore event. Returns the fresh system state plus this scan outcome.',
|
||||
'Queues an EXPLORE task with the given crew team (lead + helpers): validates that the body exists and has not been scanned yet, and that the team is free, then the scan — a deterministic haul into the cargo hold, the explored flag, the ~18% crew roll and the explore event — lands when the task completes on the turn tick. Queueing spends no turn. Returns the fresh system state, with the outcome key empty and crewFound null until the scan resolves.',
|
||||
operationId: 'explorePlanet',
|
||||
requestBody: {
|
||||
required: true,
|
||||
@@ -134,7 +135,7 @@ export const openApiSpec = {
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Fresh system state plus the scan outcome',
|
||||
description: 'Fresh system state — the scan itself lands when the task completes on the turn tick (outcome empty, crewFound null)',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/ExploreResult' },
|
||||
@@ -142,7 +143,7 @@ export const openApiSpec = {
|
||||
},
|
||||
},
|
||||
400: {
|
||||
description: 'Malformed body or non-integer planetId',
|
||||
description: 'Malformed body, a non-integer planetId/leadCrewId, a non-integer-array helperCrewIds, duplicate crew ids, or a team over the size cap',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
@@ -150,7 +151,7 @@ export const openApiSpec = {
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: 'Unknown planet id',
|
||||
description: 'Unknown planet id or unknown crew member',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
@@ -158,7 +159,7 @@ export const openApiSpec = {
|
||||
},
|
||||
},
|
||||
409: {
|
||||
description: 'Body was already explored (each can only be scanned once)',
|
||||
description: 'Body was already explored (each can only be scanned once) — or the crew team is blocked (a member committed to a pending task, a helper already busy, a jump in transit, or a jump already queued)',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: { $ref: '#/components/schemas/Error' },
|
||||
@@ -827,7 +828,7 @@ export const openApiSpec = {
|
||||
maxItems: 2,
|
||||
},
|
||||
},
|
||||
turn: { type: 'integer', description: 'Turn counter — one per jump' },
|
||||
turn: { type: 'integer', description: 'Turn counter — advances on the turn tick and on the still-instant actions (ship work, research, mission accept); a queued jump or exploration costs no turn' },
|
||||
},
|
||||
required: ['systems', 'edges', 'turn'],
|
||||
},
|
||||
@@ -835,8 +836,14 @@ export const openApiSpec = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
systemId: { type: 'integer', description: 'solar_systems.id of the jump target' },
|
||||
leadCrewId: { type: 'integer', description: 'crew.id of the team lead — the member the queued task is committed to first' },
|
||||
helperCrewIds: {
|
||||
type: 'array',
|
||||
description: `Optional supporting crew (crew.id) — the whole team, lead + helpers, holds at most ${MAX_TEAM_SIZE} distinct members, all of them free`,
|
||||
items: { type: 'integer' },
|
||||
},
|
||||
},
|
||||
required: ['systemId'],
|
||||
required: ['systemId', 'leadCrewId'],
|
||||
},
|
||||
Planet: {
|
||||
type: 'object',
|
||||
@@ -900,7 +907,7 @@ export const openApiSpec = {
|
||||
items: { $ref: '#/components/schemas/ShipSystem' },
|
||||
},
|
||||
inventory: { type: 'array', items: { $ref: '#/components/schemas/InventoryItem' } },
|
||||
turn: { type: 'integer', description: 'Turn counter — one per jump, exploration or ship action' },
|
||||
turn: { type: 'integer', description: 'Turn counter — one per ship action (research and mission accept cost one too; a queued jump or exploration costs no turn)' },
|
||||
},
|
||||
required: ['systems', 'inventory', 'turn'],
|
||||
},
|
||||
@@ -993,7 +1000,7 @@ export const openApiSpec = {
|
||||
items: { $ref: '#/components/schemas/Planet' },
|
||||
},
|
||||
inventory: { type: 'array', items: { $ref: '#/components/schemas/InventoryItem' } },
|
||||
turn: { type: 'integer', description: 'Turn counter — one per jump or exploration' },
|
||||
turn: { type: 'integer', description: 'Turn counter — advances on the turn tick and on the still-instant actions (ship work, research, mission accept); a queued jump or exploration costs no turn' },
|
||||
},
|
||||
required: ['systemId', 'systemName', 'planets', 'inventory', 'turn'],
|
||||
},
|
||||
@@ -1001,8 +1008,14 @@ export const openApiSpec = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
planetId: { type: 'integer', description: 'planets.id of the body to scan (planet or moon)' },
|
||||
leadCrewId: { type: 'integer', description: 'crew.id of the team lead — the member the queued task is committed to first' },
|
||||
helperCrewIds: {
|
||||
type: 'array',
|
||||
description: `Optional supporting crew (crew.id) — the whole team, lead + helpers, holds at most ${MAX_TEAM_SIZE} distinct members, all of them free`,
|
||||
items: { type: 'integer' },
|
||||
},
|
||||
},
|
||||
required: ['planetId'],
|
||||
required: ['planetId', 'leadCrewId'],
|
||||
},
|
||||
ExploreResult: {
|
||||
allOf: [
|
||||
@@ -1012,11 +1025,11 @@ export const openApiSpec = {
|
||||
properties: {
|
||||
outcome: {
|
||||
type: 'array',
|
||||
description: 'What this scan found — may be empty (some scans find nothing)',
|
||||
description: 'What this scan found — always empty in the queueing response; populated only once the scan resolves on the turn tick (a resolved scan may still find nothing)',
|
||||
items: { $ref: '#/components/schemas/FoundItem' },
|
||||
},
|
||||
crewFound: {
|
||||
description: 'A crew member who joined the ship on this scan (~18% of scans), null when none',
|
||||
description: 'A crew member who joined the ship on this scan (~18% of scans), null when none — always null in the queueing response',
|
||||
anyOf: [{ $ref: '#/components/schemas/CrewMember' }, { type: 'null' }],
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user