// Server runtime flags read from the environment once at startup. import { MIN_PLAYERS } from '../../engine/lobby.js' /** * The account whose `actor.rpg.sprite/self` record we clone when a freshly logged-in player opts for * the default actor instead of creating their own at rpg.actor (see /api/sprite/default). Read from * `SABOTAGE_DEFAULT_SPRITE_DID`; falls back to the known-good default actor so local dev works with * no env setup. */ export const DEFAULT_SPRITE_DID = process.env.SABOTAGE_DEFAULT_SPRITE_DID?.trim() || 'did:plc:tf6ewqt32uhclenkhfzjaglo' /** * Dev solo mode (`SABOTAGE_DEV_SOLO=1`). Lowers the minimum roster/participant count to one so a * single logged-in user can create and start a game by themselves — they then become the saboteur * (pickSaboteur on a one-player set returns that player). Strictly a local-dev affordance for * walking the rendered world without four real OAuth logins; never set this in production. */ export const DEV_SOLO = process.env.SABOTAGE_DEV_SOLO === '1' || process.env.SABOTAGE_DEV_SOLO === 'true' /** * Play-test interest mode (`SABOTAGE_PLAYTEST=1`). When on, the Deception case opens an "I'm * interested in play-testing" page instead of the map chooser: it links the player to the * play-testing group chat (client-side, VITE_PLAYTEST_CHAT_URL) rather than starting a game — no PDS * write. Used while the mode is gated. Surfaced to the client via /api/session so the SPA can swap pages. */ export const PLAYTEST = process.env.SABOTAGE_PLAYTEST === '1' || process.env.SABOTAGE_PLAYTEST === 'true' /** Minimum players to create/start a game — 1 in dev solo mode, otherwise the engine default. */ export const MIN_PLAYERS_EFFECTIVE = DEV_SOLO ? 1 : MIN_PLAYERS /** A playable map offered to clients (the map chooser). Mirrors town.deception.listMaps#mapRef. */ export interface CuratedMap { /** AT-URI of the world.tilemap.map record. */ uri: string /** Human-friendly display name. */ name: string } /** * The curated set of maps the server offers via town.deception.listMaps — today just the farm map. * The map's AT-URI is read from `SABOTAGE_FARM_MAP_URI` (its name from `SABOTAGE_FARM_MAP_NAME`, * default 'Farm'); we fall back to the known-good farm map Chris shared so local dev works without * any env setup. Set the env var to point at a different map. An empty/whitespace override yields an * empty list (the chooser shows "no maps available"). */ // The 'Farm' record with authored stations (4 collect / 4 deposit / meeting / spawn). The earlier // default (…/3mnkrgzpfiw22) was actually the stationless 'Beach Day' record, so deduction rejected it // with map-has-no-inspectable-stations — that map has no town.deception.collect/deposit markers. const DEFAULT_FARM_MAP_URI = 'at://did:plc:dp7v5b5kejmmzzpwmqyf5wj6/world.tilemap.map/3mnma4hb5ba22' export const CURATED_MAPS: CuratedMap[] = buildCuratedMaps() function buildCuratedMaps(): CuratedMap[] { const raw = process.env.SABOTAGE_FARM_MAP_URI // Unset → dev default; explicitly set-but-empty → no maps. const uri = (raw === undefined ? DEFAULT_FARM_MAP_URI : raw).trim() if (!uri) return [] const name = process.env.SABOTAGE_FARM_MAP_NAME?.trim() || 'Farm' return [{ uri, name }] }