/** * THE CAPITAL'S SHOPS AND SET PIECES (track T90, 2026-10-14; plan `.cursor/task-plans/2026-10-14-t90-capital-shops.md`), the follow-on to * T77's quests (capitalQuests.ts). After T77 the Capital had thirteen quests and no shops: the planned market and district NPC spots * (CAPITAL_NPC_SPOTS) were empty tiles. This file puts eight shopkeepers on them, and adds the two set pieces T77 left: * * - EIGHT SHOPKEEPERS, named residents on the city-folk look (the client dresses a Capital person by its id; the chandler is a docker), * each with a counter of EXISTING goods. Every counter is a world.ts NAMED_SHOPKEEPERS entry keyed by name. The profit-loop rule holds * across all counters (no counter buys a line for more than any counter sells it for): buy-backs are the universal rates already in the game * (Trader Joe's table, the Northern Gate Stores' silver and gold, Saul's fish) or a tenth of the counter price (bows). * Armour and weapon prices are a placeholder formula (bars x a per-metal unit) for the balance pass; nobody buys that gear back. * - A HARBOUR FISHING ERRAND, A Catch for the Galley (the Ship's Chandler Jory Tolliver, Fishing 14): three fixed tide snapper spots off the * east end of the Royal Pier (the existing fish, the small rod and crab meat the chandler sells or hands over). * - THE WALL ALARM: a night set piece on the north ring road. A clock-read window (UTC night hours, ten minutes in every thirty) in which a * small scaled stream of prowlers climbs the wall. Nothing is rolled or stored: the window is read off the clock, so a restart or a second * server agrees. Every number is a PLACEHOLDER for the balance pass. * * Imports only erased types from storyQuests.ts, so storyQuests.ts can spread CAPITAL_SHOP_QUESTS with no cycle. */ import type { StoryQuestDef } from './storyQuests.js'; /** What one bar of each metal counts for at the armourer's and the weaponsmith's counters (PLACEHOLDER, balance pass). John's Armoury sells poplar at 1200-2200. */ export declare const CAPITAL_BAR_UNIT_PRICE: Readonly>; /** The counter price of a forged piece: the bars it takes times the metal's unit price (wood is not counted), or 0 for a piece with no such recipe. */ export declare function capitalForgedPrice(output: string): number; /** The role the client dresses a Capital person by (the id prefix `capital--`). The chandler is a docker; everyone else is city folk. */ export type CapitalShopRole = 'folk' | 'docker'; export type CapitalShopLine = { readonly kind: string; readonly price: number; }; export type CapitalShopFolk = { readonly key: string; readonly name: string; readonly role: CapitalShopRole; /** Where they stand (world tiles) and what they face. */ readonly x: number; readonly z: number; readonly faceX: number; readonly faceZ: number; /** The plan's NPC spot id they stand on, or '' for the chandler (the harbour has none). */ readonly spotId: string; /** For the guide: where the counter is. */ readonly place: string; readonly shopTitle: string; readonly stock: ReadonlyArray; /** What the counter buys back. */ readonly buys: Readonly>; /** The general store buys what Trader Joe buys, at his rates (the backend spreads its own table in: the types do not hold it). */ readonly buysLikeTrader?: true; /** The Speak line, and the line for the Trade option (the client's menu). */ readonly speak: string; readonly trade: string; }; export declare const CAPITAL_SHOP_NAMES: { readonly store: "Storekeeper Wilm Ardent"; readonly armourer: "Armourer Berta Stonewell"; readonly weaponsmith: "Weaponsmith Ivo Draymark"; readonly fletcher: "Fletcher Linnet Swift"; readonly apothecary: "Apothecary Sorrel Quince"; readonly baker: "Baker Maud Pennick"; readonly assayer: "Assayer Joren Marchant"; readonly chandler: "Ship's Chandler Jory Tolliver"; }; /** The Ship's Chandler stands inside the chandler's shop on the Harbour Road (types harbour.ts `chandler`, door at 784,168), two tiles in from the door. */ export declare const CAPITAL_CHANDLER_AT: { readonly x: 786; readonly z: 170; }; /** The mini potions the apothecary keeps (a stat boost for a quarter of an hour; the full ones are for the brewer). PLACEHOLDER price. */ export declare const CAPITAL_MINI_POTION_KINDS: readonly string[]; export declare const CAPITAL_MINI_POTION_PRICE = 350; export declare const CAPITAL_SHOP_FOLK: ReadonlyArray; export declare function capitalShopFolkByName(name: string | undefined): CapitalShopFolk | null; /** Fixed tide snapper spots: three water tiles two north of the Royal Pier's boards, east of the royal-north ship's hull (x 830-846). */ export declare const CAPITAL_HARBOUR_FISH_SPOTS: ReadonlyArray<{ x: number; z: number; }>; export declare const CAPITAL_SHOP_QUEST_IDS: readonly ["catchForTheGalley"]; export type CapitalShopQuestId = (typeof CAPITAL_SHOP_QUEST_IDS)[number]; export declare const CATCH_FOR_GALLEY_FISHING = 14; export declare const CATCH_FOR_GALLEY_FISH = 5; export declare const CATCH_FOR_GALLEY_QUEST: StoryQuestDef; export declare const CAPITAL_SHOP_QUESTS: Readonly>; export declare const CAPITAL_SHOP_QUEST_META: Readonly>; export declare const CAPITAL_SHOP_QUEST_GIVER_PLACES: Readonly>; export declare const WALL_ALARM_NAME = "The Wall Alarm"; /** UTC hours in which the alarm may sound (the night watch's hours). */ export declare const WALL_ALARM_HOURS_UTC: readonly number[]; /** A slot is thirty minutes; the alarm sounds for the first ten of a night slot. */ export declare const WALL_ALARM_SLOT_MS: number; export declare const WALL_ALARM_LENGTH_MS: number; /** Where it happens: the north stretch of the ring road, inside the wall (the Wall Walk's north-west and north-east corner posts bound it). */ export declare const WALL_ALARM_AREA: { readonly minX: 489; readonly maxX: 751; readonly minZ: 85; readonly maxZ: 91; }; export declare function inWallAlarmArea(x: number, z: number): boolean; /** The prowlers: cutthroats (the Lost Seal's own thieves), scaled to whoever stands on the wall. */ export declare const WALL_ALARM_STREAM: { readonly kind: "cutthroat"; readonly name: "Wall prowler"; readonly levels: [number, number]; readonly cap: 3; readonly perExtraPlayer: 1; readonly everyMs: 10000; readonly firstWave: 2; /** Prowlers ignore anyone below this Combat. */ readonly aggroCombat: 10; readonly aggroRadius: 6; readonly leashRadius: 30; readonly aggroText: "A prowler drops over the parapet and comes at you!"; }; export declare const WALL_ALARM_DIFFICULTY = 1; /** Where they come over the wall: three points on the ring road's north side, clear of the corner posts (standable, checked by the backend smoke). */ export declare const WALL_ALARM_NESTS: ReadonlyArray<{ x: number; z: number; }>; /** Prowlers felled, in one alarm, that earn the watch's pay; paid when the window closes to those still standing. */ export declare const WALL_ALARM_KILLS_TO_PAY = 3; export declare const WALL_ALARM_REWARD: { readonly coins: 150; readonly explorerXp: 250; }; /** At most this many paid alarms per account per UTC day (kept in memory: a restart resets it). */ export declare const WALL_ALARM_PAID_PER_DAY = 6; export declare const WALL_ALARM_DIFFICULTY_NOTE = "placeholder numbers for the balance pass"; export declare const WALL_ALARM_TEXTS: { readonly start: "The alarm bell rings from the Great Gate: prowlers are coming over the north wall! Hold the ring road until the bell stops."; readonly quiet: "The alarm bell rings, but the prowlers have no interest in someone so green. Keep to the middle of the road."; readonly endPaid: "The bell stops and the watch clears the last prowlers. The Guard thanks you for standing your ground."; readonly endPlain: "The bell stops and the watch clears the last prowlers."; /** To a player on the wall just before a window opens. */ readonly warn: "The watch is mustering: the alarm bell will ring on the north wall within the minute."; }; export type WallAlarmWindow = { /** Which half hour this is (counted from the Unix epoch). */ slot: number; startMs: number; /** When the alarm ends (startMs + the length) if it sounds in this slot. */ endMs: number; /** True when the alarm is sounding at `nowMs`. */ active: boolean; /** The start of the next alarm at or after `nowMs` (this one's when it is sounding). */ nextStartMs: number; }; /** The alarm window at `nowMs`: read off the clock, never rolled or stored, so a restart or a second server agrees. */ export declare function wallAlarmWindow(nowMs: number): WallAlarmWindow; //# sourceMappingURL=capitalShops.d.ts.map