diff --git a/src/spec/chunks.ts b/src/spec/chunks.ts index d1a67f5..b50ed94 100644 --- a/src/spec/chunks.ts +++ b/src/spec/chunks.ts @@ -50,6 +50,213 @@ export const statusSchema = () => { }; }; +// The base `/v2/` path segment for a building or module, derived from its doc page name +// (e.g. `buildingBase('GasGiantPlatform')` -> `/v2/gasgiantplatform`). +export const buildingBase = (name: string) => `/v2/${name.toLowerCase()}`; + +// The `build`, `upgrade`, `downgrade`, `demolish`, `repair`, and `get_stats_for_level` methods +// shared by every regular (non-module) building type. `view` is intentionally excluded — nearly +// every building type adds its own extra fields to `view`, so it's defined per-building via +// buildingView() instead. +export const buildingCommonMethods = (base: string) => { + const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, + }); + + const pendingBuildSchema = { + type: 'object', + properties: { + seconds_remaining: { type: 'integer' }, + start: { type: 'string' }, + end: { type: 'string' }, + }, + required: ['seconds_remaining', 'start', 'end'], + }; + + const queueResultSchema = (description: string) => ({ + ...response200(description, { + type: 'object', + required: ['building', 'status'], + properties: { + building: { + type: 'object', + properties: { + id: { type: 'string' }, + level: { type: 'integer' }, + pending_build: pendingBuildSchema, + }, + required: ['id', 'level', 'pending_build'], + }, + status: statusSchema(), + }, + }), + ...response500(), + }); + + const buildingViewResultSchema = (description: string) => ({ + ...response200(description, { + type: 'object', + required: ['building', 'status'], + properties: { building: { $ref: '#/components/schemas/building' }, status: statusSchema() }, + }), + ...response500(), + }); + + return { + [`${base}/build`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['body_id', 'x', 'y'], + properties: { + body_id: { type: 'string' }, + x: { type: 'integer', minimum: -5, maximum: 5 }, + y: { type: 'integer', minimum: -5, maximum: 5 }, + }, + }), + responses: queueResultSchema("Adds this building to the planet's build queue."), + }, + }, + + [`${base}/upgrade`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: queueResultSchema('Adds the requested upgrade to the build queue.'), + }, + }, + + [`${base}/downgrade`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: buildingViewResultSchema( + "Downgrades a building by one level and then returns the building's view." + ), + }, + }, + + [`${base}/demolish`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Instantly destroys a building.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/repair`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: buildingViewResultSchema( + "Restores a building's efficiency to 100%, then returns the building's view." + ), + }, + }, + + [`${base}/get_stats_for_level`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'level'], + properties: { + building_id: { type: 'string' }, + level: { type: 'integer', minimum: 1, maximum: 100 }, + }, + }), + responses: { + ...response200( + 'Returns the projected stats of a building at a given level. The building must already exist, since where it exists and who owns it affects the stats.', + { + type: 'object', + required: ['building', 'status'], + properties: { + building: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + image: { type: 'string' }, + level: { type: 'integer' }, + food_hour: { type: 'integer' }, + food_capacity: { type: 'integer' }, + energy_hour: { type: 'integer' }, + energy_capacity: { type: 'integer' }, + ore_hour: { type: 'integer' }, + ore_capacity: { type: 'integer' }, + water_hour: { type: 'integer' }, + water_capacity: { type: 'integer' }, + waste_hour: { type: 'integer' }, + waste_capacity: { type: 'integer' }, + happiness_hour: { type: 'integer' }, + upgrade: { + type: 'object', + properties: { + cost: { $ref: '#/components/schemas/building_cost' }, + production: { $ref: '#/components/schemas/building_production' }, + image: { type: 'string' }, + }, + required: ['cost', 'production', 'image'], + }, + }, + required: ['id', 'name', 'image', 'level'], + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + }; +}; + +// The `view` method for a building or module. `extraProperties`/`extraRequired` describe fields +// the building type adds as siblings of `building`/`status` (e.g. OreStorage adds `ore_stored`, +// PlanetaryCommand adds `planet`, Capitol adds `rename_empire_cost`). +export const buildingView = ( + base: string, + extraProperties: object = {}, + extraRequired: string[] = [] +) => { + return { + [`${base}/view`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, + }), + responses: { + ...response200('Retrieves the properties of the building.', { + type: 'object', + required: ['building', 'status', ...extraRequired], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + ...extraProperties, + }, + }), + ...response500(), + }, + }, + }, + }; +}; + export const speciesSchema = () => { return { type: 'object', diff --git a/src/spec/components.ts b/src/spec/components.ts index 3b2d114..14a352e 100644 --- a/src/spec/components.ts +++ b/src/spec/components.ts @@ -198,6 +198,149 @@ export const components = { ], }, + building_cost: { + type: 'object', + properties: { + food: { type: 'integer' }, + water: { type: 'integer' }, + energy: { type: 'integer' }, + waste: { type: 'integer' }, + ore: { type: 'integer' }, + time: { type: 'integer' }, + }, + required: ['food', 'water', 'energy', 'waste', 'ore', 'time'], + }, + + building_production: { + type: 'object', + properties: { + food_hour: { type: 'integer' }, + food_capacity: { type: 'integer' }, + energy_hour: { type: 'integer' }, + energy_capacity: { type: 'integer' }, + ore_hour: { type: 'integer' }, + ore_capacity: { type: 'integer' }, + water_hour: { type: 'integer' }, + water_capacity: { type: 'integer' }, + waste_hour: { type: 'integer' }, + waste_capacity: { type: 'integer' }, + happiness_hour: { type: 'integer' }, + }, + required: [ + 'food_hour', + 'food_capacity', + 'energy_hour', + 'energy_capacity', + 'ore_hour', + 'ore_capacity', + 'water_hour', + 'water_capacity', + 'waste_hour', + 'waste_capacity', + 'happiness_hour', + ], + }, + + // The fields common to every building's `view` response. Building-type-specific endpoints + // (see src/spec/paths/buildings/*.ts) add extra sibling fields alongside this on `view`. + building: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + image: { type: 'string' }, + url: { type: 'string' }, + level: { type: 'integer' }, + x: { type: 'integer', minimum: -5, maximum: 5 }, + y: { type: 'integer', minimum: -5, maximum: 5 }, + efficiency: { type: 'integer' }, + food_hour: { type: 'integer' }, + food_capacity: { type: 'integer' }, + energy_hour: { type: 'integer' }, + energy_capacity: { type: 'integer' }, + ore_hour: { type: 'integer' }, + ore_capacity: { type: 'integer' }, + water_hour: { type: 'integer' }, + water_capacity: { type: 'integer' }, + waste_hour: { type: 'integer' }, + waste_capacity: { type: 'integer' }, + happiness_hour: { type: 'integer' }, + repair_costs: { + type: 'object', + properties: { + food: { type: 'integer' }, + water: { type: 'integer' }, + energy: { type: 'integer' }, + ore: { type: 'integer' }, + }, + required: ['food', 'water', 'energy', 'ore'], + }, + // Only present while the building is being built/upgraded. + pending_build: { + type: 'object', + properties: { + seconds_remaining: { type: 'integer' }, + start: { type: 'string' }, + end: { type: 'string' }, + }, + required: ['seconds_remaining', 'start', 'end'], + }, + // Only present while the building is doing work (e.g. Parks, Waste Recycling). + work: { + type: 'object', + properties: { + seconds_remaining: { type: 'integer' }, + start: { type: 'string' }, + end: { type: 'string' }, + }, + required: ['seconds_remaining', 'start', 'end'], + }, + downgrade: { + type: 'object', + properties: { + can: { type: 'integer', enum: [1, 0] }, + reason: { type: 'string' }, + image: { type: 'string' }, + }, + required: ['can', 'reason', 'image'], + }, + upgrade: { + type: 'object', + properties: { + can: { type: 'integer', enum: [1, 0] }, + reason: { type: 'array', items: {} }, + cost: { $ref: '#/components/schemas/building_cost' }, + production: { $ref: '#/components/schemas/building_production' }, + image: { type: 'string' }, + }, + required: ['can', 'reason', 'cost', 'production', 'image'], + }, + }, + required: [ + 'id', + 'name', + 'image', + 'level', + 'x', + 'y', + 'efficiency', + 'food_hour', + 'food_capacity', + 'energy_hour', + 'energy_capacity', + 'ore_hour', + 'ore_capacity', + 'water_hour', + 'water_capacity', + 'waste_hour', + 'waste_capacity', + 'happiness_hour', + 'repair_costs', + 'downgrade', + 'upgrade', + ], + }, + rpc_error: { type: 'object', required: ['id', 'jsonrpc', 'error'], diff --git a/src/spec/paths.ts b/src/spec/paths.ts index bffd410..8a6f920 100644 --- a/src/spec/paths.ts +++ b/src/spec/paths.ts @@ -1,4 +1,19 @@ import { empire } from './paths/empire'; import { body } from './paths/body'; +import { alliance } from './paths/alliance'; +import { inbox } from './paths/inbox'; +import { map } from './paths/map'; +import { captcha } from './paths/captcha'; +import { buildings } from './paths/buildings'; +import { modules } from './paths/modules'; -export const paths = { ...empire, ...body }; +export const paths = { + ...empire, + ...body, + ...alliance, + ...inbox, + ...map, + ...captcha, + ...buildings, + ...modules, +}; diff --git a/src/spec/paths/alliance.ts b/src/spec/paths/alliance.ts new file mode 100644 index 0000000..5dfe0ee --- /dev/null +++ b/src/spec/paths/alliance.ts @@ -0,0 +1,105 @@ +import { requestBodySchema, response200, response500, security, statusSchema } from '../chunks'; + +// NOTE: alliance *management* (create, invite, leave, stash, propositions/voting) lives on the +// Embassy building, not this module — see src/spec/paths/buildings/embassy.ts. This module only +// exposes read-only alliance lookups. +export const alliance = { + '/v2/alliance/view_profile': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['alliance_id'], + properties: { alliance_id: { type: 'string' } }, + }), + + responses: { + ...response200("Provides a list of the data that's publicly known about this alliance.", { + type: 'object', + required: ['profile', 'status'], + properties: { + profile: { + type: 'object', + required: [ + 'id', + 'name', + 'description', + 'leader_id', + 'date_created', + 'members', + 'space_stations', + 'influence', + ], + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + description: { type: 'string' }, + leader_id: { type: 'string' }, + date_created: { type: 'string' }, + members: { + type: 'array', + items: { + type: 'object', + required: ['id', 'name'], + properties: { id: { type: 'string' }, name: { type: 'string' } }, + }, + }, + space_stations: { + type: 'array', + items: { + type: 'object', + required: ['id', 'name', 'x', 'y'], + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + x: { type: 'number' }, + y: { type: 'number' }, + }, + }, + }, + influence: { type: 'integer' }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + '/v2/alliance/find': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['name'], + properties: { name: { type: 'string' } }, + }), + + responses: { + ...response200( + 'Find an alliance by name. Case insensitive, partial matches accepted. Must be at least 3 characters.', + { + type: 'object', + required: ['alliances', 'status'], + properties: { + alliances: { + type: 'array', + items: { + type: 'object', + required: ['id', 'name'], + properties: { id: { type: 'string' }, name: { type: 'string' } }, + }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/body.ts b/src/spec/paths/body.ts index 570c402..776405d 100644 --- a/src/spec/paths/body.ts +++ b/src/spec/paths/body.ts @@ -1,4 +1,41 @@ -import { response200, response500, security } from '../chunks'; +import { requestBodySchema, response200, response500, security, statusSchema } from '../chunks'; + +// The lightweight per-building shape returned by get_buildings/repair_list — not the full +// `building` schema (see components.ts), since this is a list/grid view, not a single-building +// detail view. +const buildingListEntrySchema = { + type: 'object', + required: ['name', 'x', 'y', 'url', 'level', 'image', 'efficiency'], + properties: { + name: { type: 'string' }, + x: { type: 'integer', minimum: -5, maximum: 5 }, + y: { type: 'integer', minimum: -5, maximum: 5 }, + url: { type: 'string' }, + level: { type: 'integer' }, + image: { type: 'string' }, + efficiency: { type: 'integer' }, + // Only included when the building is being built/upgraded. + pending_build: { + type: 'object', + properties: { + seconds_remaining: { type: 'integer' }, + start: { type: 'string' }, + end: { type: 'string' }, + }, + required: ['seconds_remaining', 'start', 'end'], + }, + // Only included when the building is working (Parks, Waste Recycling, etc). + work: { + type: 'object', + properties: { + seconds_remaining: { type: 'integer' }, + start: { type: 'string' }, + end: { type: 'string' }, + }, + required: ['seconds_remaining', 'start', 'end'], + }, + }, +}; export const body = { '/v2/body/get_status': { @@ -19,4 +56,363 @@ export const body = { }, }, }, + + '/v2/body/get_buildings': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['body_id'], + properties: { body_id: { type: 'string' } }, + }), + + responses: { + ...response200( + "Retrieves the buildings on a planet's 11x11 (-5 to 5) surface grid. The planetary command building is always at 0,0.", + { + type: 'object', + required: ['buildings', 'body', 'status'], + properties: { + buildings: { + type: 'object', + description: 'Keyed by building id.', + additionalProperties: buildingListEntrySchema, + }, + body: { + type: 'object', + required: ['surface_image'], + properties: { surface_image: { type: 'string' } }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + '/v2/body/repair_list': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['body_id', 'building_ids'], + properties: { + body_id: { type: 'string' }, + building_ids: { type: 'array', items: { type: 'string' } }, + }, + }), + + responses: { + ...response200( + 'Repairs the given buildings, in the order provided. Returns the same shape as get_buildings, but only for the repaired buildings.', + { + type: 'object', + required: ['buildings', 'body', 'status'], + properties: { + buildings: { + type: 'object', + description: 'Keyed by building id.', + additionalProperties: buildingListEntrySchema, + }, + body: { + type: 'object', + required: ['surface_image'], + properties: { surface_image: { type: 'string' } }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + '/v2/body/rearrange_buildings': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['body_id', 'arrangement'], + properties: { + body_id: { type: 'string' }, + arrangement: { + type: 'array', + description: + 'Every building being moved must be included. The Planetary Command/Station Command must end up at 0,0.', + items: { + type: 'object', + required: ['id', 'x', 'y'], + properties: { + id: { type: 'string' }, + x: { type: 'integer', minimum: -5, maximum: 5 }, + y: { type: 'integer', minimum: -5, maximum: 5 }, + }, + }, + }, + }, + }), + + responses: { + ...response200('Rearranges buildings to the supplied coordinates.', { + type: 'object', + required: ['moved', 'body', 'status'], + properties: { + moved: { + type: 'array', + items: { + type: 'object', + required: ['id', 'name', 'x', 'y'], + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + }, + }, + }, + body: { + type: 'object', + required: ['surface_image'], + properties: { surface_image: { type: 'string' } }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + '/v2/body/get_buildable': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['body_id', 'x', 'y', 'tag'], + properties: { + body_id: { type: 'string' }, + x: { type: 'integer', minimum: -5, maximum: 5 }, + y: { type: 'integer', minimum: -5, maximum: 5 }, + tag: { + type: 'string', + description: 'A tag to filter buildable types by. Cannot be Now, Soon, or Later.', + }, + }, + }), + + responses: { + ...response200( + 'Lists the building types buildable at a given spot for a given tag. If multiple plans apply, returns the one with the highest extra_build_level.', + { + type: 'object', + required: ['max_items_in_build_queue', 'build_queue', 'buildable', 'status'], + properties: { + max_items_in_build_queue: { type: 'integer' }, + build_queue: { + type: 'object', + required: ['max', 'current'], + properties: { max: { type: 'integer' }, current: { type: 'integer' } }, + }, + buildable: { + type: 'object', + description: 'Keyed by building type name.', + additionalProperties: { + type: 'object', + required: ['url', 'build', 'image', 'production'], + properties: { + url: { type: 'string' }, + image: { type: 'string' }, + build: { + type: 'object', + required: ['can', 'no_plot_use', 'cost', 'tags', 'reason'], + properties: { + can: { type: 'integer', enum: [1, 0] }, + no_plot_use: { type: 'integer', enum: [1, 0] }, + cost: { $ref: '#/components/schemas/building_cost' }, + // Only present for some plan types — skips level 1 and builds straight + // to this level. + extra_level: { type: 'integer' }, + tags: { type: 'array', items: { type: 'string' } }, + reason: { + type: 'array', + items: {}, + description: '[code, message, data], same shape as an rpc_error.', + }, + }, + }, + production: { + type: 'object', + properties: { + food_hour: { type: 'integer' }, + energy_hour: { type: 'integer' }, + ore_hour: { type: 'integer' }, + water_hour: { type: 'integer' }, + waste_hour: { type: 'integer' }, + happiness_hour: { type: 'integer' }, + }, + }, + }, + }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + '/v2/body/get_buildable_locations': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['body_id'], + properties: { + body_id: { type: 'string' }, + size: { + type: 'integer', + description: + 'Optional building footprint size. 9 = center tile (LCOT), 4 = northwest tile (SSLA); omitted/other values return locations for single-tile buildings.', + }, + }, + }), + + responses: { + ...response200( + 'Lists unoccupied buildable locations on the planet. Order is not guaranteed.', + { + type: 'object', + required: ['unoccupied', 'status'], + properties: { + unoccupied: { + type: 'array', + items: { type: 'array', items: { type: 'integer' }, minItems: 2, maxItems: 2 }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + '/v2/body/rename': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['body_id', 'name'], + properties: { body_id: { type: 'string' }, name: { type: 'string' } }, + }), + + responses: { + ...response200('Renames a body owned by the empire attached to this session.', { + type: 'integer', + enum: [1], + }), + ...response500(), + }, + }, + }, + + '/v2/body/abandon': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['body_id'], + properties: { body_id: { type: 'string' } }, + }), + + responses: { + ...response200( + 'Abandons a colony, destroying everything on the planet. The home planet cannot be abandoned.', + { type: 'object', required: ['status'], properties: { status: statusSchema() } } + ), + ...response500(), + }, + }, + }, + + '/v2/body/view_laws': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['body_id'], + properties: { + body_id: { + type: 'string', + description: 'The id of the space station itself, not its Parliament building.', + }, + }, + }), + + responses: { + ...response200('Returns the laws enacted by this space station.', { + type: 'object', + required: ['status', 'laws'], + properties: { + status: statusSchema(), + laws: { + type: 'array', + items: { + type: 'object', + required: ['id', 'name', 'description', 'date_enacted'], + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + description: { type: 'string' }, + date_enacted: { type: 'string' }, + }, + }, + }, + }, + }), + ...response500(), + }, + }, + }, + + '/v2/body/set_colony_notes': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['body_id', 'options'], + properties: { + body_id: { type: 'string' }, + options: { + type: 'object', + required: ['notes'], + properties: { notes: { type: 'string' } }, + }, + }, + }), + + responses: { + ...response200('Sets the per-colony notes for an owned body (colony or station).', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, }; diff --git a/src/spec/paths/buildings/algae.ts b/src/spec/paths/buildings/algae.ts new file mode 100644 index 0000000..626c3e4 --- /dev/null +++ b/src/spec/paths/buildings/algae.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Algae'); + +export const algae = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/algaepond.ts b/src/spec/paths/buildings/algaepond.ts new file mode 100644 index 0000000..6baa2ea --- /dev/null +++ b/src/spec/paths/buildings/algaepond.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('AlgaePond'); + +export const algaePond = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/amalgusmeadow.ts b/src/spec/paths/buildings/amalgusmeadow.ts new file mode 100644 index 0000000..164c5ef --- /dev/null +++ b/src/spec/paths/buildings/amalgusmeadow.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('AmalgusMeadow'); + +export const amalgusMeadow = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/apple.ts b/src/spec/paths/buildings/apple.ts new file mode 100644 index 0000000..667c0ec --- /dev/null +++ b/src/spec/paths/buildings/apple.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Apple'); + +export const apple = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/archaeology.ts b/src/spec/paths/buildings/archaeology.ts new file mode 100644 index 0000000..7d4d121 --- /dev/null +++ b/src/spec/paths/buildings/archaeology.ts @@ -0,0 +1,249 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Archaeology'); + +const ORE_TYPES = [ + 'rutile', + 'chromite', + 'chalcopyrite', + 'galena', + 'gold', + 'uraninite', + 'bauxite', + 'goethite', + 'halite', + 'gypsum', + 'trona', + 'kerogen', + 'methane', + 'anthracite', + 'sulfur', + 'zircon', + 'monazite', + 'fluorite', + 'beryl', + 'magnetite', +]; + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +export const archaeology = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/search_for_glyph`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'ore_type'], + properties: { + building_id: { type: 'string' }, + ore_type: { + type: 'string', + enum: ORE_TYPES, + description: 'Consumes 10,000 of this ore type to search for a glyph.', + }, + }, + }), + responses: { + ...response200('Searches ore for an ancient glyph. Returns the building view.', { + type: 'object', + required: ['building', 'status'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/subsidize_search`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Spends 2 essentia to complete the current glyph search immediately. Returns the building view.', + { + type: 'object', + required: ['building', 'status'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/get_glyph_summary`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Returns the glyphs available for assembly.', { + type: 'object', + required: ['glyphs', 'status'], + properties: { + glyphs: { + type: 'array', + items: { + type: 'object', + required: ['id', 'name', 'type', 'quantity'], + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + type: { type: 'string' }, + quantity: { type: 'integer' }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/assemble_glyphs`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'glyphs'], + properties: { + building_id: { type: 'string' }, + glyphs: { + type: 'array', + items: { type: 'string' }, + minItems: 1, + maxItems: 4, + description: 'Up to four glyph type names to combine.', + }, + quantity: { type: 'integer', minimum: 1, description: 'Defaults to 1.' }, + }, + }), + responses: { + ...response200('Converts glyphs into a rare ancient item.', { + type: 'object', + required: ['status', 'item_name'], + properties: { status: statusSchema(), item_name: { type: 'string' } }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_ores_available_for_processing`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Lists ore types with sufficient quantity in storage to search for a glyph.', + { + type: 'object', + required: ['ore', 'status'], + properties: { + ore: { + type: 'object', + description: 'Keyed by ore type.', + additionalProperties: { type: 'integer' }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/view_excavators`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists the active excavator sites controlled by this ministry.', { + type: 'object', + required: ['max_excavators', 'travelling', 'excavators', 'status'], + properties: { + max_excavators: { type: 'integer' }, + travelling: { type: 'integer' }, + excavators: { + type: 'array', + items: { + type: 'object', + required: ['id', 'date_landed'], + properties: { + id: { type: 'string' }, + date_landed: { type: 'string' }, + body: { type: 'object', description: 'The body the excavator is sited on.' }, + artifact_chance: { type: 'number' }, + glyph_chance: { type: 'number' }, + plan_chance: { type: 'number' }, + resource_chance: { type: 'number' }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/abandon_excavator`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'site_id'], + properties: { building_id: { type: 'string' }, site_id: { type: 'string' } }, + }), + responses: { + ...response200('Closes a single excavator site.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/mass_abandon_excavator`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Destroys all excavators belonging to this ministry.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/atmosphericevaporator.ts b/src/spec/paths/buildings/atmosphericevaporator.ts new file mode 100644 index 0000000..320adda --- /dev/null +++ b/src/spec/paths/buildings/atmosphericevaporator.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('AtmosphericEvaporator'); + +export const atmosphericEvaporator = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/beach.ts b/src/spec/paths/buildings/beach.ts new file mode 100644 index 0000000..94b7f94 --- /dev/null +++ b/src/spec/paths/buildings/beach.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Beach'); + +export const beach = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/bean.ts b/src/spec/paths/buildings/bean.ts new file mode 100644 index 0000000..703e123 --- /dev/null +++ b/src/spec/paths/buildings/bean.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Bean'); + +export const bean = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/beeldeban.ts b/src/spec/paths/buildings/beeldeban.ts new file mode 100644 index 0000000..8672555 --- /dev/null +++ b/src/spec/paths/buildings/beeldeban.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Beeldeban'); + +export const beeldeban = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/beeldebannest.ts b/src/spec/paths/buildings/beeldebannest.ts new file mode 100644 index 0000000..db58968 --- /dev/null +++ b/src/spec/paths/buildings/beeldebannest.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('BeeldebanNest'); + +export const beeldebanNest = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/blackholegenerator.ts b/src/spec/paths/buildings/blackholegenerator.ts new file mode 100644 index 0000000..6728555 --- /dev/null +++ b/src/spec/paths/buildings/blackholegenerator.ts @@ -0,0 +1,245 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('BlackHoleGenerator'); + +const TASK_NAMES = [ + 'Make Asteroid', + 'Make Planet', + 'Increase Size', + 'Change Type', + 'Swap Places', + 'Jump Zone', + 'Move System', +]; + +// Identifies a target body/star/zone. Exactly one addressing scheme is expected to be used at a +// time (body_name, body_id, x+y, or star_name/star_id [+ optional orbit], or zone for Jump Zone). +const targetSchema = { + type: 'object', + description: + 'Identifies the target body, star, or zone for the task. Provide one addressing scheme.', + properties: { + body_name: { + type: 'string', + description: "Case insensitive; throws if it doesn't match a body.", + }, + body_id: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + star_name: { + type: 'string', + description: "Case insensitive; throws if it doesn't match a star.", + }, + star_id: { type: 'string' }, + orbit: { + type: 'integer', + description: + 'Used with star_name/star_id to target a specific (possibly unoccupied) orbit around that star.', + }, + zone: { + type: 'string', + description: "Zone name, e.g. '-1|4'. Only used for the Jump Zone task.", + }, + }, +}; + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +export const blackHoleGenerator = { + ...buildingCommonMethods(base), + ...buildingView(base, { + tasks: { + type: 'array', + description: 'Tasks the generator can currently attempt (range is not factored in).', + items: { + type: 'object', + required: ['name'], + properties: { + name: { type: 'string', enum: TASK_NAMES }, + base_fail: { type: 'integer' }, + min_level: { type: 'integer' }, + occupied: { type: 'integer', enum: [0, 1] }, + recovery: { + type: 'integer', + description: 'Cooldown, in seconds, before the task can be used again.', + }, + side_chance: { type: 'integer' }, + types: { type: 'array', items: { type: 'string' } }, + waste_cost: { type: 'integer' }, + reason: { + type: 'string', + description: 'Present when the task cannot currently be used.', + }, + }, + }, + }, + task_options: { + type: 'object', + properties: { + asteroid_types: { type: 'array', items: { type: 'integer' } }, + planet_types: { type: 'array', items: { type: 'integer' } }, + zones: { type: 'array', items: { type: 'string' } }, + }, + }, + }), + + [`${base}/generate_singularity`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'target', 'task_name'], + properties: { + building_id: { type: 'string' }, + target: targetSchema, + task_name: { type: 'string', enum: TASK_NAMES }, + params: { + type: 'object', + description: "Only used for the 'Change Type' task.", + properties: { + newtype: { type: 'integer', description: 'One of the 40 basic planet type ids.' }, + }, + }, + subsidize: { + type: 'integer', + enum: [0, 1], + description: + "Spend essentia to guarantee 'perfection' (100% success). Only supported via this named-argument form.", + }, + }, + }), + responses: { + ...response200( + 'Attempts a Black Hole Generator task against the target body. Returns the success, failure, and side-effect results (not all fields are populated for every outcome). Throws 1002, 1009, 1010, 1013.', + { + type: 'object', + required: ['status'], + properties: { + status: statusSchema(), + fail: { type: 'object', description: 'Present when the task failed.' }, + side: { type: 'object', description: 'Present when a side effect occurred.' }, + target: { + type: 'object', + description: 'Present when the task succeeded (or produced a side effect).', + properties: { + class: { type: 'string' }, + id: { type: 'string' }, + name: { type: 'string' }, + old_class: { type: 'string' }, + old_size: { type: 'integer' }, + message: { type: 'string' }, + size: { type: 'integer' }, + type: { + type: 'string', + enum: ['asteroid', 'gas giant', 'habitable planet', 'space station'], + }, + variance: { type: 'integer', enum: [-1, 0, 1] }, + waste: { type: 'string', enum: ['Zero', 'Random', 'Filled'] }, + }, + }, + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/get_actions_for`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'target'], + properties: { building_id: { type: 'string' }, target: targetSchema }, + }), + responses: { + ...response200( + 'Returns the task list with success percentage and Essentia cost for the given target.', + { + type: 'object', + required: ['status', 'tasks'], + properties: { + status: statusSchema(), + building: { $ref: '#/components/schemas/building' }, + tasks: { + type: 'array', + items: { + type: 'object', + required: ['name'], + properties: { + name: { type: 'string', enum: TASK_NAMES }, + base_fail: { type: 'integer' }, + body_id: { type: 'string' }, + dist: { type: 'number' }, + min_level: { type: 'integer' }, + occupied: { type: 'integer', enum: [0, 1] }, + range: { type: 'integer' }, + reason: { + type: 'string', + description: 'Present when the task cannot currently be used.', + }, + recovery: { type: 'integer' }, + side_chance: { type: 'integer' }, + success: { type: 'integer', description: 'Percentage chance of success.' }, + essentia_cost: { + type: 'integer', + description: + "Essentia cost to make the task 'perfect' (100% success). Minimum is 2.", + }, + throw: { + type: 'integer', + description: 'RPC error code thrown if the task cannot be used.', + }, + types: { type: 'array', items: { type: 'string' } }, + waste_cost: { type: 'integer' }, + body_type: { + type: 'string', + enum: ['asteroid', 'habitable planet'], + description: "Present only when name is 'Change Type'.", + }, + }, + }, + }, + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/subsidize_cooldown`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Spends 2 essentia to cool down the generator immediately. Returns the building view. Throws 1011.', + { + type: 'object', + required: ['building', 'status'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/bread.ts b/src/spec/paths/buildings/bread.ts new file mode 100644 index 0000000..524d60b --- /dev/null +++ b/src/spec/paths/buildings/bread.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Bread'); + +export const bread = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/burger.ts b/src/spec/paths/buildings/burger.ts new file mode 100644 index 0000000..e89c1ab --- /dev/null +++ b/src/spec/paths/buildings/burger.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Burger'); + +export const burger = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/capitol.ts b/src/spec/paths/buildings/capitol.ts new file mode 100644 index 0000000..12f1c1a --- /dev/null +++ b/src/spec/paths/buildings/capitol.ts @@ -0,0 +1,35 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Capitol'); + +export const capitol = { + ...buildingCommonMethods(base), + ...buildingView(base, { rename_empire_cost: { type: 'integer' } }), + + [`${base}/rename_empire`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'name'], + properties: { building_id: { type: 'string' }, name: { type: 'string' } }, + }), + responses: { + ...response200( + "Spends essentia to change the empire's name (cost given by view's rename_empire_cost).", + { type: 'object', required: ['status'], properties: { status: statusSchema() } } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/cheese.ts b/src/spec/paths/buildings/cheese.ts new file mode 100644 index 0000000..7499d65 --- /dev/null +++ b/src/spec/paths/buildings/cheese.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Cheese'); + +export const cheese = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/chip.ts b/src/spec/paths/buildings/chip.ts new file mode 100644 index 0000000..ebfcbc3 --- /dev/null +++ b/src/spec/paths/buildings/chip.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Chip'); + +export const chip = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/cider.ts b/src/spec/paths/buildings/cider.ts new file mode 100644 index 0000000..01754b1 --- /dev/null +++ b/src/spec/paths/buildings/cider.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Cider'); + +export const cider = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/citadelofknope.ts b/src/spec/paths/buildings/citadelofknope.ts new file mode 100644 index 0000000..1e8ab93 --- /dev/null +++ b/src/spec/paths/buildings/citadelofknope.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('CitadelOfKnope'); + +export const citadelOfKnope = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/cloakinglab.ts b/src/spec/paths/buildings/cloakinglab.ts new file mode 100644 index 0000000..6cb01c7 --- /dev/null +++ b/src/spec/paths/buildings/cloakinglab.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('CloakingLab'); + +export const cloakingLab = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/corn.ts b/src/spec/paths/buildings/corn.ts new file mode 100644 index 0000000..e5f985c --- /dev/null +++ b/src/spec/paths/buildings/corn.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Corn'); + +export const corn = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/cornmeal.ts b/src/spec/paths/buildings/cornmeal.ts new file mode 100644 index 0000000..d2d88b3 --- /dev/null +++ b/src/spec/paths/buildings/cornmeal.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('CornMeal'); + +export const cornMeal = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/crashedshipsite.ts b/src/spec/paths/buildings/crashedshipsite.ts new file mode 100644 index 0000000..46c95ac --- /dev/null +++ b/src/spec/paths/buildings/crashedshipsite.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('CrashedShipSite'); + +export const crashedShipSite = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/crater.ts b/src/spec/paths/buildings/crater.ts new file mode 100644 index 0000000..ef42086 --- /dev/null +++ b/src/spec/paths/buildings/crater.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Crater'); + +export const crater = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/dairy.ts b/src/spec/paths/buildings/dairy.ts new file mode 100644 index 0000000..b9d91e0 --- /dev/null +++ b/src/spec/paths/buildings/dairy.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Dairy'); + +export const dairy = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/denton.ts b/src/spec/paths/buildings/denton.ts new file mode 100644 index 0000000..83c6cdf --- /dev/null +++ b/src/spec/paths/buildings/denton.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Denton'); + +export const denton = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/dentonbrambles.ts b/src/spec/paths/buildings/dentonbrambles.ts new file mode 100644 index 0000000..4443b76 --- /dev/null +++ b/src/spec/paths/buildings/dentonbrambles.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('DentonBrambles'); + +export const dentonBrambles = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/deployedbleeder.ts b/src/spec/paths/buildings/deployedbleeder.ts new file mode 100644 index 0000000..279ce7b --- /dev/null +++ b/src/spec/paths/buildings/deployedbleeder.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('DeployedBleeder'); + +export const deployedBleeder = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/development.ts b/src/spec/paths/buildings/development.ts new file mode 100644 index 0000000..5ccf027 --- /dev/null +++ b/src/spec/paths/buildings/development.ts @@ -0,0 +1,137 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Development'); + +const buildQueueItemSchema = { + type: 'object', + properties: { + building_id: { type: 'string' }, + name: { type: 'string' }, + to_level: { type: 'integer' }, + seconds_remaining: { type: 'integer' }, + x: { type: 'integer', minimum: -5, maximum: 5 }, + y: { type: 'integer', minimum: -5, maximum: 5 }, + subsidy_cost: { + type: 'integer', + description: 'The essentia cost to subsidize just this building.', + }, + }, + required: ['building_id', 'name', 'to_level', 'seconds_remaining', 'x', 'y', 'subsidy_cost'], +}; + +// Same shape as buildingView()'s response, reused by cancel_build which returns the same as view. +const developmentViewResultSchema = (description: string) => ({ + ...response200(description, { + type: 'object', + required: ['building', 'status', 'build_queue', 'subsidy_cost'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + build_queue: { type: 'array', items: buildQueueItemSchema }, + subsidy_cost: { + type: 'integer', + description: 'The essentia cost to subsidize the whole build queue.', + }, + }, + }), + ...response500(), +}); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +export const development = { + ...buildingCommonMethods(base), + ...buildingView( + base, + { + build_queue: { type: 'array', items: buildQueueItemSchema }, + subsidy_cost: { + type: 'integer', + description: 'The essentia cost to subsidize the whole build queue.', + }, + }, + ['build_queue', 'subsidy_cost'] + ), + + [`${base}/subsidize_build_queue`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Instantly finishes all buildings in the build queue.', { + type: 'object', + required: ['status', 'essentia_spent'], + properties: { status: statusSchema(), essentia_spent: { type: 'integer' } }, + }), + ...response500(), + }, + }, + }, + + [`${base}/subsidize_one_build`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'scheduled_id'], + properties: { + building_id: { type: 'string' }, + scheduled_id: { + type: 'string', + description: + 'The ID of the building scheduled to be built/upgraded that you wish to subsidize.', + }, + }, + }), + responses: { + ...response200( + 'Subsidizes the immediate build of one job on the build queue. Later jobs (if any) are brought forward by the (remaining) time of the subsidized build.', + { + type: 'object', + required: ['status', 'essentia_spent'], + properties: { status: statusSchema(), essentia_spent: { type: 'integer' } }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/cancel_build`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + scheduled_id: { + oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }], + description: + 'The ID, or array of IDs, of the building(s) scheduled to be built/upgraded that you wish to cancel. One of scheduled_id or cancel_all is required.', + }, + cancel_all: { + type: 'boolean', + description: 'If true, cancels all builds currently scheduled.', + }, + }, + }), + responses: developmentViewResultSchema( + 'Cancels a build. All following builds in the build queue are brought forward. Resources or plans used when the build/upgrade was requested are not returned. Returns the same as the view method.' + ), + }, + }, +}; diff --git a/src/spec/paths/buildings/distributioncenter.ts b/src/spec/paths/buildings/distributioncenter.ts new file mode 100644 index 0000000..6ce5262 --- /dev/null +++ b/src/spec/paths/buildings/distributioncenter.ts @@ -0,0 +1,130 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('DistributionCenter'); + +const reserveSchema = { + type: 'object', + properties: { + can: { type: 'integer', enum: [1, 0] }, + seconds_remaining: { + type: 'integer', + description: 'Time until reserved resources will automatically be released.', + }, + max_reserve_duration: { + type: 'integer', + description: 'Max length resources can be kept in reserve.', + }, + max_reserve_size: { + type: 'integer', + description: 'Max amount of resources that can be reserved.', + }, + resources: { + type: 'array', + description: 'Resources currently in reserve.', + items: { + type: 'object', + properties: { type: { type: 'string' }, quantity: { type: 'integer' } }, + required: ['type', 'quantity'], + }, + }, + }, + required: ['can', 'seconds_remaining', 'max_reserve_duration', 'max_reserve_size', 'resources'], +}; + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +export const distributionCenter = { + ...buildingCommonMethods(base), + ...buildingView(base, { reserve: reserveSchema }, ['reserve']), + + [`${base}/reserve`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'resources'], + properties: { + building_id: { type: 'string' }, + resources: { + type: 'array', + description: "Resources to reserve so they don't get automatically spent.", + items: { + type: 'object', + properties: { type: { type: 'string' }, quantity: { type: 'integer' } }, + required: ['type', 'quantity'], + }, + }, + }, + }), + responses: { + ...response200( + 'Reserves resources so they are held until the timer expires or manually released. Returns the building view. Throws 1009, 1010, and 1011.', + { + type: 'object', + required: ['building', 'status', 'reserve'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + reserve: reserveSchema, + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/release_reserve`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Returns the resources held in reserve back to the planet.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_stored_resources`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Returns a list of the resources you have stored, to make it easier to identify what you want to store.', + { + type: 'object', + required: ['status', 'cargo_space_used_each', 'resources'], + properties: { + status: statusSchema(), + cargo_space_used_each: { type: 'integer' }, + resources: { + type: 'object', + description: 'Keyed by resource type.', + additionalProperties: { type: 'integer' }, + }, + }, + } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/embassy.ts b/src/spec/paths/buildings/embassy.ts new file mode 100644 index 0000000..45b6944 --- /dev/null +++ b/src/spec/paths/buildings/embassy.ts @@ -0,0 +1,441 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Embassy'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +const optionalMessageRequestBody = (extraRequired: string[] = [], extraProperties: object = {}) => + requestBodySchema({ + type: 'object', + required: ['building_id', ...extraRequired], + properties: { + building_id: { type: 'string' }, + message: { type: 'string' }, + ...extraProperties, + }, + }); + +// This is the module where alliance *management* (create/dissolve/invite/leave/stash/ +// propositions) lives, per the docs — the Alliance module itself only exposes read-only lookups. +export const embassy = { + ...buildingCommonMethods(base), + ...buildingView(base, { + alliance_status: { + type: 'object', + description: 'Present only when this empire is in an alliance.', + }, + }), + + [`${base}/create_alliance`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'name'], + properties: { + building_id: { type: 'string' }, + name: { type: 'string', minLength: 3, maxLength: 30 }, + }, + }), + responses: { + ...response200('Creates a new alliance with this empire as leader.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_alliance_status`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200("Returns this empire's alliance data.", { + type: 'object', + required: ['status'], + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + members: { + type: 'array', + items: { + type: 'object', + properties: { empire_id: { type: 'string' }, name: { type: 'string' } }, + }, + }, + leader_id: { type: 'string' }, + forum_uri: { type: 'string' }, + description: { type: 'string' }, + announcements: { type: 'string' }, + date_created: { type: 'string' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/dissolve_alliance`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Leader-only. Disbands the alliance and converts its space stations to asteroids.', + { type: 'object', required: ['status'], properties: { status: statusSchema() } } + ), + ...response500(), + }, + }, + }, + + [`${base}/update_alliance`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'params'], + properties: { + building_id: { type: 'string' }, + params: { + type: 'object', + properties: { + forum_uri: { type: 'string' }, + description: { type: 'string' }, + announcements: { type: 'string' }, + }, + }, + }, + }), + responses: { + ...response200('Leader-only. Updates alliance metadata.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/send_invite`]: { + post: { + ...security(), + ...optionalMessageRequestBody(['invitee_id'], { invitee_id: { type: 'string' } }), + responses: { + ...response200('Leader-only. Invites an empire to join the alliance.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/withdraw_invite`]: { + post: { + ...security(), + ...optionalMessageRequestBody(['invite_id'], { invite_id: { type: 'string' } }), + responses: { + ...response200('Leader-only. Withdraws a pending invite.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_pending_invites`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Leader-only. Lists outstanding invites sent by the alliance.', { + type: 'object', + required: ['invites', 'status'], + properties: { + invites: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + empire_id: { type: 'string' }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/accept_invite`]: { + post: { + ...security(), + ...optionalMessageRequestBody(['invite_id'], { invite_id: { type: 'string' } }), + responses: { + ...response200('Accepts an invite to join an alliance.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/reject_invite`]: { + post: { + ...security(), + ...optionalMessageRequestBody(['invite_id'], { invite_id: { type: 'string' } }), + responses: { + ...response200('Declines an invite to join an alliance.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_my_invites`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists invites this empire has received.', { + type: 'object', + required: ['invites', 'status'], + properties: { + invites: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + alliance_id: { type: 'string' }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/leave_alliance`]: { + post: { + ...security(), + ...optionalMessageRequestBody(), + responses: { + ...response200('Leaves the current alliance.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/expel_member`]: { + post: { + ...security(), + ...optionalMessageRequestBody(['empire_id'], { empire_id: { type: 'string' } }), + responses: { + ...response200('Leader-only. Removes a member from the alliance.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/assign_alliance_leader`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'new_leader_id'], + properties: { building_id: { type: 'string' }, new_leader_id: { type: 'string' } }, + }), + responses: { + ...response200('Leader-only. Transfers alliance leadership to another current member.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_stash`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200("Returns the alliance stash's contents.", { + type: 'object', + required: ['stash', 'max_exchange_size', 'exchanges_remaining_today', 'status'], + properties: { + stash: { type: 'object', additionalProperties: { type: 'integer' } }, + max_exchange_size: { type: 'integer' }, + exchanges_remaining_today: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/donate_to_stash`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'donation'], + properties: { + building_id: { type: 'string' }, + donation: { + type: 'object', + description: + 'Resource name to quantity, e.g. {"water": 4500, "bread": 5000}. Waste is not allowed.', + additionalProperties: { type: 'integer' }, + }, + }, + }), + responses: { + ...response200('Donates resources to the alliance stash.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/exchange_with_stash`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'donation', 'request'], + properties: { + building_id: { type: 'string' }, + donation: { + type: 'object', + description: 'Must equal request in total value. Waste is not allowed.', + additionalProperties: { type: 'integer' }, + }, + request: { type: 'object', additionalProperties: { type: 'integer' } }, + }, + }), + responses: { + ...response200('Exchanges resources with the alliance stash.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_propositions`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists pending propositions the alliance is voting on.', { + type: 'object', + required: ['propositions', 'status'], + properties: { + propositions: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + description: { type: 'string' }, + votes_needed: { type: 'integer' }, + votes_yes: { type: 'integer' }, + votes_no: { type: 'integer' }, + status: { type: 'string' }, + date_ends: { type: 'string' }, + proposed_by: { + type: 'object', + properties: { id: { type: 'string' }, name: { type: 'string' } }, + }, + my_vote: { + type: 'integer', + enum: [1, 0], + description: 'Only present if this empire has voted.', + }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/cast_vote`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'proposition_id', 'vote'], + properties: { + building_id: { type: 'string' }, + proposition_id: { type: 'string' }, + vote: { type: 'integer', enum: [1, 0] }, + }, + }), + responses: { + ...response200('Casts a vote on a proposition. Throws 1018 if already voted.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/energyreserve.ts b/src/spec/paths/buildings/energyreserve.ts new file mode 100644 index 0000000..7851049 --- /dev/null +++ b/src/spec/paths/buildings/energyreserve.ts @@ -0,0 +1,39 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('EnergyReserve'); + +export const energyReserve = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/dump`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'amount'], + properties: { + building_id: { type: 'string' }, + amount: { type: 'integer', description: 'The amount of energy to dump.' }, + }, + }), + responses: { + ...response200('Converts energy into waste.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/entertainment.ts b/src/spec/paths/buildings/entertainment.ts new file mode 100644 index 0000000..a1c6ee6 --- /dev/null +++ b/src/spec/paths/buildings/entertainment.ts @@ -0,0 +1,69 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Entertainment'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +export const entertainment = { + ...buildingCommonMethods(base), + ...buildingView(base, { ducks_quacked: { type: 'integer' } }, ['ducks_quacked']), + + [`${base}/get_lottery_voting_options`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Returns a list of sites the user can vote on. Voting once per site per day enters the empire into a daily lottery for 10 essentia; each vote is equal, but more votes increase the odds of winning. Each url is usable only once every 24 hours.', + { + type: 'object', + required: ['options', 'status'], + properties: { + options: { + type: 'array', + items: { + type: 'object', + properties: { name: { type: 'string' }, url: { type: 'string' } }, + required: ['name', 'url'], + }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/duck_quack`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Returns a fun string of quack text. Formatting (whitespace and carriage returns) must be preserved when displayed to the user.', + { + type: 'object', + required: ['quack', 'status'], + properties: { quack: { type: 'string' }, status: statusSchema() }, + } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/espionage.ts b/src/spec/paths/buildings/espionage.ts new file mode 100644 index 0000000..e7c2d61 --- /dev/null +++ b/src/spec/paths/buildings/espionage.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Espionage'); + +export const espionage = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/essentiavein.ts b/src/spec/paths/buildings/essentiavein.ts new file mode 100644 index 0000000..78d06f7 --- /dev/null +++ b/src/spec/paths/buildings/essentiavein.ts @@ -0,0 +1,49 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('EssentiaVein'); + +export const essentiaVein = { + ...buildingCommonMethods(base), + ...buildingView(base, { + drain_capable: { + type: 'integer', + description: 'How many groups of 30 days can be drained. E.g. 3 means 90-119 days remaining.', + }, + }), + + [`${base}/drain`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + times: { + type: 'integer', + minimum: 1, + description: + "Number of 30-day periods to drain in a single RPC. Instead of 4 essentia/day over 30 days, each period instantly provides 30 essentia. Defaults to 1. Periods less than 30 days can't be drained quickly.", + }, + }, + }), + responses: { + ...response200('Instantly drains one or more 30-day periods of essentia from the vein.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/fission.ts b/src/spec/paths/buildings/fission.ts new file mode 100644 index 0000000..8a053c1 --- /dev/null +++ b/src/spec/paths/buildings/fission.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Fission'); + +export const fission = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/fissure.ts b/src/spec/paths/buildings/fissure.ts new file mode 100644 index 0000000..ce7dbe3 --- /dev/null +++ b/src/spec/paths/buildings/fissure.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Fissure'); + +export const fissure = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/foodreserve.ts b/src/spec/paths/buildings/foodreserve.ts new file mode 100644 index 0000000..015a504 --- /dev/null +++ b/src/spec/paths/buildings/foodreserve.ts @@ -0,0 +1,49 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('FoodReserve'); + +export const foodReserve = { + ...buildingCommonMethods(base), + ...buildingView(base, { + food_stored: { + type: 'object', + description: 'Keyed by food type, e.g. apple, bread, algae.', + additionalProperties: { type: 'integer' }, + }, + }), + + [`${base}/dump`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'type', 'amount'], + properties: { + building_id: { type: 'string' }, + type: { + type: 'string', + description: 'Food type to convert into waste, e.g. apple, corn, burger.', + }, + amount: { type: 'integer' }, + }, + }), + responses: { + ...response200('Converts food into waste.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/fusion.ts b/src/spec/paths/buildings/fusion.ts new file mode 100644 index 0000000..87c8e07 --- /dev/null +++ b/src/spec/paths/buildings/fusion.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Fusion'); + +export const fusion = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/gasgiantlab.ts b/src/spec/paths/buildings/gasgiantlab.ts new file mode 100644 index 0000000..4182262 --- /dev/null +++ b/src/spec/paths/buildings/gasgiantlab.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('GasGiantLab'); + +export const gasGiantLab = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/gasgiantplatform.ts b/src/spec/paths/buildings/gasgiantplatform.ts new file mode 100644 index 0000000..a560306 --- /dev/null +++ b/src/spec/paths/buildings/gasgiantplatform.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('GasGiantPlatform'); + +export const gasGiantPlatform = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/geneticslab.ts b/src/spec/paths/buildings/geneticslab.ts new file mode 100644 index 0000000..608e7d7 --- /dev/null +++ b/src/spec/paths/buildings/geneticslab.ts @@ -0,0 +1,161 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + speciesSchema, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('GeneticsLab'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +const experimentResultSchema = ( + description: string, + extraProperties: object = {}, + extraRequired: string[] = [] +) => ({ + ...response200(description, { + type: 'object', + required: [ + 'status', + 'grafts', + 'survival_odds', + 'graft_odds', + 'essentia_cost', + 'can_experiment', + ...extraRequired, + ], + properties: { + status: statusSchema(), + grafts: { + type: 'array', + items: { + type: 'object', + properties: { + spy: { + type: 'object', + description: 'The prisoner spy available to be experimented on.', + properties: { id: { type: 'string' }, name: { type: 'string' } }, + required: ['id', 'name'], + }, + species: speciesSchema(), + graftable_affinities: { + type: 'array', + items: { type: 'string' }, + description: + "Names of the species attributes this prisoner's traits can be grafted onto.", + }, + }, + required: ['spy', 'species', 'graftable_affinities'], + }, + }, + survival_odds: { + type: 'integer', + description: 'Percent chance the prisoner survives the experiment.', + }, + graft_odds: { type: 'integer', description: 'Percent chance the graft succeeds.' }, + essentia_cost: { type: 'integer' }, + can_experiment: { type: 'integer', enum: [1, 0] }, + ...extraProperties, + }, + }), + ...response500(), +}); + +export const geneticsLab = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/prepare_experiment`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: experimentResultSchema( + 'Returns everything needed to set up a genetic graft experiment.' + ), + }, + }, + + [`${base}/run_experiment`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'spy_id', 'affinity'], + properties: { + building_id: { type: 'string' }, + spy_id: { type: 'string' }, + affinity: { + type: 'string', + description: + "One of the prisoner's graftable_affinities to attempt to graft onto the species.", + }, + }, + }), + responses: experimentResultSchema( + 'Experiments on a prisoner, attempting to graft one of their genetic traits onto the empire species. Returns the same shape as prepare_experiment plus an experiment result.', + { + experiment: { + type: 'object', + properties: { + graft: { type: 'integer', enum: [1, 0], description: 'Whether the graft succeeded.' }, + survive: { + type: 'integer', + enum: [1, 0], + description: 'Whether the prisoner survived.', + }, + message: { type: 'string' }, + }, + required: ['graft', 'survive', 'message'], + }, + }, + ['experiment'] + ), + }, + }, + + [`${base}/rename_species`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'params'], + properties: { + building_id: { type: 'string' }, + params: { + type: 'object', + required: ['name'], + properties: { + name: { + type: 'string', + description: + "The empire's new species name. Limited to 30 characters, cannot be blank, and cannot contain @, &, <, >, or ;.", + }, + description: { + type: 'string', + description: + "The species' description. Limited to 1024 characters, cannot contain < or >.", + }, + }, + }, + }, + }), + responses: { + ...response200( + "Updates the empire's species name and description. Can throw error codes 1000 (name not available) and 1005 (contains invalid characters), with the offending field in the error's data.", + { type: 'object', required: ['success'], properties: { success: { type: 'string' } } } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/geo.ts b/src/spec/paths/buildings/geo.ts new file mode 100644 index 0000000..4228e47 --- /dev/null +++ b/src/spec/paths/buildings/geo.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Geo'); + +export const geo = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/geothermalvent.ts b/src/spec/paths/buildings/geothermalvent.ts new file mode 100644 index 0000000..fe5978b --- /dev/null +++ b/src/spec/paths/buildings/geothermalvent.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('GeoThermalVent'); + +export const geoThermalVent = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/gratchsgauntlet.ts b/src/spec/paths/buildings/gratchsgauntlet.ts new file mode 100644 index 0000000..6da39cd --- /dev/null +++ b/src/spec/paths/buildings/gratchsgauntlet.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('GratchsGauntlet'); + +export const gratchsGauntlet = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/greatballofjunk.ts b/src/spec/paths/buildings/greatballofjunk.ts new file mode 100644 index 0000000..e0fe019 --- /dev/null +++ b/src/spec/paths/buildings/greatballofjunk.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('GreatBallOfJunk'); + +export const greatBallOfJunk = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/grove.ts b/src/spec/paths/buildings/grove.ts new file mode 100644 index 0000000..40a5900 --- /dev/null +++ b/src/spec/paths/buildings/grove.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Grove'); + +export const grove = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/hallsofvrbansk.ts b/src/spec/paths/buildings/hallsofvrbansk.ts new file mode 100644 index 0000000..193fdef --- /dev/null +++ b/src/spec/paths/buildings/hallsofvrbansk.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('HallsOfVrbansk'); + +export const hallsOfVrbansk = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/hydrocarbon.ts b/src/spec/paths/buildings/hydrocarbon.ts new file mode 100644 index 0000000..df86d35 --- /dev/null +++ b/src/spec/paths/buildings/hydrocarbon.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Hydrocarbon'); + +export const hydrocarbon = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/index.ts b/src/spec/paths/buildings/index.ts new file mode 100644 index 0000000..0a6208e --- /dev/null +++ b/src/spec/paths/buildings/index.ts @@ -0,0 +1,269 @@ +import { archaeology } from './archaeology'; +import { shipyard } from './shipyard'; +import { trade } from './trade'; +import { intelligence } from './intelligence'; +import { oreStorage } from './orestorage'; +import { planetaryCommand } from './planetarycommand'; +import { embassy } from './embassy'; +import { capitol } from './capitol'; + +import { algae } from './algae'; +import { algaePond } from './algaepond'; +import { amalgusMeadow } from './amalgusmeadow'; +import { apple } from './apple'; +import { atmosphericEvaporator } from './atmosphericevaporator'; +import { beach } from './beach'; +import { bean } from './bean'; +import { beeldeban } from './beeldeban'; +import { beeldebanNest } from './beeldebannest'; +import { blackHoleGenerator } from './blackholegenerator'; +import { bread } from './bread'; +import { burger } from './burger'; +import { cheese } from './cheese'; +import { chip } from './chip'; +import { cider } from './cider'; + +import { citadelOfKnope } from './citadelofknope'; +import { cloakingLab } from './cloakinglab'; +import { corn } from './corn'; +import { cornMeal } from './cornmeal'; +import { crashedShipSite } from './crashedshipsite'; +import { crater } from './crater'; +import { dairy } from './dairy'; +import { denton } from './denton'; +import { dentonBrambles } from './dentonbrambles'; +import { deployedBleeder } from './deployedbleeder'; +import { development } from './development'; +import { distributionCenter } from './distributioncenter'; +import { energyReserve } from './energyreserve'; +import { entertainment } from './entertainment'; +import { espionage } from './espionage'; + +import { essentiaVein } from './essentiavein'; +import { fission } from './fission'; +import { fissure } from './fissure'; +import { foodReserve } from './foodreserve'; +import { fusion } from './fusion'; +import { gasGiantLab } from './gasgiantlab'; +import { gasGiantPlatform } from './gasgiantplatform'; +import { geneticsLab } from './geneticslab'; +import { geo } from './geo'; +import { geoThermalVent } from './geothermalvent'; +import { gratchsGauntlet } from './gratchsgauntlet'; +import { greatBallOfJunk } from './greatballofjunk'; +import { grove } from './grove'; +import { hallsOfVrbansk } from './hallsofvrbansk'; +import { hydrocarbon } from './hydrocarbon'; + +import { intelTraining } from './inteltraining'; +import { interDimensionalRift } from './interdimensionalrift'; +import { junkHengeSculpture } from './junkhengesculpture'; +import { kalavianRuins } from './kalavianruins'; +import { kasternsKeep } from './kasternskeep'; +import { lake } from './lake'; +import { lagoon } from './lagoon'; +import { lapis } from './lapis'; +import { lapisForest } from './lapisforest'; +import { libraryOfJith } from './libraryofjith'; +import { lostCityOfTyleon } from './lostcityoftyleon'; +import { luxuryHousing } from './luxuryhousing'; +import { malcud } from './malcud'; +import { malcudField } from './malcudfield'; +import { massadsHenge } from './massadshenge'; + +import { mayhemTraining } from './mayhemtraining'; +import { mercenariesGuild } from './mercenariesguild'; +import { metalJunkArches } from './metaljunkarches'; +import { mine } from './mine'; +import { miningMinistry } from './miningministry'; +import { missionCommand } from './missioncommand'; +import { munitionsLab } from './munitionslab'; +import { naturalSpring } from './naturalspring'; +import { network19 } from './network19'; +import { observatory } from './observatory'; +import { oracleOfAnid } from './oracleofanid'; +import { oreRefinery } from './orerefinery'; +import { oversight } from './oversight'; +import { pancake } from './pancake'; +import { pantheonOfHagness } from './pantheonofhagness'; + +import { park } from './park'; +import { pie } from './pie'; +import { pilotTraining } from './pilottraining'; +import { politicsTraining } from './politicstraining'; +import { potato } from './potato'; +import { propulsion } from './propulsion'; +import { pyramidJunkSculpture } from './pyramidjunksculpture'; +import { ravine } from './ravine'; +import { rockyOutcrop } from './rockyoutcrop'; +import { sand } from './sand'; +import { saw } from './saw'; +import { security_ } from './security'; +import { shake } from './shake'; +import { singularity } from './singularity'; +import { soup } from './soup'; + +import { spaceJunkPark } from './spacejunkpark'; +import { spacePort } from './spaceport'; +import { spaceStationLab } from './spacestationlab'; +import { stockpile } from './stockpile'; +import { subspaceSupplyDepot } from './subspacesupplydepot'; +import { supplyPod } from './supplypod'; +import { syrup } from './syrup'; +import { templeOfTheDrajilites } from './templeofthedrajilites'; +import { terraformingLab } from './terraforminglab'; +import { terraformingPlatform } from './terraformingplatform'; +import { theDillonForge } from './thedillonforge'; +import { theftTraining } from './thefttraining'; +import { themePark } from './themepark'; +import { transporter } from './transporter'; +import { university } from './university'; + +import { volcano } from './volcano'; +import { wasteDigester } from './wastedigester'; +import { wasteEnergy } from './wasteenergy'; +import { wasteExchanger } from './wasteexchanger'; +import { wasteRecycling } from './wasterecycling'; +import { wasteSequestration } from './wastesequestration'; +import { wasteTreatment } from './wastetreatment'; +import { waterProduction } from './waterproduction'; +import { waterPurification } from './waterpurification'; +import { waterReclamation } from './waterreclamation'; +import { waterStorage } from './waterstorage'; +import { wheat } from './wheat'; + +export const buildings = { + ...archaeology, + ...shipyard, + ...trade, + ...intelligence, + ...oreStorage, + ...planetaryCommand, + ...embassy, + ...capitol, + + ...algae, + ...algaePond, + ...amalgusMeadow, + ...apple, + ...atmosphericEvaporator, + ...beach, + ...bean, + ...beeldeban, + ...beeldebanNest, + ...blackHoleGenerator, + ...bread, + ...burger, + ...cheese, + ...chip, + ...cider, + + ...citadelOfKnope, + ...cloakingLab, + ...corn, + ...cornMeal, + ...crashedShipSite, + ...crater, + ...dairy, + ...denton, + ...dentonBrambles, + ...deployedBleeder, + ...development, + ...distributionCenter, + ...energyReserve, + ...entertainment, + ...espionage, + + ...essentiaVein, + ...fission, + ...fissure, + ...foodReserve, + ...fusion, + ...gasGiantLab, + ...gasGiantPlatform, + ...geneticsLab, + ...geo, + ...geoThermalVent, + ...gratchsGauntlet, + ...greatBallOfJunk, + ...grove, + ...hallsOfVrbansk, + ...hydrocarbon, + + ...intelTraining, + ...interDimensionalRift, + ...junkHengeSculpture, + ...kalavianRuins, + ...kasternsKeep, + ...lake, + ...lagoon, + ...lapis, + ...lapisForest, + ...libraryOfJith, + ...lostCityOfTyleon, + ...luxuryHousing, + ...malcud, + ...malcudField, + ...massadsHenge, + + ...mayhemTraining, + ...mercenariesGuild, + ...metalJunkArches, + ...mine, + ...miningMinistry, + ...missionCommand, + ...munitionsLab, + ...naturalSpring, + ...network19, + ...observatory, + ...oracleOfAnid, + ...oreRefinery, + ...oversight, + ...pancake, + ...pantheonOfHagness, + + ...park, + ...pie, + ...pilotTraining, + ...politicsTraining, + ...potato, + ...propulsion, + ...pyramidJunkSculpture, + ...ravine, + ...rockyOutcrop, + ...sand, + ...saw, + ...security_, + ...shake, + ...singularity, + ...soup, + + ...spaceJunkPark, + ...spacePort, + ...spaceStationLab, + ...stockpile, + ...subspaceSupplyDepot, + ...supplyPod, + ...syrup, + ...templeOfTheDrajilites, + ...terraformingLab, + ...terraformingPlatform, + ...theDillonForge, + ...theftTraining, + ...themePark, + ...transporter, + ...university, + + ...volcano, + ...wasteDigester, + ...wasteEnergy, + ...wasteExchanger, + ...wasteRecycling, + ...wasteSequestration, + ...wasteTreatment, + ...waterProduction, + ...waterPurification, + ...waterReclamation, + ...waterStorage, + ...wheat, +}; diff --git a/src/spec/paths/buildings/intelligence.ts b/src/spec/paths/buildings/intelligence.ts new file mode 100644 index 0000000..2d6b4d6 --- /dev/null +++ b/src/spec/paths/buildings/intelligence.ts @@ -0,0 +1,346 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Intelligence'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +const ASSIGNMENTS = [ + 'Idle', + 'Bugout', + 'Counter Espionage', + 'Security Sweep', + 'Intel Training', + 'Mayhem Training', + 'Politics Training', + 'Theft Training', + 'Political Propaganda', + 'Gather Resource Intelligence', + 'Gather Empire Intelligence', + 'Gather Operative Intelligence', + 'Hack Network 19', + 'Sabotage Probes', + 'Rescue Comrades', + 'Sabotage Resources', + 'Appropriate Resources', + 'Assassinate Operatives', + 'Sabotage Infrastructure', + 'Sabotage Defenses', + 'Sabotage BHG', + 'Incite Mutiny', + 'Abduct Operatives', + 'Appropriate Technology', + 'Incite Rebellion', + 'Incite Insurrection', +]; + +const spySchema = { + type: 'object', + required: [ + 'id', + 'name', + 'assignment', + 'level', + 'politics', + 'mayhem', + 'theft', + 'intel', + 'is_available', + ], + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + assignment: { type: 'string' }, + possible_assignments: { + type: 'array', + items: { + type: 'object', + properties: { + task: { type: 'string' }, + recovery: { type: 'integer' }, + skill: { type: 'string' }, + }, + }, + }, + level: { type: 'integer' }, + politics: { type: 'integer' }, + mayhem: { type: 'integer' }, + theft: { type: 'integer' }, + intel: { type: 'integer' }, + offense_rating: { type: 'integer' }, + defense_rating: { type: 'integer' }, + assigned_to: { + type: 'object', + properties: { + body_id: { type: 'string' }, + name: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + }, + }, + based_from: { + type: 'object', + properties: { + body_id: { type: 'string' }, + name: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + }, + }, + is_available: { type: 'integer', enum: [1, 0] }, + available_on: { type: 'string' }, + started_assignment: { type: 'string' }, + seconds_remaining: { type: 'integer' }, + mission_count: { + type: 'object', + properties: { offensive: { type: 'integer' }, defensive: { type: 'integer' } }, + }, + }, +}; + +export const intelligence = { + ...buildingCommonMethods(base), + ...buildingView(base, { + spies: { + type: 'object', + properties: { + maximum: { type: 'integer' }, + current: { type: 'integer' }, + in_training: { type: 'integer' }, + training_costs: { $ref: '#/components/schemas/building_cost' }, + }, + }, + }), + + [`${base}/train_spy`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + quantity: { type: 'integer', minimum: 1, maximum: 5, description: 'Defaults to 1.' }, + }, + }), + responses: { + ...response200('Queues spies for training. Throws 1013, 1009.', { + type: 'object', + required: ['trained', 'not_trained', 'status'], + properties: { + trained: { type: 'integer' }, + not_trained: { type: 'integer' }, + reason_not_trained: { + type: 'object', + properties: { code: { type: 'integer' }, message: { type: 'string' } }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_spies`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { type: 'integer', description: 'Defaults to 1. 30 per page.' }, + }, + }), + responses: { + ...response200('Retrieves a paginated spy roster.', { + type: 'object', + required: ['spies', 'spy_count', 'status'], + properties: { + spies: { type: 'array', items: spySchema }, + spy_count: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_all_spies`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Retrieves the complete (non-paginated) spy roster.', { + type: 'object', + required: ['spies', 'spy_count', 'status'], + properties: { + spies: { type: 'array', items: spySchema }, + spy_count: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/subsidize_training`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Completes all in-training spies immediately for 1 essentia per spy. Returns the building view. Throws 1011.', + { + type: 'object', + required: ['building', 'status'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/burn_spy`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'spy_id'], + properties: { building_id: { type: 'string' }, spy_id: { type: 'string' } }, + }), + responses: { + ...response200('Eliminates a spy from payroll. Throws 1002, 1010.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/name_spy`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'spy_id', 'name'], + properties: { + building_id: { type: 'string' }, + spy_id: { type: 'string' }, + name: { type: 'string', description: 'Cannot contain @, <, #, &, ; or profanity.' }, + }, + }), + responses: { + ...response200("Sets a spy's name. Throws 1002, 1005, 1013.", { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/name_spies`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + prefix: { type: 'string' }, + suffix: { type: 'string' }, + rename_null_only: { + type: 'boolean', + description: 'When true, only renames spies still named "Agent Null".', + }, + }, + }), + responses: { + ...response200('Batch-names spies using the pattern "prefix ## suffix".', { + type: 'object', + required: ['spies', 'spy_count', 'renamed', 'status'], + properties: { + spies: { type: 'array', items: spySchema }, + spy_count: { type: 'integer' }, + renamed: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/assign_spy`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'spy_id', 'assignment'], + properties: { + building_id: { type: 'string' }, + spy_id: { type: 'string' }, + assignment: { + oneOf: [ + { type: 'string', enum: ASSIGNMENTS }, + { + type: 'object', + required: ['assignment'], + properties: { + assignment: { type: 'string', enum: ASSIGNMENTS }, + noempty: { + type: 'boolean', + description: + 'For Security Sweep: suppress the email sent when no spies are found.', + }, + }, + }, + ], + }, + }, + }), + responses: { + ...response200('Assigns a spy to a new task.', { + type: 'object', + required: ['mission', 'spy', 'status'], + properties: { + mission: { + type: 'object', + properties: { + result: { type: 'string', enum: ['Accepted', 'Success', 'Bounce', 'Failure'] }, + message_id: { type: 'string' }, + reason: { type: 'string' }, + }, + }, + spy: spySchema, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/inteltraining.ts b/src/spec/paths/buildings/inteltraining.ts new file mode 100644 index 0000000..0126d18 --- /dev/null +++ b/src/spec/paths/buildings/inteltraining.ts @@ -0,0 +1,19 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('IntelTraining'); + +export const intelTraining = { + ...buildingCommonMethods(base), + ...buildingView(base, { + spies: { + type: 'object', + description: 'Summary of spy training capacity for this facility.', + properties: { + max_points: { type: 'integer' }, + points_per: { type: 'integer' }, + in_training: { type: 'integer' }, + }, + required: ['max_points', 'points_per', 'in_training'], + }, + }), +}; diff --git a/src/spec/paths/buildings/interdimensionalrift.ts b/src/spec/paths/buildings/interdimensionalrift.ts new file mode 100644 index 0000000..2b4ed3e --- /dev/null +++ b/src/spec/paths/buildings/interdimensionalrift.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('InterDimensionalRift'); + +export const interDimensionalRift = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/junkhengesculpture.ts b/src/spec/paths/buildings/junkhengesculpture.ts new file mode 100644 index 0000000..43e5f1f --- /dev/null +++ b/src/spec/paths/buildings/junkhengesculpture.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('JunkHengeSculpture'); + +export const junkHengeSculpture = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/kalavianruins.ts b/src/spec/paths/buildings/kalavianruins.ts new file mode 100644 index 0000000..9c000ba --- /dev/null +++ b/src/spec/paths/buildings/kalavianruins.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('KalavianRuins'); + +export const kalavianRuins = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/kasternskeep.ts b/src/spec/paths/buildings/kasternskeep.ts new file mode 100644 index 0000000..189017c --- /dev/null +++ b/src/spec/paths/buildings/kasternskeep.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('KasternsKeep'); + +export const kasternsKeep = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/lagoon.ts b/src/spec/paths/buildings/lagoon.ts new file mode 100644 index 0000000..6d0bd00 --- /dev/null +++ b/src/spec/paths/buildings/lagoon.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Lagoon'); + +export const lagoon = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/lake.ts b/src/spec/paths/buildings/lake.ts new file mode 100644 index 0000000..4075527 --- /dev/null +++ b/src/spec/paths/buildings/lake.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Lake'); + +export const lake = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/lapis.ts b/src/spec/paths/buildings/lapis.ts new file mode 100644 index 0000000..80f965a --- /dev/null +++ b/src/spec/paths/buildings/lapis.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Lapis'); + +export const lapis = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/lapisforest.ts b/src/spec/paths/buildings/lapisforest.ts new file mode 100644 index 0000000..34620e9 --- /dev/null +++ b/src/spec/paths/buildings/lapisforest.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('LapisForest'); + +export const lapisForest = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/libraryofjith.ts b/src/spec/paths/buildings/libraryofjith.ts new file mode 100644 index 0000000..6c55af0 --- /dev/null +++ b/src/spec/paths/buildings/libraryofjith.ts @@ -0,0 +1,43 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + speciesSchema, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('LibraryOfJith'); + +export const libraryOfJith = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/research_species`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'empire_id'], + properties: { + building_id: { type: 'string' }, + empire_id: { + type: 'string', + description: "The unique id of an empire you'd like to know more about.", + }, + }, + }), + responses: { + ...response200('Returns species stats for any species in the game.', { + type: 'object', + required: ['species', 'status'], + properties: { species: speciesSchema(), status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/lostcityoftyleon.ts b/src/spec/paths/buildings/lostcityoftyleon.ts new file mode 100644 index 0000000..032566b --- /dev/null +++ b/src/spec/paths/buildings/lostcityoftyleon.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('LostCityOfTyleon'); + +export const lostCityOfTyleon = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/luxuryhousing.ts b/src/spec/paths/buildings/luxuryhousing.ts new file mode 100644 index 0000000..63bfe0d --- /dev/null +++ b/src/spec/paths/buildings/luxuryhousing.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('LuxuryHousing'); + +export const luxuryHousing = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/malcud.ts b/src/spec/paths/buildings/malcud.ts new file mode 100644 index 0000000..2fa2644 --- /dev/null +++ b/src/spec/paths/buildings/malcud.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Malcud'); + +export const malcud = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/malcudfield.ts b/src/spec/paths/buildings/malcudfield.ts new file mode 100644 index 0000000..19d7ba1 --- /dev/null +++ b/src/spec/paths/buildings/malcudfield.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('MalcudField'); + +export const malcudField = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/massadshenge.ts b/src/spec/paths/buildings/massadshenge.ts new file mode 100644 index 0000000..c90aa92 --- /dev/null +++ b/src/spec/paths/buildings/massadshenge.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('MassadsHenge'); + +export const massadsHenge = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/mayhemtraining.ts b/src/spec/paths/buildings/mayhemtraining.ts new file mode 100644 index 0000000..9a1fdd3 --- /dev/null +++ b/src/spec/paths/buildings/mayhemtraining.ts @@ -0,0 +1,18 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('MayhemTraining'); + +export const mayhemTraining = { + ...buildingCommonMethods(base), + ...buildingView(base, { + spies: { + type: 'object', + properties: { + max_points: { type: 'integer' }, + points_per: { type: 'integer' }, + in_training: { type: 'integer' }, + }, + required: ['max_points', 'points_per', 'in_training'], + }, + }), +}; diff --git a/src/spec/paths/buildings/mercenariesguild.ts b/src/spec/paths/buildings/mercenariesguild.ts new file mode 100644 index 0000000..8a93211 --- /dev/null +++ b/src/spec/paths/buildings/mercenariesguild.ts @@ -0,0 +1,266 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('MercenariesGuild'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +const tradeEntrySchema = { + type: 'object', + properties: { + date_offered: { type: 'string' }, + id: { type: 'string' }, + ask: { type: 'integer', description: 'Amount of essentia being asked for.' }, + offer: { type: 'array', items: { type: 'string' } }, + body: { + type: 'object', + description: + 'Only present on view_market. Use with get_trade_ships to determine travel time.', + properties: { id: { type: 'string' } }, + required: ['id'], + }, + empire: { + type: 'object', + description: 'Only present on view_market.', + properties: { id: { type: 'string' }, name: { type: 'string' } }, + required: ['id', 'name'], + }, + }, + required: ['date_offered', 'id', 'ask', 'offer'], +}; + +export const mercenariesGuild = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/add_to_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'spy_id', 'ask'], + properties: { + building_id: { type: 'string' }, + spy_id: { type: 'string', description: 'See get_spies for a list of your spies.' }, + ask: { + type: 'integer', + minimum: 1, + maximum: 99, + description: 'Amount of essentia being asked for.', + }, + ship_id: { type: 'string', description: 'Optional. See get_trade_ships for details.' }, + }, + }), + responses: { + ...response200('Queues a trade of a spy for others to see.', { + type: 'object', + required: ['trade_id', 'status'], + properties: { trade_id: { type: 'string' }, status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_spies`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Returns a list of spies that may be traded. Used with add_to_market.', { + type: 'object', + required: ['spies', 'cargo_space_used_each', 'status'], + properties: { + spies: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + level: { type: 'integer' }, + }, + required: ['id', 'name', 'level'], + }, + }, + cargo_space_used_each: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/withdraw_from_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'trade_id'], + properties: { building_id: { type: 'string' }, trade_id: { type: 'string' } }, + }), + responses: { + ...response200( + 'Removes a trade that you have offered and collects the items up for trade.', + { type: 'object', required: ['status'], properties: { status: statusSchema() } } + ), + ...response500(), + }, + }, + }, + + [`${base}/accept_from_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'trade_id'], + properties: { building_id: { type: 'string' }, trade_id: { type: 'string' } }, + }), + responses: { + ...response200( + 'Accepts a trade offer from the list of available trades. See view_market.', + { type: 'object', required: ['status'], properties: { status: statusSchema() } } + ), + ...response500(), + }, + }, + }, + + [`${base}/view_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { + type: 'integer', + description: 'Optional. Defaults to 1. 25 trades per page.', + }, + }, + }), + responses: { + ...response200('Displays a list of trades available at the present time.', { + type: 'object', + required: ['trades', 'trade_count', 'page_number', 'status'], + properties: { + trades: { type: 'array', items: tradeEntrySchema }, + trade_count: { type: 'integer' }, + page_number: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_my_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { + type: 'integer', + description: 'Optional. Defaults to 1. 25 trades per page.', + }, + }, + }), + responses: { + ...response200('Displays a list of trades the current user has posted.', { + type: 'object', + required: ['trades', 'trade_count', 'page_number', 'status'], + properties: { + trades: { type: 'array', items: tradeEntrySchema }, + trade_count: { type: 'integer' }, + page_number: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_trade_ships`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + target_body_id: { + type: 'string', + description: + 'Optional. If included, the estimated travel time to this body is calculated.', + }, + }, + }), + responses: { + ...response200('Returns a list of the ships that could be used to do a trade.', { + type: 'object', + required: ['ships', 'status'], + properties: { + ships: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + type: { type: 'string' }, + name: { type: 'string' }, + estimated_travel_time: { + type: 'integer', + description: + 'In seconds, one way. Only present when target_body_id is provided.', + }, + }, + required: ['id', 'type', 'name'], + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/report_abuse`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'trade_id'], + properties: { building_id: { type: 'string' }, trade_id: { type: 'string' } }, + }), + responses: { + ...response200('Reports a trade that is suspected of abusing the trade system.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/metaljunkarches.ts b/src/spec/paths/buildings/metaljunkarches.ts new file mode 100644 index 0000000..61a949e --- /dev/null +++ b/src/spec/paths/buildings/metaljunkarches.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('MetalJunkArches'); + +export const metalJunkArches = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/mine.ts b/src/spec/paths/buildings/mine.ts new file mode 100644 index 0000000..597e640 --- /dev/null +++ b/src/spec/paths/buildings/mine.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Mine'); + +export const mine = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/miningministry.ts b/src/spec/paths/buildings/miningministry.ts new file mode 100644 index 0000000..9a801ef --- /dev/null +++ b/src/spec/paths/buildings/miningministry.ts @@ -0,0 +1,203 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('MiningMinistry'); + +const ORE_TYPES = [ + 'rutile', + 'chromite', + 'chalcopyrite', + 'galena', + 'gold', + 'uraninite', + 'bauxite', + 'goethite', + 'halite', + 'gypsum', + 'trona', + 'kerogen', + 'methane', + 'anthracite', + 'sulfur', + 'zircon', + 'monazite', + 'fluorite', + 'beryl', + 'magnetite', +]; + +const oreHourProperties = Object.fromEntries( + ORE_TYPES.map((ore) => [`${ore}_hour`, { type: 'integer' }]) +); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +export const miningMinistry = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/view_platforms`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Returns a list of the mining platforms currently controlled by this ministry.', + { + type: 'object', + required: ['max_platforms', 'platforms', 'status'], + properties: { + max_platforms: { type: 'integer' }, + platforms: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + asteroid: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + image: { type: 'string' }, + }, + required: ['id', 'name', 'x', 'y', 'image'], + }, + ...oreHourProperties, + shipping_capacity: { + type: 'integer', + description: + 'A percent indicating production vs shipping efficiency. -1 means no ships are servicing the platforms, 0 means ships but no production, 1-99 means more shipping capacity than production, 100 means production and shipping are in harmony, and greater than 100 means more ships are needed.', + }, + }, + required: ['id', 'asteroid', 'shipping_capacity'], + }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/view_ships`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Shows the ships that are working in the mining fleet, and available to work in it.', + { + type: 'object', + required: ['ships', 'status'], + properties: { + ships: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + id: { type: 'string' }, + task: { type: 'string' }, + speed: { type: 'integer' }, + hold_size: { type: 'integer' }, + }, + required: ['name', 'id', 'task', 'speed', 'hold_size'], + }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/add_cargo_ship_to_fleet`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'ship_id'], + properties: { building_id: { type: 'string' }, ship_id: { type: 'string' } }, + }), + responses: { + ...response200('Takes a cargo ship from the space port and adds it to the mining fleet.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/remove_cargo_ship_from_fleet`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'ship_id'], + properties: { building_id: { type: 'string' }, ship_id: { type: 'string' } }, + }), + responses: { + ...response200( + 'Tells one of the cargo ships in the mining fleet to come home and park at the space port.', + { type: 'object', required: ['status'], properties: { status: statusSchema() } } + ), + ...response500(), + }, + }, + }, + + [`${base}/abandon_platform`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'platform_id'], + properties: { building_id: { type: 'string' }, platform_id: { type: 'string' } }, + }), + responses: { + ...response200('Closes down an existing mining platform.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/mass_abandon_platform`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Destroys all platforms controlled by this ministry.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/missioncommand.ts b/src/spec/paths/buildings/missioncommand.ts new file mode 100644 index 0000000..843ae64 --- /dev/null +++ b/src/spec/paths/buildings/missioncommand.ts @@ -0,0 +1,106 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('MissionCommand'); + +const missionIdRequestBody = (extraDescription: string) => + requestBodySchema({ + type: 'object', + required: ['building_id', 'mission_id'], + properties: { + building_id: { type: 'string' }, + mission_id: { type: 'string', description: extraDescription }, + }, + }); + +export const missionCommand = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/get_missions`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, + }), + responses: { + ...response200( + "Returns a (non-exhaustive) list of missions eligible to be completed in this zone. Excludes missions already completed or above the empire's university level.", + { + type: 'object', + required: ['missions', 'status'], + properties: { + missions: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + max_university_level: { type: 'integer' }, + date_posted: { type: 'string' }, + name: { type: 'string' }, + description: { type: 'string' }, + objectives: { type: 'array', items: { type: 'string' } }, + rewards: { type: 'array', items: { type: 'string' } }, + }, + required: [ + 'id', + 'max_university_level', + 'date_posted', + 'name', + 'description', + 'objectives', + 'rewards', + ], + }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/complete_mission`]: { + post: { + ...security(), + ...missionIdRequestBody('The unique id of the mission to complete.'), + responses: { + ...response200( + 'Completes a mission. Rejected if the objectives are not all met; otherwise the rewards are distributed.', + { type: 'object', required: ['status'], properties: { status: statusSchema() } } + ), + ...response500(), + }, + }, + }, + + [`${base}/skip_mission`]: { + post: { + ...security(), + ...missionIdRequestBody( + "The unique id of the mission to skip. Won't appear again for this empire for 30 days." + ), + responses: { + ...response200('Skips a mission, hiding it from this list for 30 days.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/munitionslab.ts b/src/spec/paths/buildings/munitionslab.ts new file mode 100644 index 0000000..f827b1d --- /dev/null +++ b/src/spec/paths/buildings/munitionslab.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('MunitionsLab'); + +export const munitionsLab = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/naturalspring.ts b/src/spec/paths/buildings/naturalspring.ts new file mode 100644 index 0000000..021a84d --- /dev/null +++ b/src/spec/paths/buildings/naturalspring.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('NaturalSpring'); + +export const naturalSpring = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/network19.ts b/src/spec/paths/buildings/network19.ts new file mode 100644 index 0000000..c51ae96 --- /dev/null +++ b/src/spec/paths/buildings/network19.ts @@ -0,0 +1,87 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Network19'); + +export const network19 = { + ...buildingCommonMethods(base), + ...buildingView(base, { + restrict_coverage: { + type: 'integer', + enum: [1, 0], + description: + 'Whether a policy restricting coverage of this planet is currently in effect. See restrict_coverage.', + }, + }), + + [`${base}/restrict_coverage`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'onoff'], + properties: { + building_id: { type: 'string' }, + onoff: { + type: 'integer', + enum: [1, 0], + description: + 'Whether to restrict what Network 19 covers about your planet. Restricting makes citizens unhappy.', + }, + }, + }), + responses: { + ...response200( + 'Enacts or disbands a policy restricting what Network 19 covers about your planet.', + { type: 'object', required: ['status'], properties: { status: statusSchema() } } + ), + ...response500(), + }, + }, + }, + + [`${base}/view_news`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, + }), + responses: { + ...response200( + 'Returns the top 100 headlines from this zone, and a list of RSS feeds usable outside the game to see the same news.', + { + type: 'object', + required: ['news', 'feeds', 'status'], + properties: { + news: { + type: 'array', + items: { + type: 'object', + properties: { headline: { type: 'string' }, date: { type: 'string' } }, + required: ['headline', 'date'], + }, + }, + feeds: { + type: 'object', + description: 'Keyed by zone coordinates (e.g. "0|0|0"), values are RSS feed URLs.', + additionalProperties: { type: 'string' }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/observatory.ts b/src/spec/paths/buildings/observatory.ts new file mode 100644 index 0000000..70bae61 --- /dev/null +++ b/src/spec/paths/buildings/observatory.ts @@ -0,0 +1,108 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Observatory'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +const starSchema = { + type: 'object', + properties: { + id: { type: 'string' }, + color: { type: 'string' }, + name: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + z: { type: 'integer' }, + bodies: { type: 'array', items: { $ref: '#/components/schemas/body_status' } }, + }, + required: ['id', 'color', 'name', 'x', 'y', 'z', 'bodies'], +}; + +export const observatory = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/get_probed_stars`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { + type: 'integer', + description: + 'Optional. Which page of probes to return. Defaults to 1. Up to 25 probes per page.', + }, + }, + }), + responses: { + ...response200('Returns a list of the stars that have been probed by this planet.', { + type: 'object', + required: ['stars', 'star_count', 'max_probes', 'travelling', 'status'], + properties: { + stars: { type: 'array', items: starSchema }, + star_count: { type: 'integer' }, + max_probes: { type: 'integer' }, + travelling: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/abandon_probe`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'star_id'], + properties: { + building_id: { type: 'string' }, + star_id: { + type: 'string', + description: 'The unique id of the star the probe is attached to.', + }, + }, + }), + responses: { + ...response200('Deactivates a single probe, allowing it to burn up in the star.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/abandon_all_probes`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Deactivates all probes controlled by this observatory, allowing them to burn up in the stars.', + { type: 'object', required: ['status'], properties: { status: statusSchema() } } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/oracleofanid.ts b/src/spec/paths/buildings/oracleofanid.ts new file mode 100644 index 0000000..87f904a --- /dev/null +++ b/src/spec/paths/buildings/oracleofanid.ts @@ -0,0 +1,89 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('OracleOfAnid'); + +const starSchema = { + type: 'object', + properties: { + id: { type: 'string' }, + color: { type: 'string' }, + name: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + z: { type: 'integer' }, + bodies: { type: 'array', items: { $ref: '#/components/schemas/body_status' } }, + }, + required: ['id', 'color', 'name', 'x', 'y', 'z', 'bodies'], +}; + +export const oracleOfAnid = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/get_star`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'star_id'], + properties: { building_id: { type: 'string' }, star_id: { type: 'string' } }, + }), + responses: { + ...response200( + "Retrieves info on a single star, including its bodies, even without a probe there. The Oracle's range is 10 map units per level; requesting a star outside that range throws 1009. Use Map/search_stars to look up a star's id by name.", + { + type: 'object', + required: ['star', 'status'], + properties: { star: starSchema, status: statusSchema() }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/get_probed_stars`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { + type: 'integer', + description: 'Optional. Defaults to 1. Each page contains page_size records.', + }, + page_size: { + type: 'integer', + minimum: 1, + maximum: 200, + description: 'Optional. Defaults to 25.', + }, + }, + }), + responses: { + ...response200('Returns all stars within range of the Oracle.', { + type: 'object', + required: ['stars', 'star_count', 'max_distance', 'status'], + properties: { + stars: { type: 'array', items: starSchema }, + star_count: { type: 'integer' }, + max_distance: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/orerefinery.ts b/src/spec/paths/buildings/orerefinery.ts new file mode 100644 index 0000000..76d8a7a --- /dev/null +++ b/src/spec/paths/buildings/orerefinery.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('OreRefinery'); + +export const oreRefinery = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/orestorage.ts b/src/spec/paths/buildings/orestorage.ts new file mode 100644 index 0000000..04df6b7 --- /dev/null +++ b/src/spec/paths/buildings/orestorage.ts @@ -0,0 +1,49 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('OreStorage'); + +export const oreStorage = { + ...buildingCommonMethods(base), + ...buildingView(base, { + ore_stored: { + type: 'object', + description: 'Keyed by ore type.', + additionalProperties: { type: 'integer' }, + }, + }), + + [`${base}/dump`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'type', 'amount'], + properties: { + building_id: { type: 'string' }, + type: { + type: 'string', + description: 'Ore type to convert into waste, e.g. gold, bauxite, galena.', + }, + amount: { type: 'integer' }, + }, + }), + responses: { + ...response200('Converts ore into waste.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/oversight.ts b/src/spec/paths/buildings/oversight.ts new file mode 100644 index 0000000..84832de --- /dev/null +++ b/src/spec/paths/buildings/oversight.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Oversight'); + +export const oversight = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/pancake.ts b/src/spec/paths/buildings/pancake.ts new file mode 100644 index 0000000..f8949fc --- /dev/null +++ b/src/spec/paths/buildings/pancake.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Pancake'); + +export const pancake = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/pantheonofhagness.ts b/src/spec/paths/buildings/pantheonofhagness.ts new file mode 100644 index 0000000..4ecda46 --- /dev/null +++ b/src/spec/paths/buildings/pantheonofhagness.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('PantheonOfHagness'); + +export const pantheonOfHagness = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/park.ts b/src/spec/paths/buildings/park.ts new file mode 100644 index 0000000..80eb83c --- /dev/null +++ b/src/spec/paths/buildings/park.ts @@ -0,0 +1,74 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Park'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +const viewResultSchema = (description: string) => ({ + ...response200(description, { + type: 'object', + required: ['building', 'status', 'party'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + party: { + type: 'object', + properties: { + seconds_remaining: { type: 'integer' }, + happiness: { type: 'integer' }, + can_throw: { type: 'integer', enum: [1, 0] }, + }, + required: ['seconds_remaining', 'happiness', 'can_throw'], + }, + }, + }), + ...response500(), +}); + +export const park = { + ...buildingCommonMethods(base), + ...buildingView(base, { + party: { + type: 'object', + properties: { + seconds_remaining: { type: 'integer' }, + happiness: { type: 'integer' }, + can_throw: { type: 'integer', enum: [1, 0] }, + }, + required: ['seconds_remaining', 'happiness', 'can_throw'], + }, + }), + + [`${base}/throw_a_party`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: viewResultSchema( + 'Spends 10,000 food to throw a day-long party generating happiness. Returns the building view.' + ), + }, + }, + + [`${base}/subsidize_party`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: viewResultSchema( + 'Spends 2 essentia to complete the current party immediately. Returns the building view.' + ), + }, + }, +}; diff --git a/src/spec/paths/buildings/pie.ts b/src/spec/paths/buildings/pie.ts new file mode 100644 index 0000000..a86afe3 --- /dev/null +++ b/src/spec/paths/buildings/pie.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Pie'); + +export const pie = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/pilottraining.ts b/src/spec/paths/buildings/pilottraining.ts new file mode 100644 index 0000000..48a40dc --- /dev/null +++ b/src/spec/paths/buildings/pilottraining.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('PilotTraining'); + +export const pilotTraining = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/planetarycommand.ts b/src/spec/paths/buildings/planetarycommand.ts new file mode 100644 index 0000000..1a5ec9b --- /dev/null +++ b/src/spec/paths/buildings/planetarycommand.ts @@ -0,0 +1,124 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('PlanetaryCommand'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +export const planetaryCommand = { + ...buildingCommonMethods(base), + ...buildingView(base, { + next_colony_cost: { + type: 'integer', + description: 'Happiness required to settle the next colony.', + }, + food: { + type: 'object', + description: 'Hourly rate and stored amount, keyed by food type (algae, bean, etc).', + additionalProperties: { type: 'integer' }, + }, + ore: { + type: 'object', + description: 'Hourly rate and stored amount, keyed by ore type.', + additionalProperties: { type: 'integer' }, + }, + pod_delay: { type: 'integer', description: 'Seconds between supply pods being sent.' }, + planet: { + type: 'object', + description: 'Comprehensive planet data — coordinates, type, population, happiness, storage.', + }, + }), + + [`${base}/view_plans`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists all building plans this empire has collected.', { + type: 'object', + required: ['plans', 'status'], + properties: { + plans: { + type: 'array', + items: { + type: 'object', + properties: { + quantity: { type: 'integer' }, + name: { type: 'string' }, + level: { type: 'integer' }, + extra_build_level: { type: 'integer' }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_incoming_supply_chains`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists supply chains feeding resources into this planet.', { + type: 'object', + required: ['supply_chains', 'status'], + properties: { + supply_chains: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + from_body: { type: 'string' }, + resource_hour: { type: 'integer' }, + resource_type: { type: 'string' }, + percent_transferred: { type: 'number' }, + stalled: { type: 'integer', enum: [1, 0] }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/subsidize_pod_cooldown`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Spends 2 essentia to send a supply pod immediately. Returns the building view. Throws 1011.', + { + type: 'object', + required: ['building', 'status'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/politicstraining.ts b/src/spec/paths/buildings/politicstraining.ts new file mode 100644 index 0000000..da6b4b1 --- /dev/null +++ b/src/spec/paths/buildings/politicstraining.ts @@ -0,0 +1,18 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('PoliticsTraining'); + +export const politicsTraining = { + ...buildingCommonMethods(base), + ...buildingView(base, { + spies: { + type: 'object', + properties: { + max_points: { type: 'integer' }, + points_per: { type: 'integer' }, + in_training: { type: 'integer' }, + }, + required: ['max_points', 'points_per', 'in_training'], + }, + }), +}; diff --git a/src/spec/paths/buildings/potato.ts b/src/spec/paths/buildings/potato.ts new file mode 100644 index 0000000..51d89b7 --- /dev/null +++ b/src/spec/paths/buildings/potato.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Potato'); + +export const potato = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/propulsion.ts b/src/spec/paths/buildings/propulsion.ts new file mode 100644 index 0000000..1ef97c3 --- /dev/null +++ b/src/spec/paths/buildings/propulsion.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Propulsion'); + +export const propulsion = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/pyramidjunksculpture.ts b/src/spec/paths/buildings/pyramidjunksculpture.ts new file mode 100644 index 0000000..280eb3a --- /dev/null +++ b/src/spec/paths/buildings/pyramidjunksculpture.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('PyramidJunkSculpture'); + +export const pyramidJunkSculpture = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/ravine.ts b/src/spec/paths/buildings/ravine.ts new file mode 100644 index 0000000..3363f71 --- /dev/null +++ b/src/spec/paths/buildings/ravine.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Ravine'); + +export const ravine = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/rockyoutcrop.ts b/src/spec/paths/buildings/rockyoutcrop.ts new file mode 100644 index 0000000..76c541a --- /dev/null +++ b/src/spec/paths/buildings/rockyoutcrop.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('RockyOutcrop'); + +export const rockyOutcrop = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/sand.ts b/src/spec/paths/buildings/sand.ts new file mode 100644 index 0000000..771617e --- /dev/null +++ b/src/spec/paths/buildings/sand.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Sand'); + +export const sand = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/saw.ts b/src/spec/paths/buildings/saw.ts new file mode 100644 index 0000000..e4e8293 --- /dev/null +++ b/src/spec/paths/buildings/saw.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('SAW'); + +export const saw = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/security.ts b/src/spec/paths/buildings/security.ts new file mode 100644 index 0000000..24c362a --- /dev/null +++ b/src/spec/paths/buildings/security.ts @@ -0,0 +1,142 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Security'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +const prisonerIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id', 'prisoner_id'], + properties: { building_id: { type: 'string' }, prisoner_id: { type: 'string' } }, +}); + +export const security_ = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/view_prisoners`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { + type: 'integer', + description: 'Defaults to 1. Each page contains 25 spies.', + }, + }, + }), + responses: { + ...response200('Displays a list of the spies that have been captured.', { + type: 'object', + required: ['status', 'prisoners'], + properties: { + status: statusSchema(), + prisoners: { + type: 'array', + items: { + type: 'object', + required: ['id', 'name', 'level', 'task', 'sentence_expires'], + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + level: { type: 'integer' }, + task: { type: 'string', enum: ['Captured', 'Prisoner Transport'] }, + sentence_expires: { type: 'string' }, + }, + }, + }, + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/execute_prisoner`]: { + post: { + ...security(), + ...prisonerIdRequestBody, + responses: { + ...response200( + "Executes a prisoner rather than letting them serve out their sentence. Costs 10,000 times the prisoner's level in happiness from your planet.", + { type: 'object', required: ['status'], properties: { status: statusSchema() } } + ), + ...response500(), + }, + }, + }, + + [`${base}/release_prisoner`]: { + post: { + ...security(), + ...prisonerIdRequestBody, + responses: { + ...response200('Releases a captured prisoner.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_foreign_spies`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { + type: 'integer', + description: 'Defaults to 1. Each page contains 25 spies.', + }, + }, + }), + responses: { + ...response200( + 'Displays a list of the spies that are on your planet and have a level lower than your security ministry.', + { + type: 'object', + required: ['status', 'spies'], + properties: { + status: statusSchema(), + spies: { + type: 'array', + items: { + type: 'object', + required: ['name', 'level', 'task', 'next_mission'], + properties: { + name: { type: 'string' }, + level: { type: 'integer' }, + task: { type: 'string' }, + next_mission: { type: 'string' }, + }, + }, + }, + }, + } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/shake.ts b/src/spec/paths/buildings/shake.ts new file mode 100644 index 0000000..b53e224 --- /dev/null +++ b/src/spec/paths/buildings/shake.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Shake'); + +export const shake = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/shipyard.ts b/src/spec/paths/buildings/shipyard.ts new file mode 100644 index 0000000..5741ec8 --- /dev/null +++ b/src/spec/paths/buildings/shipyard.ts @@ -0,0 +1,226 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Shipyard'); + +const shipsBuildingSchema = { + type: 'object', + required: ['status', 'number_of_ships_building', 'cost_to_subsidize', 'ships_building'], + properties: { + status: statusSchema(), + number_of_ships_building: { type: 'integer' }, + cost_to_subsidize: { type: 'integer' }, + ships_building: { + type: 'array', + items: { + type: 'object', + required: ['id', 'type', 'type_human', 'date_completed'], + properties: { + id: { type: 'string' }, + type: { type: 'string' }, + type_human: { type: 'string' }, + date_completed: { type: 'string' }, + }, + }, + }, + }, +}; + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +export const shipyard = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/view_build_queue`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { type: 'integer', description: 'Defaults to 1. 25 items per page.' }, + }, + }), + responses: { + ...response200( + 'Retrieves the ships currently being built at this shipyard.', + shipsBuildingSchema + ), + ...response500(), + }, + }, + }, + + [`${base}/subsidize_build_queue`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Completes the entire build queue immediately for 1 essentia per ship. Throws 1011.', + shipsBuildingSchema + ), + ...response500(), + }, + }, + }, + + [`${base}/subsidize_ship`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'ship_id'], + properties: { building_id: { type: 'string' }, ship_id: { type: 'string' } }, + }), + responses: { + ...response200( + 'Completes a single ship immediately for 1 essentia. Throws 1011.', + shipsBuildingSchema + ), + ...response500(), + }, + }, + }, + + [`${base}/get_buildable`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + tag: { + type: 'string', + enum: ['Trade', 'Colonization', 'Intelligence', 'Exploration', 'War', 'Mining'], + }, + }, + }), + responses: { + ...response200('Lists buildable ship types with cost and availability.', { + type: 'object', + required: [ + 'buildable', + 'docks_available', + 'build_queue_max', + 'build_queue_used', + 'status', + ], + properties: { + buildable: { + type: 'object', + description: 'Keyed by ship type.', + additionalProperties: { + type: 'object', + required: ['can', 'cost', 'attributes'], + properties: { + can: { type: 'boolean' }, + reason: { type: 'array', items: {} }, + cost: { + type: 'object', + properties: { + seconds: { type: 'integer' }, + food: { type: 'integer' }, + water: { type: 'integer' }, + energy: { type: 'integer' }, + ore: { type: 'integer' }, + waste: { type: 'integer' }, + }, + }, + attributes: { + type: 'object', + properties: { + speed: { type: 'integer' }, + hold_size: { type: 'integer' }, + max_occupants: { type: 'integer' }, + combat: { type: 'integer' }, + stealth: { type: 'integer' }, + }, + }, + }, + }, + }, + docks_available: { type: 'integer' }, + build_queue_max: { type: 'integer' }, + build_queue_used: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/build_ship`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'type'], + properties: { + building_id: { type: 'string' }, + type: { type: 'string' }, + quantity: { type: 'integer', minimum: 1, maximum: 600, description: 'Defaults to 1.' }, + }, + }), + responses: { + ...response200('Queues ships for construction at this shipyard.', shipsBuildingSchema), + ...response500(), + }, + }, + }, + + [`${base}/build_ships`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['options'], + properties: { + options: { + type: 'object', + required: ['type'], + properties: { + type: { type: 'string' }, + quantity: { + type: 'integer', + minimum: 1, + maximum: 600, + description: 'Defaults to 1.', + }, + body_id: { type: 'string', description: 'Alternative to building_id.' }, + building_id: { + description: 'A single shipyard id, or an array of shipyard ids.', + oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }], + }, + autoselect: { type: 'string', enum: ['all', 'higher', 'only'] }, + }, + }, + }, + }), + responses: { + ...response200('Queues ships for construction across multiple shipyards at once.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/singularity.ts b/src/spec/paths/buildings/singularity.ts new file mode 100644 index 0000000..a3d1f72 --- /dev/null +++ b/src/spec/paths/buildings/singularity.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Singularity'); + +export const singularity = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/soup.ts b/src/spec/paths/buildings/soup.ts new file mode 100644 index 0000000..9eca2ee --- /dev/null +++ b/src/spec/paths/buildings/soup.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Soup'); + +export const soup = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/spacejunkpark.ts b/src/spec/paths/buildings/spacejunkpark.ts new file mode 100644 index 0000000..088efb9 --- /dev/null +++ b/src/spec/paths/buildings/spacejunkpark.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('SpaceJunkPark'); + +export const spaceJunkPark = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/spaceport.ts b/src/spec/paths/buildings/spaceport.ts new file mode 100644 index 0000000..5d3a2a8 --- /dev/null +++ b/src/spec/paths/buildings/spaceport.ts @@ -0,0 +1,753 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('SpacePort'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +// A star/body locator, as accepted by every method that needs to identify a target — exactly one +// of these should be given. +const targetSchema = { + type: 'object', + properties: { + body_name: { type: 'string' }, + body_id: { type: 'string' }, + star_name: { type: 'string' }, + star_id: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + }, + description: 'Identifies a star or body by exactly one of these keys.', +}; + +// A body/star reference as embedded in ship from/to/orbiting blocks. +const locationRefSchema = { + type: 'object', + properties: { + id: { type: 'string' }, + type: { type: 'string', enum: ['body', 'star'] }, + name: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + empire: { type: 'object', properties: { id: { type: 'string' }, name: { type: 'string' } } }, + }, +}; + +// Common shape of a ship object, as returned by most SpacePort methods. Not every field/block is +// present on every response — e.g. travelling ships have from/to, defending fighters have +// from/orbiting. +const shipSchema = { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + type: { type: 'string' }, + type_human: { type: 'string' }, + task: { type: 'string' }, + speed: { type: 'integer' }, + fleet_speed: { type: 'integer' }, + stealth: { type: 'integer' }, + hold_size: { type: 'integer' }, + berth_level: { type: 'integer' }, + date_started: { type: 'string' }, + date_available: { type: 'string' }, + date_arrives: { type: 'string' }, + can_recall: { type: 'integer', enum: [1, 0] }, + can_scuttle: { type: 'integer', enum: [1, 0] }, + from: locationRefSchema, + to: locationRefSchema, + orbiting: locationRefSchema, + }, +}; + +export const spacePort = { + ...buildingCommonMethods(base), + ...buildingView(base, { + max_ships: { type: 'integer', description: 'Twice the level of the Space Port.' }, + docks_available: { type: 'integer' }, + docked_ships: { + type: 'object', + description: 'Count of docked ships, keyed by ship type.', + additionalProperties: { type: 'integer' }, + }, + }), + + [`${base}/view_all_ships`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + paging: { + type: 'object', + properties: { + page_number: { type: 'integer', description: 'Defaults to 1.' }, + items_per_page: { type: 'integer', description: 'Defaults to 25.' }, + no_paging: { type: 'integer', enum: [1, 0] }, + }, + }, + filter: { + type: 'object', + properties: { + task: { + description: + 'One or more of: Building, Defend, Docked, Mining, Orbiting, Supply Chain, Travelling, Waiting on Trade, Waste Chain.', + oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }], + }, + type: { + description: 'One or more existing ship type names.', + oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }], + }, + tag: { + description: + 'One or more of Trade, Colonization, Intelligence, Exploration, War, Mining. Converted to types before filtering, overriding any `type` passed.', + oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }], + }, + }, + }, + sort: { + type: 'string', + enum: ['combat', 'name', 'speed', 'stealth', 'task', 'type'], + description: "Defaults to 'type'. A secondary sort by 'name' is always applied.", + }, + }, + }), + responses: { + ...response200("Shows all of this empire's ships, whatever they are doing.", { + type: 'object', + required: ['ships', 'number_of_ships', 'status'], + properties: { + ships: { type: 'array', items: shipSchema }, + number_of_ships: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_foreign_ships`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { type: 'integer', description: 'Defaults to 1. 25 per page.' }, + }, + }), + responses: { + ...response200( + "Lists incoming foreign ships whose stealth this Space Port's level can detect (350 * level >= ship stealth). The `from` block is only included if 450 * level >= ship stealth.", + { + type: 'object', + required: ['ships', 'number_of_ships', 'status'], + properties: { + ships: { type: 'array', items: shipSchema }, + number_of_ships: { type: 'integer' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/get_fleet_for`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['from_body_id', 'target'], + properties: { from_body_id: { type: 'string' }, target: targetSchema }, + }), + responses: { + ...response200( + 'Summarizes ships available to include in a fleet action, grouped by type/speed/stealth/combat.', + { + type: 'object', + required: ['ships', 'status'], + properties: { + ships: { + type: 'array', + items: { + type: 'object', + properties: { + type: { type: 'string' }, + type_human: { type: 'string' }, + speed: { type: 'integer' }, + stealth: { type: 'integer' }, + combat: { type: 'integer' }, + name: { type: 'string' }, + hold_size: { type: 'integer' }, + quantity: { type: 'integer' }, + estimated_travel_time: { type: 'integer' }, + }, + }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/get_ships_for`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['from_body_id', 'target'], + properties: { from_body_id: { type: 'string' }, target: targetSchema }, + }), + responses: { + ...response200( + 'Lists incoming ships and ships available to send to a target. Use with send_ship.', + { + type: 'object', + required: [ + 'incoming', + 'available', + 'unavailable', + 'orbiting', + 'fleet_send_limit', + 'status', + ], + properties: { + incoming: { type: 'array', items: shipSchema }, + available: { type: 'array', items: shipSchema }, + unavailable: { + type: 'array', + description: 'Docked ships that are not available to send, with a reason.', + items: { + type: 'object', + properties: { reason: { type: 'array', items: {} }, ship: shipSchema }, + }, + }, + orbiting: { + type: 'array', + description: + 'Only present if the target is a body. Defending fighters that can be recalled.', + items: shipSchema, + }, + mining_platforms: { + type: 'array', + description: 'Only present if the target is an asteroid with platforms on it.', + items: { + type: 'object', + properties: { empire_id: { type: 'string' }, empire_name: { type: 'string' } }, + }, + }, + fleet_send_limit: { type: 'integer' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/send_ship`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['ship_id', 'target'], + properties: { ship_id: { type: 'string' }, target: targetSchema }, + }), + responses: { + ...response200('Sends a single ship to a body or star. Use with get_ships_for.', { + type: 'object', + required: ['ship', 'status'], + properties: { ship: shipSchema, status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/send_ship_types`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['from_body_id', 'target', 'types', 'arrival'], + properties: { + from_body_id: { type: 'string' }, + target: targetSchema, + types: { + type: 'array', + description: 'The ship specifications and quantities to send. See get_fleet_for.', + items: { + type: 'object', + required: ['type', 'quantity'], + properties: { + type: { type: 'string' }, + speed: { type: 'integer' }, + stealth: { type: 'integer' }, + combat: { type: 'integer' }, + quantity: { type: 'integer' }, + }, + }, + }, + arrival: { + description: + 'The desired arrival time, either an absolute day/time or the earliest possible.', + oneOf: [ + { + type: 'object', + properties: { + day: { + type: 'integer', + description: 'Day of the month, up to 60 days in the future.', + }, + hour: { type: 'integer' }, + minute: { type: 'integer' }, + second: { type: 'integer' }, + }, + }, + { type: 'object', properties: { earliest: { type: 'integer', enum: [1] } } }, + ], + }, + }, + }), + responses: { + ...response200( + 'Sends the given quantities of matching docked ships to a target. Returns the same shape as get_fleet_for, showing ships remaining to send. Throws 1002, 1009, 1010, 1019.', + { + type: 'object', + required: ['ships', 'status'], + properties: { + ships: { + type: 'array', + items: { + type: 'object', + properties: { + type: { type: 'string' }, + type_human: { type: 'string' }, + speed: { type: 'integer' }, + stealth: { type: 'integer' }, + combat: { type: 'integer' }, + quantity: { type: 'integer' }, + }, + }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/send_fleet`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['ship_ids', 'target'], + properties: { + ship_ids: { type: 'array', items: { type: 'string' } }, + target: targetSchema, + set_speed: { + type: 'integer', + description: + "Speed all ships in the fleet should travel at. 0 uses the slowest ship's speed. Cannot exceed the slowest ship's speed.", + }, + }, + }), + responses: { + ...response200( + 'Sends a fleet of ships to a body or star. Use with get_ships_for. Throws 1002, 1009, 1010, 1016.', + { + type: 'object', + required: ['fleet', 'status'], + properties: { fleet: { type: 'array', items: shipSchema }, status: statusSchema() }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/recall_ship`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'ship_id'], + properties: { building_id: { type: 'string' }, ship_id: { type: 'string' } }, + }), + responses: { + ...response200( + 'Recalls an orbiting ship (task Defend or Orbiting) to its body of origin. Recalling an orbiting Spy Shuttle also fetches as many idle spies as will fit. Throws 1002, 1010, 1013.', + { + type: 'object', + required: ['ship', 'status'], + properties: { ship: shipSchema, status: statusSchema() }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/recall_all`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + "Recalls all of this planet's orbiting ships (task Defend or Orbiting) to their Space Port of origin. Throws 1002, 1010.", + { + type: 'object', + required: ['ships', 'status'], + properties: { ships: { type: 'array', items: shipSchema }, status: statusSchema() }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/name_ship`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'ship_id', 'name'], + properties: { + building_id: { type: 'string' }, + ship_id: { type: 'string' }, + name: { type: 'string', minLength: 1, maxLength: 30 }, + }, + }), + responses: { + ...response200('Renames a ship.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/scuttle_ship`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'ship_id'], + properties: { building_id: { type: 'string' }, ship_id: { type: 'string' } }, + }), + responses: { + ...response200('Destroys a docked ship.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/mass_scuttle_ship`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'ship_ids'], + properties: { + building_id: { type: 'string' }, + ship_ids: { type: 'array', items: { type: 'string' } }, + }, + }), + responses: { + ...response200('Destroys multiple docked ships.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_ships_travelling`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { type: 'integer', description: 'Defaults to 1. 25 per page.' }, + }, + }), + responses: { + ...response200( + "Lists ships travelling to or from this planet, regardless of which Space Port they'll land at.", + { + type: 'object', + required: ['number_of_ships_travelling', 'ships_travelling', 'status'], + properties: { + number_of_ships_travelling: { type: 'integer' }, + ships_travelling: { type: 'array', items: shipSchema }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/view_ships_orbiting`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { type: 'integer', description: 'Defaults to 1. 25 per page.' }, + }, + }), + responses: { + ...response200( + "Lists foreign ships orbiting this planet whose stealth this Space Port's level can detect (350 * level >= ship stealth). The `from` block is only included if 450 * level >= ship stealth.", + { + type: 'object', + required: ['ships', 'number_of_ships', 'status'], + properties: { + ships: { type: 'array', items: shipSchema }, + number_of_ships: { type: 'integer' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/prepare_send_spies`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['on_body_id', 'to_body_id'], + properties: { on_body_id: { type: 'string' }, to_body_id: { type: 'string' } }, + }), + responses: { + ...response200('Gathers the ships and spies needed to call send_spies.', { + type: 'object', + required: ['ships', 'spies', 'status'], + properties: { + ships: { + type: 'array', + description: + 'Spy Pods hold 1 spy, Spy Shuttles hold 4, other cargo-hold ships hold 1 per 350 units of hold size.', + items: shipSchema, + }, + spies: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + level: { type: 'integer' }, + name: { type: 'string' }, + assigned_to: { + type: 'object', + properties: { body_id: { type: 'string' }, name: { type: 'string' } }, + }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/send_spies`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['on_body_id', 'to_body_id', 'ship_id', 'spy_ids'], + properties: { + on_body_id: { type: 'string' }, + to_body_id: { type: 'string' }, + ship_id: { type: 'string' }, + spy_ids: { type: 'array', items: { type: 'string' } }, + }, + }), + responses: { + ...response200( + 'Sends spies from on_body_id to to_body_id using the chosen ship. See prepare_send_spies.', + { + type: 'object', + required: ['ship', 'spies_sent', 'spies_not_sent', 'status'], + properties: { + ship: shipSchema, + spies_sent: { type: 'array', items: { type: 'string' } }, + spies_not_sent: { + type: 'array', + items: { type: 'string' }, + description: + 'Should only be non-empty in edge cases (e.g. a spy died between calls).', + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/prepare_fetch_spies`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['on_body_id', 'to_body_id'], + properties: { + on_body_id: { type: 'string', description: 'The planet the spies are currently on.' }, + to_body_id: { + type: 'string', + description: + 'The planet the spies should be brought to, and the ship will be dispatched from.', + }, + }, + }), + responses: { + ...response200('Gathers the ships and spies needed to call fetch_spies.', { + type: 'object', + required: ['ships', 'spies', 'status'], + properties: { + ships: { type: 'array', items: shipSchema }, + spies: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + level: { type: 'integer' }, + name: { type: 'string' }, + assigned_to: { + type: 'object', + properties: { body_id: { type: 'string' }, name: { type: 'string' } }, + }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/fetch_spies`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['on_body_id', 'to_body_id', 'ship_id', 'spy_ids'], + properties: { + on_body_id: { type: 'string', description: 'The planet the spies are currently on.' }, + to_body_id: { + type: 'string', + description: + 'The planet the spies should be brought to, and the ship will be dispatched from.', + }, + ship_id: { type: 'string' }, + spy_ids: { type: 'array', items: { type: 'string' } }, + }, + }), + responses: { + ...response200( + 'Sends a ship to fetch spies from on_body_id and bring them to to_body_id. Spies not Idle on arrival are not picked up. See prepare_fetch_spies.', + { + type: 'object', + required: ['ship', 'status'], + properties: { ship: shipSchema, status: statusSchema() }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/view_battle_logs`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { type: 'integer', description: 'Defaults to 1. 25 per page.' }, + }, + }), + responses: { + ...response200( + "Lists this empire's battle logs, most recent first. Cleared out every seven days.", + { + type: 'object', + required: ['battle_log', 'number_of_logs', 'status'], + properties: { + battle_log: { + type: 'array', + items: { + type: 'object', + properties: { + date: { type: 'string' }, + attacking_body: { type: 'string' }, + attacking_empire: { type: 'string' }, + attacking_unit: { type: 'string' }, + defending_body: { type: 'string' }, + defending_empire: { type: 'string' }, + defending_unit: { type: 'string' }, + victory_to: { type: 'string', enum: ['attacker', 'defender'] }, + }, + }, + }, + number_of_logs: { type: 'integer' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/spacestationlab.ts b/src/spec/paths/buildings/spacestationlab.ts new file mode 100644 index 0000000..0c8213d --- /dev/null +++ b/src/spec/paths/buildings/spacestationlab.ts @@ -0,0 +1,109 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +// Accessible via /ssla, /sslb, /sslc, and /ssld — all four lab components must be built, but the +// methods below (other than the shared building methods) are only exposed on /ssla per the docs. +const base = buildingBase('SpaceStationLab'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +const makePlanSchema = { + type: 'object', + properties: { + types: { + type: 'array', + items: { + type: 'object', + properties: { + type: { type: 'string' }, + name: { type: 'string' }, + image: { type: 'string' }, + url: { type: 'string' }, + }, + }, + }, + level_costs: { + type: 'array', + items: { + type: 'object', + properties: { + level: { type: 'integer' }, + food: { type: 'integer' }, + ore: { type: 'integer' }, + water: { type: 'integer' }, + energy: { type: 'integer' }, + waste: { type: 'integer' }, + time: { type: 'integer' }, + }, + }, + }, + subsidy_cost: { type: 'integer' }, + making: { type: 'string', description: 'Only present if a plan is currently being made.' }, + }, +}; + +export const spaceStationLab = { + ...buildingCommonMethods(base), + ...buildingView(base, { make_plan: makePlanSchema }), + + [`${base}/make_plan`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'type', 'level'], + properties: { + building_id: { type: 'string' }, + type: { type: 'string', description: "Key from view's make_plan > types, e.g. 'ibs'." }, + level: { type: 'integer', minimum: 1, maximum: 30 }, + }, + }), + responses: { + ...response200('Starts the plan creation process. Returns the building view.', { + type: 'object', + required: ['building', 'status'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + make_plan: makePlanSchema, + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/subsidize_plan`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + "Spends essentia equal to view's subsidy_cost to complete the current plan immediately. Returns the building view. Throws 1011.", + { + type: 'object', + required: ['building', 'status'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + make_plan: makePlanSchema, + }, + } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/stockpile.ts b/src/spec/paths/buildings/stockpile.ts new file mode 100644 index 0000000..9a88ddb --- /dev/null +++ b/src/spec/paths/buildings/stockpile.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Stockpile'); + +export const stockpile = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/subspacesupplydepot.ts b/src/spec/paths/buildings/subspacesupplydepot.ts new file mode 100644 index 0000000..7e27e79 --- /dev/null +++ b/src/spec/paths/buildings/subspacesupplydepot.ts @@ -0,0 +1,90 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('SubspaceSupplyDepot'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +// Shared response shape for the transmit_* methods and complete_build_queue — all convert seconds +// of work into a resource (or build queue time) and return the building's resulting work block. +const workResultSchema = (description: string) => ({ + ...response200(description, { + type: 'object', + required: ['building', 'status'], + properties: { + building: { + type: 'object', + properties: { + work: { + type: 'object', + properties: { + seconds_remaining: { type: 'integer' }, + start: { type: 'string' }, + end: { type: 'string' }, + }, + required: ['seconds_remaining', 'start', 'end'], + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), +}); + +export const subspaceSupplyDepot = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/transmit_food`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: workResultSchema('Converts 3600 seconds into 3600 food.'), + }, + }, + + [`${base}/transmit_energy`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: workResultSchema('Converts 3600 seconds into 3600 energy.'), + }, + }, + + [`${base}/transmit_ore`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: workResultSchema('Converts 3600 seconds into 3600 ore.'), + }, + }, + + [`${base}/transmit_water`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: workResultSchema('Converts 3600 seconds into 3600 water.'), + }, + }, + + [`${base}/complete_build_queue`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: workResultSchema("Trades seconds for the planet's build queue time."), + }, + }, +}; diff --git a/src/spec/paths/buildings/supplypod.ts b/src/spec/paths/buildings/supplypod.ts new file mode 100644 index 0000000..e064b3f --- /dev/null +++ b/src/spec/paths/buildings/supplypod.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('SupplyPod'); + +export const supplyPod = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/syrup.ts b/src/spec/paths/buildings/syrup.ts new file mode 100644 index 0000000..282eaf8 --- /dev/null +++ b/src/spec/paths/buildings/syrup.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Syrup'); + +export const syrup = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/templeofthedrajilites.ts b/src/spec/paths/buildings/templeofthedrajilites.ts new file mode 100644 index 0000000..4e2022c --- /dev/null +++ b/src/spec/paths/buildings/templeofthedrajilites.ts @@ -0,0 +1,94 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('TempleOfTheDrajilites'); + +export const templeOfTheDrajilites = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/list_planets`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + star_id: { type: 'string', description: 'Defaults to the star the Temple is built on.' }, + }, + }), + responses: { + ...response200('Lists the planets around a given star.', { + type: 'object', + required: ['planets', 'status'], + properties: { + planets: { + type: 'array', + items: { + type: 'object', + required: ['id', 'name'], + properties: { id: { type: 'string' }, name: { type: 'string' } }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_planet`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'planet_id'], + properties: { + building_id: { type: 'string' }, + planet_id: { + type: 'string', + description: + 'Must be a planet id, not a body id (e.g. asteroids are not valid). Must be within range — 10 star map units per level of the Temple.', + }, + }, + }), + responses: { + ...response200('Returns a surface map identical in format to an Inbox attachment map.', { + type: 'object', + required: ['map', 'status'], + properties: { + map: { + type: 'object', + properties: { + surface_image: { type: 'string' }, + buildings: { + type: 'array', + items: { + type: 'object', + properties: { + x: { type: 'integer', minimum: -5, maximum: 5 }, + y: { type: 'integer', minimum: -5, maximum: 5 }, + image: { type: 'string' }, + }, + }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/terraforminglab.ts b/src/spec/paths/buildings/terraforminglab.ts new file mode 100644 index 0000000..bbb83e6 --- /dev/null +++ b/src/spec/paths/buildings/terraforminglab.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('TerraformingLab'); + +export const terraformingLab = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/terraformingplatform.ts b/src/spec/paths/buildings/terraformingplatform.ts new file mode 100644 index 0000000..17c34df --- /dev/null +++ b/src/spec/paths/buildings/terraformingplatform.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('TerraformingPlatform'); + +export const terraformingPlatform = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/thedillonforge.ts b/src/spec/paths/buildings/thedillonforge.ts new file mode 100644 index 0000000..9f8c544 --- /dev/null +++ b/src/spec/paths/buildings/thedillonforge.ts @@ -0,0 +1,152 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('TheDillonForge'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +const tasksSchema = { + type: 'object', + properties: { + current_task: { type: 'string' }, + seconds_remaining: { type: 'integer' }, + can: { type: 'integer', enum: [1, 0] }, + working: { type: 'string' }, + subsidy_cost: { type: 'integer' }, + make_plan: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + max_level: { type: 'integer' }, + class: { type: 'string' }, + reset_sec_per_level: { type: 'integer' }, + }, + }, + }, + split_plan: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + class: { type: 'string' }, + level: { type: 'integer' }, + extra_build_level: { type: 'integer' }, + fail_chance: { type: 'integer' }, + reset_seconds: { type: 'integer' }, + }, + }, + }, + }, +}; + +export const theDillonForge = { + ...buildingCommonMethods(base), + ...buildingView(base, { tasks: tasksSchema }), + + [`${base}/make_plan`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'plan_class', 'level'], + properties: { + building_id: { type: 'string' }, + plan_class: { + type: 'string', + description: "The plan's class, as returned by view's tasks > make_plan.", + }, + level: { + type: 'integer', + description: + 'The level to build the plan at. Cannot exceed the level of The Dillon Forge. Requires at least 2x level 1+0 plans of the specified class on the colony to build a level x+0 plan.', + }, + }, + }), + responses: { + ...response200('Starts making a plan. Returns the building view.', { + type: 'object', + required: ['building', 'status'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/split_plan`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'plan_class', 'level', 'quantity'], + properties: { + building_id: { type: 'string' }, + plan_class: { + type: 'string', + description: "The plan's class, as returned by view's tasks > split_plan.", + }, + level: { type: 'integer', description: 'The level of the plan to split.' }, + extra_build_level: { + type: 'integer', + description: "The plan's extra build levels, if any.", + }, + quantity: { + type: 'integer', + description: + 'Number of plans to feed into the forge. Time does not scale linearly — more plans is more efficient.', + }, + }, + }), + responses: { + ...response200('Splits a plan into its constituent glyphs. Returns the building view.', { + type: 'object', + required: ['building', 'status'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/subsidize`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Spends essentia to complete the current task immediately (2e, unless splitting multiple plans). Returns the building view. Throws 1011.', + { + type: 'object', + required: ['building', 'status'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/thefttraining.ts b/src/spec/paths/buildings/thefttraining.ts new file mode 100644 index 0000000..02b4345 --- /dev/null +++ b/src/spec/paths/buildings/thefttraining.ts @@ -0,0 +1,17 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('TheftTraining'); + +export const theftTraining = { + ...buildingCommonMethods(base), + ...buildingView(base, { + spies: { + type: 'object', + properties: { + max_points: { type: 'integer' }, + points_per: { type: 'integer' }, + in_training: { type: 'integer' }, + }, + }, + }), +}; diff --git a/src/spec/paths/buildings/themepark.ts b/src/spec/paths/buildings/themepark.ts new file mode 100644 index 0000000..7df9801 --- /dev/null +++ b/src/spec/paths/buildings/themepark.ts @@ -0,0 +1,51 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('ThemePark'); + +export const themePark = { + ...buildingCommonMethods(base), + ...buildingView(base, { + themepark: { + type: 'object', + properties: { + food_type_count: { type: 'integer' }, + can_operate: { type: 'integer', enum: [1, 0] }, + reason: { type: 'array', items: {} }, + }, + }, + }), + + [`${base}/operate`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, + }), + responses: { + ...response200( + 'Starts (or extends) operation of the Theme Park. Requires at least 1,000 of each of 5 food types to start; while operating, subsequent calls must spend at least as much food as the last call. Happiness output scales with the number of food types used and the level of the Theme Park. Returns the building view. Throws 1002, 1006, 1010, 1011.', + { + type: 'object', + required: ['building', 'status'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/trade.ts b/src/spec/paths/buildings/trade.ts new file mode 100644 index 0000000..9a1cbec --- /dev/null +++ b/src/spec/paths/buildings/trade.ts @@ -0,0 +1,689 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Trade'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +// A tradeable item, per the Trade docs — resources (quantity-based), glyphs, plans, prisoners, or ships. +const tradeableItemSchema = { + type: 'object', + properties: { + type: { type: 'string', enum: ['glyph', 'plan', 'prisoner', 'ship'] }, + // Resources are passed as a bare {resource_name: quantity} pair instead of a typed item. + name: { type: 'string' }, + quantity: { type: 'integer' }, + plan_type: { type: 'string' }, + level: { type: 'integer' }, + extra_build_level: { type: 'integer' }, + prisoner_id: { type: 'string' }, + ship_id: { type: 'string' }, + }, +}; + +const marketEntrySchema = { + type: 'object', + required: ['id', 'date', 'ask', 'offer'], + properties: { + id: { type: 'string' }, + date: { type: 'string' }, + ask: { type: 'number' }, + offer: { type: 'array', items: tradeableItemSchema }, + empire: { type: 'object', properties: { id: { type: 'string' }, name: { type: 'string' } } }, + body: { type: 'object', properties: { id: { type: 'string' }, name: { type: 'string' } } }, + transmitter_delivery_time: { type: 'integer' }, + }, +}; + +export const trade = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/add_to_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'offer', 'ask'], + properties: { + building_id: { type: 'string' }, + offer: { type: 'array', items: tradeableItemSchema }, + ask: { + type: 'number', + minimum: 0.1, + maximum: 100, + description: 'Essentia amount requested.', + }, + options: { type: 'object', properties: { ship_id: { type: 'string' } } }, + }, + }), + responses: { + ...response200('Posts a trade offer for other players to accept.', { + type: 'object', + required: ['trade_id', 'status'], + properties: { trade_id: { type: 'string' }, status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { type: 'integer', description: 'Defaults to 1. 25 items per page.' }, + filter: { + type: 'string', + enum: ['food', 'ore', 'water', 'waste', 'energy', 'glyph', 'prisoner', 'ship', 'plan'], + }, + }, + }), + responses: { + ...response200("Lists other players' posted trades.", { + type: 'object', + required: ['trades', 'status'], + properties: { + trades: { type: 'array', items: marketEntrySchema }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_my_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { type: 'integer', description: 'Defaults to 1.' }, + }, + }), + responses: { + ...response200('Lists trades posted by this empire.', { + type: 'object', + required: ['trades', 'status'], + properties: { + trades: { type: 'array', items: marketEntrySchema }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/accept_from_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'trade_id'], + properties: { building_id: { type: 'string' }, trade_id: { type: 'string' } }, + }), + responses: { + ...response200( + "Accepts another player's trade. Throws 1016 if the trade is no longer valid.", + { type: 'object', required: ['status'], properties: { status: statusSchema() } } + ), + ...response500(), + }, + }, + }, + + [`${base}/withdraw_from_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'trade_id'], + properties: { building_id: { type: 'string' }, trade_id: { type: 'string' } }, + }), + responses: { + ...response200('Cancels a trade this empire posted and retrieves the offered items.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/push_items`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'target_id', 'items'], + properties: { + building_id: { type: 'string' }, + target_id: { + type: 'string', + description: 'The destination planet, which must be owned by this empire.', + }, + items: { type: 'array', items: tradeableItemSchema }, + options: { + type: 'object', + properties: { + ship_id: { type: 'string' }, + stay: { + type: 'integer', + enum: [1, 0], + description: 'Leave the ship at the destination (requires a dock there).', + }, + }, + }, + }, + }), + responses: { + ...response200('Transfers resources/items between planets this empire owns.', { + type: 'object', + required: ['status', 'ship'], + properties: { + ship: { + type: 'object', + properties: { + name: { type: 'string' }, + type: { type: 'string' }, + date_arrives: { type: 'string' }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_stored_resources`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists resources available in storage, by type and quantity.', { + type: 'object', + required: ['resources', 'status'], + properties: { + resources: { type: 'object', additionalProperties: { type: 'integer' } }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_trade_ships`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' }, target_body_id: { type: 'string' } }, + }), + responses: { + ...response200('Lists cargo vessels available for trading, with estimated travel time.', { + type: 'object', + required: ['ships', 'status'], + properties: { + ships: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + type: { type: 'string' }, + hold_size: { type: 'integer' }, + speed: { type: 'integer' }, + estimated_travel_time: { type: 'integer' }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_ships`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists tradeable ships, with hold size and speed.', { + type: 'object', + required: ['ships', 'status'], + properties: { + ships: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + type: { type: 'string' }, + hold_size: { type: 'integer' }, + speed: { type: 'integer' }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_waste_ships`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists scow vessels available for waste transport.', { + type: 'object', + required: ['ships', 'status'], + properties: { + ships: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + task: { type: 'string' }, + speed: { type: 'integer' }, + hold_size: { type: 'integer' }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_supply_ships`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists hulk vessels available for resource supply chains.', { + type: 'object', + required: ['ships', 'status'], + properties: { + ships: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + task: { type: 'string' }, + speed: { type: 'integer' }, + hold_size: { type: 'integer' }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_supply_chains`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200("Lists this ministry's active resource supply chains.", { + type: 'object', + required: ['supply_chains', 'max_supply_chains', 'status'], + properties: { + supply_chains: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + resource_type: { type: 'string' }, + resource_hour: { type: 'integer' }, + percent_transferred: { type: 'number' }, + stalled: { type: 'integer', enum: [1, 0] }, + }, + }, + }, + max_supply_chains: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/create_supply_chain`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'target_id', 'resource_type', 'resource_hour'], + properties: { + building_id: { type: 'string' }, + target_id: { type: 'string' }, + resource_type: { type: 'string' }, + resource_hour: { type: 'integer' }, + }, + }), + responses: { + ...response200('Establishes a new resource supply chain to a target planet.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/update_supply_chain`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'supply_chain_id', 'resource_type', 'resource_hour'], + properties: { + building_id: { type: 'string' }, + supply_chain_id: { type: 'string' }, + resource_type: { type: 'string' }, + resource_hour: { type: 'integer', description: 'Set to 0 to suspend the chain.' }, + }, + }), + responses: { + ...response200('Modifies an existing supply chain.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/delete_supply_chain`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'supply_chain_id'], + properties: { building_id: { type: 'string' }, supply_chain_id: { type: 'string' } }, + }), + responses: { + ...response200('Removes a supply chain.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/add_supply_ship_to_fleet`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'ship_id'], + properties: { building_id: { type: 'string' }, ship_id: { type: 'string' } }, + }), + responses: { + ...response200('Assigns a hulk to supply chain service. Throws 1009 on failure.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/remove_supply_ship_from_fleet`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'ship_id'], + properties: { building_id: { type: 'string' }, ship_id: { type: 'string' } }, + }), + responses: { + ...response200('Returns a hulk to the spaceport from supply chain duty.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_waste_chains`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists waste chains (a default chain exists for the local star).', { + type: 'object', + required: ['waste_chains', 'status'], + properties: { + waste_chains: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + waste_hour: { type: 'integer' }, + percent_transferred: { type: 'number' }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/update_waste_chain`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'waste_chain_id', 'waste_hour'], + properties: { + building_id: { type: 'string' }, + waste_chain_id: { type: 'string' }, + waste_hour: { type: 'integer' }, + }, + }), + responses: { + ...response200('Adjusts the transfer rate of a waste chain.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/add_waste_ship_to_fleet`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'ship_id'], + properties: { building_id: { type: 'string' }, ship_id: { type: 'string' } }, + }), + responses: { + ...response200('Assigns a scow to waste transport duty. Throws 1009 on failure.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/remove_waste_ship_from_fleet`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'ship_id'], + properties: { building_id: { type: 'string' }, ship_id: { type: 'string' } }, + }), + responses: { + ...response200('Returns a scow to the spaceport from waste transport duty.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_prisoners`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists tradeable spies, with level and sentence expiration.', { + type: 'object', + required: ['prisoners', 'status'], + properties: { + prisoners: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + level: { type: 'integer' }, + sentence_expires: { type: 'string' }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_plan_summary`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Summarizes owned plans by type, level, and quantity.', { + type: 'object', + required: ['plans', 'status'], + properties: { + plans: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + level: { type: 'integer' }, + extra_build_level: { type: 'integer' }, + quantity: { type: 'integer' }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_glyph_summary`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Summarizes owned glyphs by type and quantity.', { + type: 'object', + required: ['glyphs', 'status'], + properties: { + glyphs: { + type: 'array', + items: { + type: 'object', + properties: { type: { type: 'string' }, quantity: { type: 'integer' } }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/report_abuse`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'trade_id'], + properties: { building_id: { type: 'string' }, trade_id: { type: 'string' } }, + }), + responses: { + ...response200('Flags a suspicious trade for moderation review.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/transporter.ts b/src/spec/paths/buildings/transporter.ts new file mode 100644 index 0000000..9687a4d --- /dev/null +++ b/src/spec/paths/buildings/transporter.ts @@ -0,0 +1,416 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Transporter'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +// A tradeable/pushable item — resources (name/quantity), glyphs, plans, prisoners, or ships. +const tradeableItemSchema = { + type: 'object', + properties: { + type: { type: 'string', enum: ['glyph', 'plan', 'prisoner', 'ship'] }, + // Resources are passed as { type: , quantity }. + name: { type: 'string' }, + quantity: { type: 'integer' }, + glyph_id: { type: 'string' }, + plan_id: { type: 'string' }, + prisoner_id: { type: 'string' }, + ship_id: { type: 'string' }, + }, +}; + +const marketEntrySchema = { + type: 'object', + required: ['id', 'date_offered', 'ask', 'offer'], + properties: { + id: { type: 'string' }, + date_offered: { type: 'string' }, + ask: { type: 'number', description: 'Essentia amount requested.' }, + offer: { + type: 'array', + items: { type: 'string' }, + description: 'Human-readable descriptions of the offered items.', + }, + empire: { type: 'object', properties: { id: { type: 'string' }, name: { type: 'string' } } }, + }, +}; + +export const transporter = { + ...buildingCommonMethods(base), + ...buildingView(base, { + transport: { + type: 'object', + properties: { + max: { type: 'integer' }, + pushable: { + type: 'array', + description: 'Planets with currently-online Transporters, alphabetical by name.', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + zone: { type: 'string' }, + }, + }, + }, + }, + }, + }), + + [`${base}/add_to_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'offer', 'ask'], + properties: { + building_id: { type: 'string' }, + offer: { + type: 'array', + items: tradeableItemSchema, + description: 'Resources, glyphs, plans, prisoners, or ships to offer.', + }, + ask: { + type: 'number', + minimum: 0.1, + maximum: 100, + description: 'Essentia amount requested.', + }, + }, + }), + responses: { + ...response200( + 'Queues a trade for other players to see. Costs 1 essentia in addition to whatever is offered.', + { + type: 'object', + required: ['trade_id', 'status'], + properties: { trade_id: { type: 'string' }, status: statusSchema() }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/get_ships`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists ships that may be traded. Used with add_to_market.', { + type: 'object', + required: ['ships', 'cargo_space_used_each', 'status'], + properties: { + ships: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + type: { type: 'string' }, + hold_size: { type: 'integer' }, + speed: { type: 'integer' }, + }, + }, + }, + cargo_space_used_each: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_prisoners`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists prisoners that may be traded. Used with add_to_market.', { + type: 'object', + required: ['prisoners', 'cargo_space_used_each', 'status'], + properties: { + prisoners: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + level: { type: 'integer' }, + sentence_expires: { type: 'string' }, + }, + }, + }, + cargo_space_used_each: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_plan_summary`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Lists plans that may be traded, in summary form. Used with add_to_market.', + { + type: 'object', + required: ['plans', 'cargo_space_used_each', 'status'], + properties: { + plans: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + level: { type: 'integer' }, + extra_build_level: { type: 'integer' }, + quantity: { type: 'integer' }, + }, + }, + }, + cargo_space_used_each: { type: 'integer' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/get_glyph_summary`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Summarizes glyphs that may be traded. Used with add_to_market.', { + type: 'object', + required: ['glyphs', 'cargo_space_used_each', 'status'], + properties: { + glyphs: { + type: 'array', + items: { + type: 'object', + properties: { type: { type: 'string' }, quantity: { type: 'integer' } }, + }, + }, + cargo_space_used_each: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/withdraw_from_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'trade_id'], + properties: { building_id: { type: 'string' }, trade_id: { type: 'string' } }, + }), + responses: { + ...response200('Removes a trade this empire posted and retrieves the offered items.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/accept_from_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'trade_id'], + properties: { building_id: { type: 'string' }, trade_id: { type: 'string' } }, + }), + responses: { + ...response200( + 'Accepts a trade offer from view_market. Costs the asking price plus 1 essentia. Throws 1016.', + { type: 'object', required: ['status'], properties: { status: statusSchema() } } + ), + ...response500(), + }, + }, + }, + + [`${base}/view_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { type: 'integer', description: 'Defaults to 1. 25 items per page.' }, + filter: { + type: 'string', + enum: ['food', 'ore', 'water', 'waste', 'energy', 'glyph', 'prisoner', 'ship', 'plan'], + }, + }, + }), + responses: { + ...response200('Lists trades currently available to accept.', { + type: 'object', + required: ['trades', 'trade_count', 'page_number', 'status'], + properties: { + trades: { type: 'array', items: marketEntrySchema }, + trade_count: { type: 'integer' }, + page_number: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_my_market`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { + building_id: { type: 'string' }, + page_number: { type: 'integer', description: 'Defaults to 1. 25 items per page.' }, + }, + }), + responses: { + ...response200('Lists trades this empire has posted.', { + type: 'object', + required: ['trades', 'trade_count', 'page_number', 'status'], + properties: { + trades: { type: 'array', items: marketEntrySchema }, + trade_count: { type: 'integer' }, + page_number: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_stored_resources`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Lists resources in storage, to make it easier to decide what to trade.', { + type: 'object', + required: ['resources', 'cargo_space_used_each', 'status'], + properties: { + resources: { type: 'object', additionalProperties: { type: 'integer' } }, + cargo_space_used_each: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/push_items`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'target_id', 'items'], + properties: { + building_id: { type: 'string' }, + target_id: { type: 'string', description: 'A planet controlled by this empire.' }, + items: { + type: 'array', + items: tradeableItemSchema, + description: 'Resources, glyphs, plans, prisoners, or ships to send.', + }, + }, + }), + responses: { + ...response200('Instantly sends resources/items to another planet this empire owns.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/trade_one_for_one`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'have', 'want', 'quantity'], + properties: { + building_id: { type: 'string' }, + have: { + type: 'string', + description: 'The resource type this empire has. See get_stored_resources.', + }, + want: { type: 'string', description: 'The resource type this empire wants.' }, + quantity: { type: 'integer' }, + }, + }), + responses: { + ...response200('Trades any resource for another one-for-one, in exchange for 3 essentia.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/report_abuse`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'trade_id'], + properties: { building_id: { type: 'string' }, trade_id: { type: 'string' } }, + }), + responses: { + ...response200('Reports a trade suspected of abusing the trade system.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/university.ts b/src/spec/paths/buildings/university.ts new file mode 100644 index 0000000..2329352 --- /dev/null +++ b/src/spec/paths/buildings/university.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('University'); + +export const university = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/volcano.ts b/src/spec/paths/buildings/volcano.ts new file mode 100644 index 0000000..355ede5 --- /dev/null +++ b/src/spec/paths/buildings/volcano.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Volcano'); + +export const volcano = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/wastedigester.ts b/src/spec/paths/buildings/wastedigester.ts new file mode 100644 index 0000000..46f0626 --- /dev/null +++ b/src/spec/paths/buildings/wastedigester.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('WasteDigester'); + +export const wasteDigester = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/wasteenergy.ts b/src/spec/paths/buildings/wasteenergy.ts new file mode 100644 index 0000000..3619b11 --- /dev/null +++ b/src/spec/paths/buildings/wasteenergy.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('WasteEnergy'); + +export const wasteEnergy = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/wasteexchanger.ts b/src/spec/paths/buildings/wasteexchanger.ts new file mode 100644 index 0000000..55a145b --- /dev/null +++ b/src/spec/paths/buildings/wasteexchanger.ts @@ -0,0 +1,98 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('WasteExchanger'); + +const recycleSchema = { + type: 'object', + properties: { + seconds_remaining: { type: 'integer' }, + can: { type: 'integer', enum: [1, 0] }, + seconds_per_resource: { + type: 'string', + description: + 'Seconds required to recycle one unit of a resource, precalculated for convenience.', + }, + max_recycle: { + type: 'integer', + description: 'The maximum total amount of waste that can be recycled at once.', + }, + water: { type: 'integer' }, + energy: { type: 'integer' }, + ore: { type: 'integer' }, + }, + required: [ + 'seconds_remaining', + 'can', + 'seconds_per_resource', + 'max_recycle', + 'water', + 'energy', + 'ore', + ], +}; + +const recycleResultSchema = (description: string) => ({ + ...response200(description, { + type: 'object', + required: ['building', 'status', 'recycle'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + recycle: recycleSchema, + }, + }), + ...response500(), +}); + +export const wasteExchanger = { + ...buildingCommonMethods(base), + ...buildingView(base, { recycle: recycleSchema }, ['recycle']), + + [`${base}/recycle`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'water', 'ore', 'energy'], + properties: { + building_id: { type: 'string' }, + water: { type: 'integer', description: 'Amount of water to produce from waste.' }, + ore: { type: 'integer', description: 'Amount of ore to produce from waste.' }, + energy: { type: 'integer', description: 'Amount of energy to produce from waste.' }, + use_essentia: { + type: 'integer', + enum: [1, 0], + description: + 'Defaults to 0. Spends 2 essentia to have the recycling operation completed immediately.', + }, + }, + }), + responses: recycleResultSchema( + "Converts waste into water, ore, and energy. The total requested must not exceed the waste in storage. Returns the building's view." + ), + }, + }, + + [`${base}/subsidize_recycling`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, + }), + responses: recycleResultSchema( + "Spends 2 essentia to complete the current recycling job immediately. Returns the building's view." + ), + }, + }, +}; diff --git a/src/spec/paths/buildings/wasterecycling.ts b/src/spec/paths/buildings/wasterecycling.ts new file mode 100644 index 0000000..2850d47 --- /dev/null +++ b/src/spec/paths/buildings/wasterecycling.ts @@ -0,0 +1,98 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('WasteRecycling'); + +const recycleSchema = { + type: 'object', + properties: { + seconds_remaining: { type: 'integer' }, + can: { type: 'integer', enum: [1, 0] }, + seconds_per_resource: { + type: 'string', + description: + 'Seconds required to recycle one unit of a resource, precalculated for convenience.', + }, + max_recycle: { + type: 'integer', + description: 'The maximum total amount of waste that can be recycled at once.', + }, + water: { type: 'integer' }, + energy: { type: 'integer' }, + ore: { type: 'integer' }, + }, + required: [ + 'seconds_remaining', + 'can', + 'seconds_per_resource', + 'max_recycle', + 'water', + 'energy', + 'ore', + ], +}; + +const recycleResultSchema = (description: string) => ({ + ...response200(description, { + type: 'object', + required: ['building', 'status', 'recycle'], + properties: { + building: { $ref: '#/components/schemas/building' }, + status: statusSchema(), + recycle: recycleSchema, + }, + }), + ...response500(), +}); + +export const wasteRecycling = { + ...buildingCommonMethods(base), + ...buildingView(base, { recycle: recycleSchema }, ['recycle']), + + [`${base}/recycle`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'water', 'ore', 'energy'], + properties: { + building_id: { type: 'string' }, + water: { type: 'integer', description: 'Amount of water to produce from waste.' }, + ore: { type: 'integer', description: 'Amount of ore to produce from waste.' }, + energy: { type: 'integer', description: 'Amount of energy to produce from waste.' }, + use_essentia: { + type: 'integer', + enum: [1, 0], + description: + 'Defaults to 0. Spends 2 essentia to have the recycling operation completed immediately.', + }, + }, + }), + responses: recycleResultSchema( + "Converts waste into water, ore, and energy. The total requested must not exceed the waste in storage. Returns the building's view." + ), + }, + }, + + [`${base}/subsidize_recycling`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, + }), + responses: recycleResultSchema( + "Spends 2 essentia to complete the current recycling job immediately. Returns the building's view." + ), + }, + }, +}; diff --git a/src/spec/paths/buildings/wastesequestration.ts b/src/spec/paths/buildings/wastesequestration.ts new file mode 100644 index 0000000..540dddf --- /dev/null +++ b/src/spec/paths/buildings/wastesequestration.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('WasteSequestration'); + +export const wasteSequestration = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/wastetreatment.ts b/src/spec/paths/buildings/wastetreatment.ts new file mode 100644 index 0000000..411139d --- /dev/null +++ b/src/spec/paths/buildings/wastetreatment.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('WasteTreatment'); + +export const wasteTreatment = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/waterproduction.ts b/src/spec/paths/buildings/waterproduction.ts new file mode 100644 index 0000000..7eace54 --- /dev/null +++ b/src/spec/paths/buildings/waterproduction.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('WaterProduction'); + +export const waterProduction = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/waterpurification.ts b/src/spec/paths/buildings/waterpurification.ts new file mode 100644 index 0000000..7da1643 --- /dev/null +++ b/src/spec/paths/buildings/waterpurification.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('WaterPurification'); + +export const waterPurification = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/waterreclamation.ts b/src/spec/paths/buildings/waterreclamation.ts new file mode 100644 index 0000000..cec9c64 --- /dev/null +++ b/src/spec/paths/buildings/waterreclamation.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('WaterReclamation'); + +export const waterReclamation = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/buildings/waterstorage.ts b/src/spec/paths/buildings/waterstorage.ts new file mode 100644 index 0000000..4b00fb5 --- /dev/null +++ b/src/spec/paths/buildings/waterstorage.ts @@ -0,0 +1,39 @@ +import { + buildingBase, + buildingCommonMethods, + buildingView, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('WaterStorage'); + +export const waterStorage = { + ...buildingCommonMethods(base), + ...buildingView(base), + + [`${base}/dump`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'amount'], + properties: { + building_id: { type: 'string' }, + amount: { type: 'integer', description: 'Amount of water to convert into waste.' }, + }, + }), + responses: { + ...response200('Converts water into waste.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/buildings/wheat.ts b/src/spec/paths/buildings/wheat.ts new file mode 100644 index 0000000..205167f --- /dev/null +++ b/src/spec/paths/buildings/wheat.ts @@ -0,0 +1,5 @@ +import { buildingBase, buildingCommonMethods, buildingView } from '../../chunks'; + +const base = buildingBase('Wheat'); + +export const wheat = { ...buildingCommonMethods(base), ...buildingView(base) }; diff --git a/src/spec/paths/captcha.ts b/src/spec/paths/captcha.ts new file mode 100644 index 0000000..0dacb13 --- /dev/null +++ b/src/spec/paths/captcha.ts @@ -0,0 +1,46 @@ +import { requestBodySchema, response200, response500, security } from '../chunks'; + +// This is the standalone Captcha module (`/captcha`). Distinct from `/v2/empire/fetch_captcha`, +// which is a separate, unauthenticated captcha flow used specifically for account creation. +export const captcha = { + '/v2/captcha/fetch': { + post: { + ...security(), + + responses: { + ...response200( + "Retrieves a captcha required to call solve. Display it, then call solve with the user's response.", + { + type: 'object', + required: ['guid', 'url'], + properties: { guid: { type: 'string' }, url: { type: 'string' } }, + } + ), + ...response500(), + }, + }, + }, + + '/v2/captcha/solve': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['captcha_guid', 'captcha_solution'], + properties: { + captcha_guid: { type: 'string', description: 'Must match the guid from fetch.' }, + captcha_solution: { type: 'string', description: "The user's typed solution." }, + }, + }), + + responses: { + ...response200( + 'Validates the solution against the given guid. On success the captcha remains valid for thirty minutes and this returns 1. Captchas are single-use; throws 1014 on mismatch, with new captcha data in the error data that must be used for the next attempt.', + { type: 'integer', enum: [1] } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/inbox.ts b/src/spec/paths/inbox.ts new file mode 100644 index 0000000..5652bd8 --- /dev/null +++ b/src/spec/paths/inbox.ts @@ -0,0 +1,364 @@ +import { requestBodySchema, response200, response500, security, statusSchema } from '../chunks'; + +const MESSAGE_TAGS = [ + 'Tutorial', + 'Correspondence', + 'Medal', + 'Intelligence', + 'Alert', + 'Attack', + 'Colonization', + 'Complaint', + 'Excavator', + 'Mission', + 'Parliament', + 'Probe', + 'Spies', + 'Trade', +]; + +const messageSummarySchema = { + type: 'object', + required: [ + 'id', + 'subject', + 'date', + 'from', + 'from_id', + 'to', + 'to_id', + 'has_read', + 'has_replied', + 'body_preview', + 'tags', + ], + properties: { + id: { type: 'string' }, + subject: { type: 'string' }, + date: { type: 'string' }, + from: { type: 'string' }, + from_id: { type: 'string' }, + to: { type: 'string' }, + to_id: { type: 'string' }, + has_read: { type: 'integer', enum: [1, 0] }, + has_replied: { type: 'integer', enum: [1, 0] }, + body_preview: { type: 'string' }, + tags: { type: 'string', enum: MESSAGE_TAGS }, + }, +}; + +const viewInboxRequestBody = requestBodySchema({ + type: 'object', + properties: { + options: { + type: 'object', + properties: { + page_number: { type: 'integer' }, + tags: { type: 'array', items: { type: 'string', enum: MESSAGE_TAGS } }, + empire: { type: 'string' }, + }, + }, + }, +}); + +const viewInboxResponses = (description: string) => ({ + ...response200(description, { + type: 'object', + required: ['messages', 'message_count', 'status'], + properties: { + messages: { type: 'array', items: messageSummarySchema }, + message_count: { type: 'integer' }, + status: statusSchema(), + }, + }), + ...response500(), +}); + +export const inbox = { + '/v2/inbox/view_inbox': { + post: { + ...security(), + ...viewInboxRequestBody, + responses: viewInboxResponses( + "Displays a list of the messages in the empire's inbox, 25 per page, newest to oldest." + ), + }, + }, + + '/v2/inbox/view_archived': { + post: { + ...security(), + ...viewInboxRequestBody, + responses: viewInboxResponses('Same as view_inbox, but shows archived messages.'), + }, + }, + + '/v2/inbox/view_trashed': { + post: { + ...security(), + ...viewInboxRequestBody, + responses: viewInboxResponses('Same as view_inbox, but shows trashed messages.'), + }, + }, + + '/v2/inbox/view_sent': { + post: { + ...security(), + ...viewInboxRequestBody, + responses: viewInboxResponses('Same as view_inbox, but shows sent messages.'), + }, + }, + + '/v2/inbox/view_unread': { + post: { + ...security(), + ...viewInboxRequestBody, + responses: viewInboxResponses('Same as view_inbox, but shows only unread messages.'), + }, + }, + + '/v2/inbox/read_message': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['message_id'], + properties: { message_id: { type: 'string' } }, + }), + + responses: { + ...response200('Retrieves a message and marks it read if it was not already.', { + type: 'object', + required: ['message', 'status'], + properties: { + message: { + type: 'object', + required: [ + 'id', + 'from', + 'from_id', + 'to', + 'to_id', + 'subject', + 'body', + 'date', + 'has_read', + 'has_replied', + 'has_archived', + 'has_trashed', + 'in_reply_to', + 'recipients', + 'tags', + ], + properties: { + id: { type: 'string' }, + from: { type: 'string' }, + from_id: { type: 'string' }, + to: { type: 'string' }, + to_id: { type: 'string' }, + subject: { type: 'string' }, + body: { type: 'string' }, + date: { type: 'string' }, + has_read: { type: 'integer', enum: [1, 0] }, + has_replied: { type: 'integer', enum: [1, 0] }, + has_archived: { type: 'integer', enum: [1, 0] }, + has_trashed: { type: 'integer', enum: [1, 0] }, + in_reply_to: { type: 'string' }, + // The complete list of empires who received the message. `to`/`to_id` above is + // just the empire that owns this particular copy of the message. + recipients: { type: 'array', items: { type: 'string' } }, + tags: { type: 'array', items: { type: 'string', enum: MESSAGE_TAGS } }, + // No more than one of each attachment type per message. + attachments: { + type: 'object', + properties: { + image: { + type: 'object', + required: ['url', 'title'], + properties: { + url: { type: 'string' }, + title: { type: 'string' }, + link: { type: 'string' }, + }, + }, + link: { + type: 'object', + required: ['url', 'label'], + properties: { url: { type: 'string' }, label: { type: 'string' } }, + }, + table: { type: 'array', items: { type: 'array', items: { type: 'string' } } }, + map: { + type: 'object', + required: ['surface', 'buildings'], + properties: { + surface: { type: 'string' }, + buildings: { + type: 'array', + items: { + type: 'object', + required: ['x', 'y', 'image'], + properties: { + x: { type: 'integer' }, + y: { type: 'integer' }, + image: { type: 'string' }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + '/v2/inbox/archive_messages': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['message_ids'], + properties: { message_ids: { type: 'array', items: { type: 'string' } } }, + }), + + responses: { + ...response200( + 'Archives a list of messages (marked as read in the process). Sent messages cannot be archived.', + { + type: 'object', + required: ['success', 'failure', 'status'], + properties: { + success: { type: 'array', items: { type: 'string' } }, + failure: { type: 'array', items: { type: 'string' } }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + '/v2/inbox/trash_messages': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['message_ids'], + properties: { message_ids: { type: 'array', items: { type: 'string' } } }, + }), + + responses: { + ...response200( + 'Trashes a list of messages (marked as read in the process). Only messages sent to you can be trashed.', + { + type: 'object', + required: ['success', 'status'], + properties: { + success: { type: 'array', items: { type: 'string' } }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + '/v2/inbox/trash_messages_where': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['spec'], + properties: { + spec: { + type: 'array', + items: { + type: 'object', + properties: { + tags: { type: 'array', items: { type: 'string', enum: MESSAGE_TAGS } }, + subject: { + oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }], + description: 'Use % as a wildcard, e.g. "Pass:%".', + }, + from: { type: 'array', items: { type: 'string' } }, + }, + }, + }, + return_ids: { type: 'boolean' }, + }, + }), + + responses: { + ...response200( + 'Trashes all messages matching every key of at least one spec entry (marked as read in the process).', + { + type: 'object', + required: ['deleted_count', 'status'], + properties: { + deleted: { + type: 'array', + items: { type: 'string' }, + description: 'Only present when return_ids is true.', + }, + deleted_count: { type: 'integer' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + '/v2/inbox/send_message': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['recipients', 'subject', 'body'], + properties: { + recipients: { + type: 'string', + description: + 'Comma separated empire names. "@ally" is a shortcut for all members of your alliance.', + }, + subject: { type: 'string', maxLength: 100 }, + body: { type: 'string', maxLength: 200000 }, + options: { + type: 'object', + properties: { + in_reply_to: { type: 'string' }, + forward: { + type: 'string', + description: + 'A message id whose attachments should be sent along with this message.', + }, + }, + }, + }, + }), + + responses: { + ...response200('Sends a message to other players.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/map.ts b/src/spec/paths/map.ts new file mode 100644 index 0000000..3e51593 --- /dev/null +++ b/src/spec/paths/map.ts @@ -0,0 +1,342 @@ +import { requestBodySchema, response200, response500, security, statusSchema } from '../chunks'; + +const empireSnippetSchema = { + type: 'object', + required: ['id', 'name', 'alignment', 'is_isolationist'], + properties: { + id: { type: 'number' }, + name: { type: 'string' }, + alignment: { type: 'string', enum: ['ally', 'self', 'hostile'] }, + is_isolationist: { type: 'integer', enum: [1, 0] }, + }, +}; + +const stationSnippetSchema = { + type: 'object', + required: ['id', 'x', 'y', 'name'], + properties: { + id: { type: 'string' }, + x: { type: 'number' }, + y: { type: 'number' }, + name: { type: 'string' }, + }, +}; + +const bodySnippetSchema = { + type: 'object', + required: ['name', 'id', 'orbit', 'x', 'y', 'type', 'image', 'size'], + properties: { + name: { type: 'string' }, + id: { type: 'number' }, + orbit: { type: 'integer' }, + x: { type: 'number' }, + y: { type: 'number' }, + type: { type: 'string' }, + image: { type: 'string' }, + size: { type: 'number' }, + // Only present if the body is occupied by an empire. + empire: empireSnippetSchema, + // Only present on asteroids/bodies that have a fissure. + body_has_fissure: { type: 'integer', enum: [1, 0] }, + }, +}; + +const starDetailSchema = { + type: 'object', + required: ['name', 'color', 'x', 'y', 'zone', 'id'], + properties: { + name: { type: 'string' }, + color: { type: 'string' }, + x: { type: 'number' }, + y: { type: 'number' }, + zone: { type: 'string' }, + id: { type: 'string' }, + // Only present if this star is under the influence of a space station. + station: stationSnippetSchema, + // Only present if a probe is present in the system. + bodies: { type: 'array', items: { $ref: '#/components/schemas/body_status' } }, + }, +}; + +const starDetailResponses = (description: string) => ({ + ...response200(description, { + type: 'object', + required: ['star', 'status'], + properties: { star: starDetailSchema, status: statusSchema() }, + }), + ...response500(), +}); + +export const map = { + '/v2/map/get_star_map': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['left', 'top', 'right', 'bottom'], + properties: { + left: { type: 'number' }, + top: { type: 'number' }, + right: { type: 'number' }, + bottom: { type: 'number' }, + }, + }), + + responses: { + ...response200( + "The preferred, 'lite' way to draw the starmap — returns just enough data to render it, and does not include most owned-planet detail (ore, water, etc). Maximum requestable area is 1001 units (e.g. 50x20 or 1001x1).", + { + type: 'object', + required: ['stars'], + properties: { + stars: { + type: 'array', + items: { + type: 'object', + required: ['name', 'color', 'x', 'y', 'id', 'bodies'], + properties: { + name: { type: 'string' }, + color: { type: 'string' }, + x: { type: 'number' }, + y: { type: 'number' }, + id: { type: 'number' }, + // Only present if this star is under the influence of a space station. + station: { + type: 'object', + required: ['id', 'x', 'y', 'name', 'alliance'], + properties: { + id: { type: 'number' }, + x: { type: 'number' }, + y: { type: 'number' }, + name: { type: 'string' }, + alliance: { + type: 'object', + required: ['name', 'id', 'image'], + properties: { + name: { type: 'string' }, + id: { type: 'number' }, + image: { type: 'string' }, + }, + }, + }, + }, + bodies: { type: 'array', items: bodySnippetSchema }, + }, + }, + }, + }, + } + ), + ...response500(), + }, + }, + }, + + '/v2/map/get_stars': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['x1', 'y1', 'x2', 'y2'], + properties: { + x1: { type: 'number' }, + y1: { type: 'number' }, + x2: { type: 'number' }, + y2: { type: 'number' }, + }, + }), + + responses: { + ...response200( + 'Retrieves a chunk of the map. Coordinates without a star are omitted from the results. Maximum requestable area is 900 spaces (e.g. 30x30). Throws 1003 if the area is too large.', + { + type: 'object', + required: ['stars', 'status'], + properties: { + stars: { type: 'array', items: starDetailSchema }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + '/v2/map/check_star_for_incoming_probe': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['star_id'], + properties: { star_id: { type: 'string' } }, + }), + + responses: { + ...response200( + 'If the star has a status of "unprobed", call this to check whether a probe from this empire is inbound.', + { + type: 'object', + required: ['status'], + properties: { + status: statusSchema(), + // Only present if a probe is inbound. + incoming_probe: { type: 'string' }, + }, + } + ), + ...response500(), + }, + }, + }, + + '/v2/map/get_star': { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['star_id'], + properties: { star_id: { type: 'string' } }, + }), + responses: starDetailResponses('Retrieves info on a single star.'), + }, + }, + + '/v2/map/get_star_by_name': { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['name'], + properties: { name: { type: 'string' } }, + }), + responses: starDetailResponses( + 'Retrieves info on a single star by its exact (case insensitive) name.' + ), + }, + }, + + '/v2/map/get_star_by_xy': { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['x', 'y'], + properties: { x: { type: 'number' }, y: { type: 'number' } }, + }), + responses: starDetailResponses('Retrieves info on a single star by coordinates.'), + }, + }, + + '/v2/map/search_stars': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['name'], + properties: { name: { type: 'string' } }, + }), + + responses: { + ...response200( + 'Searches for stars by partial, case insensitive name (minimum 3 characters). No body data is returned. Returns up to 25 results.', + { + type: 'object', + required: ['stars', 'status'], + properties: { + stars: { + type: 'array', + items: { + type: 'object', + required: ['name', 'color', 'x', 'y'], + properties: { + name: { type: 'string' }, + color: { type: 'string' }, + x: { type: 'number' }, + y: { type: 'number' }, + }, + }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + '/v2/map/probe_summary_fissures': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + properties: { + zone: { + type: 'string', + description: + 'A zone string, e.g. "-1|0", "5|-5", or "0|0". If omitted, all zones are searched.', + }, + }, + }), + + responses: { + ...response200( + "A summary of every body with a fissure known to your (or your alliance's) probes in the given zone. Returns an empty object if no fissures are known.", + { + type: 'object', + properties: { + fissures: { + type: 'object', + description: 'Keyed by body id.', + additionalProperties: bodySnippetSchema, + }, + }, + } + ), + ...response500(), + }, + }, + }, + + '/v2/map/view_laws': { + post: { + ...security(), + + ...requestBodySchema({ + type: 'object', + required: ['star_id'], + properties: { star_id: { type: 'string' } }, + }), + + responses: { + ...response200('Returns the laws enacted by the space station controlling this star.', { + type: 'object', + required: ['status', 'laws'], + properties: { + status: statusSchema(), + laws: { + type: 'array', + items: { + type: 'object', + required: ['id', 'name', 'description', 'date_enacted'], + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + description: { type: 'string' }, + date_enacted: { type: 'string' }, + }, + }, + }, + }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/modules/artmuseum.ts b/src/spec/paths/modules/artmuseum.ts new file mode 100644 index 0000000..b76374f --- /dev/null +++ b/src/spec/paths/modules/artmuseum.ts @@ -0,0 +1,48 @@ +import { + buildingBase, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('ArtMuseum'); + +// ArtMuseum.pod documents no methods beyond those shared by all Modules (see Modules.pod), so +// this only defines `view`. +export const artMuseum = { + [`${base}/view`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, + }), + responses: { + ...response200('Retrieves the properties of this module.', { + type: 'object', + required: ['building', 'status'], + properties: { + building: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + image: { type: 'string' }, + level: { type: 'integer' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + efficiency: { type: 'integer' }, + }, + required: ['id', 'name', 'image', 'level', 'x', 'y', 'efficiency'], + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/modules/culinaryinstitute.ts b/src/spec/paths/modules/culinaryinstitute.ts new file mode 100644 index 0000000..910bb42 --- /dev/null +++ b/src/spec/paths/modules/culinaryinstitute.ts @@ -0,0 +1,48 @@ +import { + buildingBase, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('CulinaryInstitute'); + +// CulinaryInstitute.pod documents no methods beyond those shared by all Modules (see +// Modules.pod), so this only defines `view`. +export const culinaryInstitute = { + [`${base}/view`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, + }), + responses: { + ...response200('Retrieves the properties of this module.', { + type: 'object', + required: ['building', 'status'], + properties: { + building: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + image: { type: 'string' }, + level: { type: 'integer' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + efficiency: { type: 'integer' }, + }, + required: ['id', 'name', 'image', 'level', 'x', 'y', 'efficiency'], + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/modules/ibs.ts b/src/spec/paths/modules/ibs.ts new file mode 100644 index 0000000..77ff69a --- /dev/null +++ b/src/spec/paths/modules/ibs.ts @@ -0,0 +1,48 @@ +import { + buildingBase, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('IBS'); + +// IBS.pod (Interstellar Broadcast System) documents no methods beyond those shared by all +// Modules (see Modules.pod), so this only defines `view`. +export const ibs = { + [`${base}/view`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, + }), + responses: { + ...response200('Retrieves the properties of this module.', { + type: 'object', + required: ['building', 'status'], + properties: { + building: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + image: { type: 'string' }, + level: { type: 'integer' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + efficiency: { type: 'integer' }, + }, + required: ['id', 'name', 'image', 'level', 'x', 'y', 'efficiency'], + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/modules/index.ts b/src/spec/paths/modules/index.ts new file mode 100644 index 0000000..4cfd03e --- /dev/null +++ b/src/spec/paths/modules/index.ts @@ -0,0 +1,19 @@ +import { artMuseum } from './artmuseum'; +import { culinaryInstitute } from './culinaryinstitute'; +import { ibs } from './ibs'; +import { operaHouse } from './operahouse'; +import { parliament } from './parliament'; +import { policeStation } from './policestation'; +import { stationCommand } from './stationcommand'; +import { warehouse } from './warehouse'; + +export const modules = { + ...artMuseum, + ...culinaryInstitute, + ...ibs, + ...operaHouse, + ...parliament, + ...policeStation, + ...stationCommand, + ...warehouse, +}; diff --git a/src/spec/paths/modules/operahouse.ts b/src/spec/paths/modules/operahouse.ts new file mode 100644 index 0000000..1162097 --- /dev/null +++ b/src/spec/paths/modules/operahouse.ts @@ -0,0 +1,48 @@ +import { + buildingBase, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('OperaHouse'); + +// OperaHouse.pod documents no methods beyond those shared by all Modules (see Modules.pod), so +// this only defines `view`. +export const operaHouse = { + [`${base}/view`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, + }), + responses: { + ...response200('Retrieves the properties of this module.', { + type: 'object', + required: ['building', 'status'], + properties: { + building: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + image: { type: 'string' }, + level: { type: 'integer' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + efficiency: { type: 'integer' }, + }, + required: ['id', 'name', 'image', 'level', 'x', 'y', 'efficiency'], + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/modules/parliament.ts b/src/spec/paths/modules/parliament.ts new file mode 100644 index 0000000..a8e8478 --- /dev/null +++ b/src/spec/paths/modules/parliament.ts @@ -0,0 +1,504 @@ +import { + buildingBase, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Parliament'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +// Shared shape returned by view_propositions, cast_vote, and every propose_* method. +const propositionSchema = { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + description: { type: 'string' }, + votes_needed: { type: 'integer' }, + votes_yes: { type: 'integer' }, + votes_no: { type: 'integer' }, + status: { type: 'string' }, + date_ends: { type: 'string' }, + proposed_by: { + type: 'object', + properties: { id: { type: 'string' }, name: { type: 'string' } }, + }, + my_vote: { + type: 'integer', + enum: [1, 0], + description: 'Only present if this empire has voted.', + }, + }, +}; + +const propositionResponses = (description: string) => ({ + ...response200(description, { + type: 'object', + required: ['status', 'proposition'], + properties: { status: statusSchema(), proposition: propositionSchema }, + }), + ...response500(), +}); + +// Builds one `propose_*` (or the `allow_bhg_by_alliance`) endpoint. Every proposition method +// takes `building_id` plus its own params, and returns the same {status, proposition} shape. +const proposeMethod = ( + name: string, + description: string, + extraRequired: string[] = [], + extraProperties: object = {} +) => ({ + [`${base}/${name}`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', ...extraRequired], + properties: { building_id: { type: 'string' }, ...extraProperties }, + }), + responses: propositionResponses(description), + }, + }, +}); + +// Parliament is the module through which all module build/upgrade/downgrade/demolish/repair +// acts, plus a range of station-governance actions, are proposed to and voted on by alliance +// members (see Modules.pod). Most of the endpoints below are one proposition type each; casting +// a vote and viewing propositions are separate, non-proposition methods. +export const parliament = { + [`${base}/view`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Retrieves the properties of this module.', { + type: 'object', + required: ['building', 'status'], + properties: { + building: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + image: { type: 'string' }, + level: { type: 'integer' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + efficiency: { type: 'integer' }, + }, + required: ['id', 'name', 'image', 'level', 'x', 'y', 'efficiency'], + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_laws`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['body_id'], + properties: { + body_id: { type: 'string', description: 'The unique id of the space station.' }, + }, + }), + responses: { + ...response200( + "Lists the laws currently in effect for this station's jurisdiction. Still usable, but superseded by the equivalent call on Body.", + { + type: 'object', + required: ['laws', 'status'], + properties: { + laws: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + description: { type: 'string' }, + date_enacted: { type: 'string' }, + }, + }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/view_propositions`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Returns a list of the pending propositions.', { + type: 'object', + required: ['propositions', 'status'], + properties: { + propositions: { type: 'array', items: propositionSchema }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_taxes_collected`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + 'Returns, for each empire that has paid taxes, their payments for today and the previous six days plus the seven-day total.', + { + type: 'object', + required: ['taxes_collected', 'status'], + properties: { + taxes_collected: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + paid: { + type: 'array', + items: { type: 'integer' }, + description: 'Element 0 is today, followed by the previous six days.', + }, + total: { type: 'integer' }, + }, + }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/get_stars_in_jurisdiction`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Returns a list of the stars in the jurisdiction of this space station.', { + type: 'object', + required: ['stars', 'status'], + properties: { + stars: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + color: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + station: { + type: 'object', + description: + 'Only present if this star is under the influence of a space station.', + properties: { + id: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/get_bodies_for_star_in_jurisdiction`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'star_id'], + properties: { + building_id: { type: 'string' }, + star_id: { + type: 'string', + description: 'The unique id of a star in jurisdiction. See get_stars_in_jurisdiction.', + }, + }, + }), + responses: { + ...response200( + 'Returns a list of the bodies for a star in the jurisdiction of the space station.', + { + type: 'object', + required: ['bodies', 'status'], + properties: { + bodies: { type: 'array', items: { $ref: '#/components/schemas/body_status' } }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/get_mining_platforms_for_asteroid_in_jurisdiction`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'asteroid_id'], + properties: { + building_id: { type: 'string' }, + asteroid_id: { + type: 'string', + description: + 'The unique id of an asteroid in jurisdiction. See get_bodies_for_star_in_jurisdiction.', + }, + }, + }), + responses: { + ...response200( + 'Returns a list of the mining platforms for an asteroid in the jurisdiction of the space station.', + { + type: 'object', + required: ['platforms', 'status'], + properties: { + platforms: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + empire: { + type: 'object', + properties: { id: { type: 'string' }, name: { type: 'string' } }, + }, + }, + }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/cast_vote`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'proposition_id'], + properties: { + building_id: { type: 'string' }, + proposition_id: { + type: 'string', + description: 'The id of the proposition being voted on. See view_propositions.', + }, + vote: { + type: 'integer', + enum: [1, 0], + description: '1 for yes, 0 for no. Defaults to 0.', + }, + }, + }), + responses: propositionResponses( + 'Casts a vote for or against a proposition. Cannot be voted on using a sitter password.' + ), + }, + }, + + // --- Proposition methods ------------------------------------------------------------------- + // Each proposes a law or action for Parliament to vote on; the vote itself is cast separately + // via cast_vote. Many require a minimum Parliament level, noted per-method below. + + ...proposeMethod( + 'propose_writ', + 'Proposes an unenforceable law (writ). Requires Parliament level 4+.', + ['title', 'description'], + { title: { type: 'string' }, description: { type: 'string' } } + ), + + ...proposeMethod( + 'propose_repeal_law', + 'Proposes repealing an existing law. Requires Parliament level 5+.', + ['law_id'], + { law_id: { type: 'string' } } + ), + + ...proposeMethod( + 'propose_transfer_station_ownership', + 'Proposes transferring ownership of the station to another alliance member. Requires Parliament level 6+.', + ['to_empire_id'], + { to_empire_id: { type: 'string' } } + ), + + ...proposeMethod( + 'propose_rename_star', + 'Proposes renaming a star. Requires Parliament level 8+.', + ['star_id', 'name'], + { star_id: { type: 'string' }, name: { type: 'string' } } + ), + + ...proposeMethod( + 'propose_broadcast_on_network19', + 'Proposes broadcasting a message on Network 19. Requires Parliament level 9+.', + ['message'], + { + message: { + type: 'string', + maxLength: 140, + description: 'Cannot contain special characters or profanity.', + }, + } + ), + + ...proposeMethod( + 'propose_induct_member', + 'Proposes inducting a new member into the alliance; if passed, an invitation is sent. Requires Parliament level 10+.', + ['empire_id'], + { + empire_id: { type: 'string' }, + message: { + type: 'string', + description: 'Optional personalized welcome message included in the invitation.', + }, + } + ), + + ...proposeMethod( + 'propose_expel_member', + 'Proposes expelling a member from the alliance. Requires Parliament level 10+.', + ['empire_id'], + { + empire_id: { type: 'string' }, + message: { + type: 'string', + description: 'Optional reason. Cannot contain restricted characters or profanity.', + }, + } + ), + + ...proposeMethod( + 'propose_elect_new_leader', + 'Proposes electing a new alliance leader (who must already be a member). Requires Parliament level 11+.', + ['to_empire_id'], + { to_empire_id: { type: 'string' } } + ), + + ...proposeMethod( + 'propose_rename_asteroid', + 'Proposes renaming an asteroid in the jurisdiction. Requires Parliament level 12+.', + ['asteroid_id', 'name'], + { asteroid_id: { type: 'string' }, name: { type: 'string', maxLength: 30 } } + ), + + ...proposeMethod( + 'propose_members_only_mining_rights', + 'Proposes restricting new mining platforms in the jurisdiction to alliance members only. Requires Parliament level 13+.' + ), + + ...proposeMethod( + 'propose_evict_mining_platform', + 'Proposes destroying a mining platform on an asteroid. Requires Parliament level 14+.', + ['platform_id'], + { + platform_id: { + type: 'string', + description: 'See get_mining_platforms_for_asteroid_in_jurisdiction.', + }, + } + ), + + ...proposeMethod( + 'propose_taxation', + 'Proposes an unenforceable daily tax on all empires in the jurisdiction. Requires Parliament level 15+.', + ['taxes'], + { taxes: { type: 'integer', description: 'The amount of resources to tax per day.' } } + ), + + ...proposeMethod( + 'propose_foreign_aid', + 'Proposes sending a foreign aid supply pod to a planet in the jurisdiction. Costs double the resources sent (half covers the pod, half is the aid). Limited to one per day, like normal supply pods. Requires Parliament level 16+.', + ['planet_id', 'resources'], + { + planet_id: { type: 'string' }, + resources: { + type: 'integer', + description: 'The amount of resources to send to the receiving planet.', + }, + } + ), + + ...proposeMethod( + 'propose_rename_uninhabited', + 'Proposes renaming an uninhabited planet in the jurisdiction. Requires Parliament level 17+.', + ['planet_id', 'name'], + { planet_id: { type: 'string' }, name: { type: 'string', maxLength: 30 } } + ), + + ...proposeMethod( + 'propose_members_only_colonization', + 'Proposes restricting new colonies in the jurisdiction to alliance members only. Requires Parliament level 18+.' + ), + + ...proposeMethod( + 'propose_members_only_excavation', + 'Proposes restricting new excavations in the jurisdiction to alliance members only. Requires Parliament level 18+.' + ), + + ...proposeMethod( + 'propose_members_only_stations', + 'Proposes restricting new space stations in the jurisdiction to alliance members only. Requires Parliament level 18+.' + ), + + ...proposeMethod( + 'propose_neutralize_bhg', + 'Proposes preventing non-alliance members from using Black Hole Generators on or from systems in the jurisdiction. Requires Parliament level 23+.' + ), + + ...proposeMethod( + 'propose_fire_bfg', + 'Proposes firing the BFG equipped on all space stations at a planet within the jurisdiction. Requires Parliament level 25+.', + ['body_id', 'reason'], + { + body_id: { type: 'string', description: 'See get_bodies_for_star_in_jurisdiction.' }, + reason: { type: 'string' }, + } + ), + + ...proposeMethod( + 'allow_bhg_by_alliance', + 'Proposes allowing another alliance to use Black Hole Generators in this jurisdiction, ignoring members-only colonization/stations restrictions. Requires Parliament level 28+.', + ['alliance_id'], + { alliance_id: { type: 'string' } } + ), +}; diff --git a/src/spec/paths/modules/policestation.ts b/src/spec/paths/modules/policestation.ts new file mode 100644 index 0000000..68e7c1d --- /dev/null +++ b/src/spec/paths/modules/policestation.ts @@ -0,0 +1,282 @@ +import { + buildingBase, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('PoliceStation'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +const pagedRequestBody = (extraRequired: string[] = [], extraProperties: object = {}) => + requestBodySchema({ + type: 'object', + required: ['building_id', ...extraRequired], + properties: { + building_id: { type: 'string' }, + page_number: { + type: 'integer', + description: 'Defaults to 1. Each page contains 25 results.', + }, + ...extraProperties, + }, + }); + +const shipSchema = { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + type: { type: 'string' }, + type_human: { type: 'string' }, + date_arrives: { type: 'string' }, + date_arrived: { type: 'string' }, + from: { + type: 'object', + description: + "Only included if the ship's stealth is low enough relative to the Police Station's level.", + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + empire: { + type: 'object', + properties: { id: { type: 'string' }, name: { type: 'string' } }, + }, + }, + }, + }, +}; + +// PoliceStation.pod: "captured spies are detained at the Police Station." Its .pod header refers +// to it as extending Buildings, but per Modules.pod, PoliceStation is a module and does not +// inherit build/upgrade/downgrade/demolish/repair. +export const policeStation = { + [`${base}/view`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Retrieves the properties of this module.', { + type: 'object', + required: ['building', 'status'], + properties: { + building: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + image: { type: 'string' }, + level: { type: 'integer' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + efficiency: { type: 'integer' }, + }, + required: ['id', 'name', 'image', 'level', 'x', 'y', 'efficiency'], + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_prisoners`]: { + post: { + ...security(), + ...pagedRequestBody(), + responses: { + ...response200('Displays a list of the spies that have been captured.', { + type: 'object', + required: ['prisoners', 'status'], + properties: { + prisoners: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + level: { type: 'integer' }, + task: { type: 'string', enum: ['Captured', 'Prisoner Transport'] }, + sentence_expires: { type: 'string' }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/execute_prisoner`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'prisoner_id'], + properties: { building_id: { type: 'string' }, prisoner_id: { type: 'string' } }, + }), + responses: { + ...response200( + 'Executes a captured prisoner rather than letting them serve their sentence.', + { type: 'object', required: ['status'], properties: { status: statusSchema() } } + ), + ...response500(), + }, + }, + }, + + [`${base}/release_prisoner`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id', 'prisoner_id'], + properties: { building_id: { type: 'string' }, prisoner_id: { type: 'string' } }, + }), + responses: { + ...response200('Releases a captured prisoner.', { + type: 'object', + required: ['status'], + properties: { status: statusSchema() }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_foreign_spies`]: { + post: { + ...security(), + ...pagedRequestBody(), + responses: { + ...response200( + 'Displays a list of the spies on your planet with a level lower than your Police Station.', + { + type: 'object', + required: ['spies', 'status'], + properties: { + spies: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + level: { type: 'integer' }, + task: { type: 'string' }, + next_mission: { type: 'string' }, + }, + }, + }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/view_foreign_ships`]: { + post: { + ...security(), + ...pagedRequestBody(), + responses: { + ...response200( + "Shows incoming foreign ships filtered by the ship's stealth vs the Police Station's level (525 * level >= stealth to be visible at all; the `from` block requires 675 * level >= stealth).", + { + type: 'object', + required: ['ships', 'number_of_ships', 'status'], + properties: { + ships: { type: 'array', items: shipSchema }, + number_of_ships: { type: 'integer' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/view_ships_travelling`]: { + post: { + ...security(), + ...pagedRequestBody(), + responses: { + ...response200( + 'Returns a list of ships travelling to or from this planet, regardless of destination space port.', + { + type: 'object', + required: ['ships_travelling', 'number_of_ships_travelling', 'status'], + properties: { + ships_travelling: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + type: { type: 'string' }, + type_human: { type: 'string' }, + date_arrives: { type: 'string' }, + from: { + type: 'object', + properties: { + id: { type: 'string' }, + type: { type: 'string' }, + name: { type: 'string' }, + }, + }, + to: { + type: 'object', + properties: { + id: { type: 'string' }, + type: { type: 'string' }, + name: { type: 'string' }, + }, + }, + }, + }, + }, + number_of_ships_travelling: { type: 'integer' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/view_ships_orbiting`]: { + post: { + ...security(), + ...pagedRequestBody(), + responses: { + ...response200( + "Shows foreign ships orbiting this planet, filtered by the ship's stealth vs the Police Station's level (525 * level >= stealth to be visible at all; the `from` block requires 675 * level >= stealth).", + { + type: 'object', + required: ['ships', 'number_of_ships', 'status'], + properties: { + ships: { type: 'array', items: shipSchema }, + number_of_ships: { type: 'integer' }, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/modules/stationcommand.ts b/src/spec/paths/modules/stationcommand.ts new file mode 100644 index 0000000..77b5f4e --- /dev/null +++ b/src/spec/paths/modules/stationcommand.ts @@ -0,0 +1,169 @@ +import { + buildingBase, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('StationCommand'); + +const buildingIdRequestBody = requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, +}); + +// StationCommand.pod's `planet` block on `view` documents the space station's own body/resource +// status, reusing the same shape as body_status plus counts/stores similar to statusSchema's body. +const planetSchema = { + type: 'object', + properties: { + id: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + star_id: { type: 'string' }, + orbit: { type: 'integer' }, + type: { type: 'string' }, + name: { type: 'string' }, + image: { type: 'string' }, + size: { type: 'integer' }, + water: { type: 'integer' }, + ore: { type: 'object', additionalProperties: { type: 'integer' } }, + building_count: { type: 'integer' }, + population: { type: 'integer' }, + happiness: { type: 'integer' }, + happiness_hour: { type: 'integer' }, + food_stored: { type: 'integer' }, + food_capacity: { type: 'integer' }, + food_hour: { type: 'integer' }, + energy_stored: { type: 'integer' }, + energy_capacity: { type: 'integer' }, + energy_hour: { type: 'integer' }, + ore_hour: { type: 'integer' }, + ore_capacity: { type: 'integer' }, + ore_stored: { type: 'integer' }, + waste_hour: { type: 'integer' }, + waste_stored: { type: 'integer' }, + waste_capacity: { type: 'integer' }, + water_stored: { type: 'integer' }, + water_hour: { type: 'integer' }, + water_capacity: { type: 'integer' }, + }, +}; + +// Station Command Center. StationCommand.pod: "Command extends the view method to include a +// `planet` section" plus `next_colony_cost`. +export const stationCommand = { + [`${base}/view`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200( + "Retrieves the properties of this module, plus the station's own planet data.", + { + type: 'object', + required: ['building', 'status', 'next_colony_cost', 'planet'], + properties: { + building: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + image: { type: 'string' }, + level: { type: 'integer' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + efficiency: { type: 'integer' }, + }, + required: ['id', 'name', 'image', 'level', 'x', 'y', 'efficiency'], + }, + next_colony_cost: { + type: 'integer', + description: 'The amount of happiness required to settle your next colony.', + }, + planet: planetSchema, + status: statusSchema(), + }, + } + ), + ...response500(), + }, + }, + }, + + [`${base}/view_plans`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Returns a list of all the plans this empire has collected.', { + type: 'object', + required: ['plans', 'status'], + properties: { + plans: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + level: { type: 'integer' }, + extra_build_level: { + type: 'integer', + description: + 'If level is 1 and this is present, the building will be built up to 1 plus this value when complete.', + }, + }, + required: ['name', 'level'], + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, + + [`${base}/view_incoming_supply_chains`]: { + post: { + ...security(), + ...buildingIdRequestBody, + responses: { + ...response200('Returns a list of all incoming supply chains feeding this planet.', { + type: 'object', + required: ['supply_chains', 'status'], + properties: { + supply_chains: { + type: 'array', + items: { + type: 'object', + properties: { + id: { type: 'string' }, + from_body: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + image: { type: 'string' }, + }, + }, + resource_hour: { type: 'integer' }, + resource_type: { type: 'string' }, + percent_transferred: { type: 'integer' }, + stalled: { type: 'integer', enum: [1, 0] }, + }, + }, + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, +}; diff --git a/src/spec/paths/modules/warehouse.ts b/src/spec/paths/modules/warehouse.ts new file mode 100644 index 0000000..286d67b --- /dev/null +++ b/src/spec/paths/modules/warehouse.ts @@ -0,0 +1,48 @@ +import { + buildingBase, + requestBodySchema, + response200, + response500, + security, + statusSchema, +} from '../../chunks'; + +const base = buildingBase('Warehouse'); + +// Warehouse.pod documents no methods beyond those shared by all Modules (see Modules.pod), so +// this only defines `view`. +export const warehouse = { + [`${base}/view`]: { + post: { + ...security(), + ...requestBodySchema({ + type: 'object', + required: ['building_id'], + properties: { building_id: { type: 'string' } }, + }), + responses: { + ...response200('Retrieves the properties of this module.', { + type: 'object', + required: ['building', 'status'], + properties: { + building: { + type: 'object', + properties: { + id: { type: 'string' }, + name: { type: 'string' }, + image: { type: 'string' }, + level: { type: 'integer' }, + x: { type: 'integer' }, + y: { type: 'integer' }, + efficiency: { type: 'integer' }, + }, + required: ['id', 'name', 'image', 'level', 'x', 'y', 'efficiency'], + }, + status: statusSchema(), + }, + }), + ...response500(), + }, + }, + }, +};