import type { StoryProgressMap, StoryQuestDef } from './storyQuests.js'; import type { QuestsSnapshot } from './quests.js'; import type { QuestCategory } from './quests.js'; /** The port ids of travel.ts (kept as literals here so this file imports nothing at load from it; a test pins them). */ export type VoyagePortId = 'hope-beach' | 'frozen-shore' | 'capital-harbour'; export declare const VOYAGE_PORT_IDS: readonly VoyagePortId[]; export declare const VOYAGE_LANDINGS: Readonly>; export declare const VOYAGE_PORT_LABELS: Readonly>; export declare const CRATE_FOR_THE_COAST_ID = "crateForTheCoast"; export declare const SALTMERE_RUN_ID = "saltmereRun"; export declare const NERVOUS_PASSENGER_ID = "nervousPassenger"; export declare const STORM_CROSSING_ID = "stormCrossing"; export declare const CAPTAINS_LAST_ENTRY_ID = "captainsLastEntry"; export declare const VOYAGE_QUEST_IDS: readonly ["crateForTheCoast", "saltmereRun", "nervousPassenger", "stormCrossing", "captainsLastEntry"]; export type VoyageQuestId = (typeof VOYAGE_QUEST_IDS)[number]; /** Combat levels the five ask (placeholders; the log runs 8-30). */ export declare const VOYAGE_COMBAT: { readonly crate: 8; readonly saltmere: 10; readonly passenger: 16; readonly storm: 22; readonly last: 28; }; /** The Storm Crossing's clock: the squall line crosses the bay this long after Branson gives you the glass. */ export declare const STORM_CROSSING_MS: number; export declare const STORM_CROSSING_WARN_AT_MS: readonly number[]; /** The passenger of The Nervous Passenger: the fright that makes them bolt (the third hit taken), and the lines. */ export declare const NERVOUS_PASSENGER_NAME = "Pim Sallow"; export declare const NERVOUS_PASSENGER_BOLTS_AT = 3; /** Corsair boarders the Captain's Last Entry wants repelled (the engine counts the boarders as the `cb-corsair` kind). */ export declare const CAPTAINS_LAST_BOARDERS = 6; export declare const CORSAIR_STORY_KIND = "cb-corsair"; /** Chart fares are this much cheaper for Branson's friend (the log done): a fifth. */ export declare const CAPTAINS_FRIEND_DISCOUNT = 0.2; export declare const CAPTAINS_FRIEND_PERK = "Captain's Friend: chart fares to Branson's Landing and the King's Harbour are a fifth cheaper"; export declare const VOYAGE_QUESTS: Record; /** The journal cards' words (quests.ts QUEST_META reads these through storyMeta). */ export declare const VOYAGE_QUEST_META: Record; /** * A voyage quest under way whose current step is a `reach` step ending at this port's landing waives the fare on that leg * (the log's legs are Branson's business). Derived from the quest data: a quest step added later needs no list. It only * waives the fare: the Battlefield Bridge lock is checked separately and never waived. */ export declare function voyageWaivesFare(portId: VoyagePortId, quests: QuestsSnapshot, story: StoryProgressMap): boolean; /** Branson's friend (the log done): a fifth off any fare, rounded to a whole coin; a free sailing stays free. */ export declare function captainsFriendFare(fare: number, quests: QuestsSnapshot): number; /** Slots of this length per port; a port is boarded in one slot in `CORSAIR_EVERY`, for the first `CORSAIR_RAID_MS` of it. */ export declare const CORSAIR_SLOT_MS: number; export declare const CORSAIR_RAID_MS: number; export declare const CORSAIR_EVERY = 4; /** Slot 0 of the clock (any fixed instant; a test pins it). */ export declare const CORSAIR_EPOCH_MS: number; /** Each port is boarded in a different slot of the four, so exactly one slot in four has no boarding anywhere. */ export declare const CORSAIR_PORT_OFFSET: Readonly>; /** The boarders: Blackwake deckhands in looks (the nearest pirate the game has), scaled to whoever stands on the quay. */ export declare const CORSAIR_STREAM: { readonly kind: "blackwakedeckhand"; readonly name: "Corsair boarder"; readonly levels: [number, number]; /** Alive at once with one player on the quay, plus `perExtraPlayer` for each more (twice `cap` at most). */ readonly cap: 3; readonly perExtraPlayer: 1; readonly everyMs: 9000; readonly firstWave: 2; /** Boarders ignore anyone below this Combat (a newcomer on the pier is left alone). */ readonly aggroCombat: 8; readonly aggroRadius: 7; readonly leashRadius: 30; readonly aggroText: "A corsair leaps from the grappled sloop and comes at you!"; }; /** The quay's ground the boarders hold and the players fight on: a box of this reach round the landing. */ export declare const CORSAIR_ARENA_RADIUS = 11; /** Boarders felled in one boarding, and still standing when it ends, that earn the quay's thanks (once per boarding per player). */ export declare const CORSAIR_KILLS_TO_PAY = 3; export declare const CORSAIR_REWARD: { readonly coins: 100; readonly explorerXp: 150; }; export declare const CORSAIR_DIFFICULTY = 1; export declare const CORSAIR_TEXTS: { readonly start: (port: string) => string; readonly quiet: (port: string) => string; readonly endPaid: "The sloop casts off and the quay falls quiet. The harbour thanks you for standing your ground."; readonly endPlain: "The sloop casts off and the quay falls quiet."; readonly hurt: (n: number) => string; }; export type CorsairWindow = { /** The slot this instant falls in (counted from CORSAIR_EPOCH_MS). */ slot: number; slotStartMs: number; /** When the boarding of this slot ends (slotStartMs + CORSAIR_RAID_MS); only meaningful while `slotRaided`. */ raidEndMs: number; /** True when this port is boarded in this slot at all. */ slotRaided: boolean; /** True while the grappled sloop is alongside: the slot is raided and the first half is still running. */ raided: boolean; }; /** Whether a port is under boarding at `nowMs`, read off the wall clock. */ export declare function corsairWindow(nowMs: number, portId: VoyagePortId): CorsairWindow; /** Is this tile on the quay of this port (the arena of its boarding)? */ export declare function inCorsairArena(portId: VoyagePortId, x: number, z: number): boolean; /** The port whose quay holds this tile, or null. */ export declare function corsairPortAt(x: number, z: number): VoyagePortId | null; /** "The Long Pier is boarded now (2 minutes left)" or "next boarding at the Landing in 5 minutes": one line for /corsairs and the masters. */ export declare function corsairDescribe(nowMs: number): string; /** Contracts a character may finish in a day (three; the fourth is the members' extra, like the Deep Sea). */ export declare const SHIPPING_DAILY_CAP = 3; export declare const SHIPPING_MEMBER_EXTRA = 1; /** A contract is on the board in a band of Combat; the board shows this many at a port. */ export declare const SHIPPING_BOARD_SIZE = 3; export type ShippingContract = { id: string; label: string; /** The goods the destination master takes (no shop sells any of them: a test pins that, so there is no buy-and-deliver loop). */ cargo: { kind: string; qty: number; label: string; }; to: VoyagePortId; minCombat: number; maxCombat: number; coins: number; explorerXp: number; /** Held when the contract is taken and paid back with the delivery; lost if the contract lapses or is abandoned (a coin sink). */ bond: number; }; /** * The pool. Cargo values (what any trader pays) and the coins here follow `coins ~= 1.5 x value + 50` (a hauling premium; the * backend smoke `voyages-smoke.ts` checks every row against the live counters). */ export declare const SHIPPING_CONTRACTS: readonly ShippingContract[]; export declare function shippingContractById(id: string): ShippingContract | null; /** The day a moment falls in (UTC); the same count as dailyHooks.ts dailyDay, duplicated so this file imports nothing from it. */ export declare function shippingDay(nowMs: number): number; /** Ports a character may take freight to: Hope Beach always, the others once the Battlefield Bridge is mended (the chart's own lock). */ export declare function shippingOpenPorts(quests: QuestsSnapshot): VoyagePortId[]; /** * Today's contracts at this port for this character: the pool filtered to the character's Combat band and to destinations * that are open to them and are not this port, three of them picked by the day and the port (a member sees one more). * Pure: the server and the client agree, and the same day gives the same board. Empty when nothing is open. */ export declare function shippingBoard(input: { here: VoyagePortId; combat: number; day: number; member: boolean; quests: QuestsSnapshot; }): ShippingContract[]; /** What the character keeps about the board: saved with them, so a logout or a restart changes nothing. */ export type ShippingState = { /** The UTC day `done` counts. */ day: number; /** Contracts delivered on `day`. */ done: number; /** The contract id under way ('' = none), the day it was taken (it lapses at the next midnight) and the bond held for it. */ active: string; activeDay: number; bond: number; }; export declare const EMPTY_SHIPPING: ShippingState; export declare function normalizeShippingState(raw: unknown): ShippingState; /** Contracts the character may still finish today. */ export declare function shippingLeftToday(state: ShippingState, day: number, member: boolean): number; /** The contract under way, or null (a lapsed one is returned too, with `lapsed` true: its day is over). */ export declare function shippingActive(state: ShippingState, day: number): { contract: ShippingContract; lapsed: boolean; } | null; /** A loaded freight contract waives the fare to its port: the active contract is going there, in time, and the bag holds the cargo. */ export declare function freightWaivesFare(portId: VoyagePortId, state: ShippingState, day: number, held: (kind: string) => number): boolean; /** The shipping board's dialog actions (the three travel masters' menus send these). */ export declare const SHIPPING_ACTION_PREFIX = "ship:"; export declare const SHIPPING_TAKE_PREFIX = "ship:take:"; export declare const SHIPPING_DELIVER_ACTION = "ship:deliver"; export declare const SHIPPING_ABANDON_ACTION = "ship:abandon"; export declare const SHIPPING_BOARD_ACTION = "ship:board"; export declare function shippingTakeAction(id: string): string; export declare function shippingTakeId(action: string): string | null; /** One board row in words ("Cooked crab x12 to Branson's Landing: 195 coins, bond 35"). */ export declare function shippingContractLine(c: ShippingContract): string; export type ShippingViewRow = { /** 1-based place on today's board: the number `shippingTakeAction` takes. */ n: number; id: string; label: string; cargoLabel: string; qty: number; to: VoyagePortId; toLabel: string; coins: number; bond: number; explorerXp: number; /** The bag holds the bond right now. */ canAfford: boolean; }; export type ShippingViewFreight = { id: string; label: string; cargoLabel: string; qty: number; held: number; to: VoyagePortId; toLabel: string; coins: number; bond: number; /** The contract's day is over (it lapsed at midnight; the bond is gone and "give up" clears it). */ lapsed: boolean; /** This is the destination master: the goods can be signed for here. */ here: boolean; /** Here, in time, and the bag holds the whole cargo. */ ready: boolean; }; export type ShippingView = { port: VoyagePortId; portLabel: string; day: number; member: boolean; /** Contracts a character may finish today, and how many are left. */ cap: number; left: number; /** 'board': rows to take; 'bridge': the other ports are shut until the Battlefield Bridge is mended; 'none': nothing for this Combat today. */ state: 'board' | 'bridge' | 'none'; rows: ShippingViewRow[]; /** The contract under way, or null: the panel's "no cargo" state. */ freight: ShippingViewFreight | null; }; /** The panel's model for one master: today's board here, the freight under way, what is left today. Pure. */ export declare function shippingView(input: { here: VoyagePortId; combat: number; day: number; member: boolean; quests: QuestsSnapshot; state: ShippingState; held: (kind: string) => number; coins: number; }): ShippingView; export declare const VOYAGE_MARKS: { readonly boardingPier: "voyage:boarding-pier"; readonly boardingLanding: "voyage:boarding-landing"; readonly boardingHarbour: "voyage:boarding-harbour"; readonly contract: "voyage:contract"; readonly passenger: "voyage:passenger"; readonly storm: "voyage:storm"; }; export declare const LEDGER_VOYAGE_LINES: readonly { id: string; label: string; }[]; /** The ledger mark a boarding at this port writes. */ export declare function corsairLedgerMark(portId: VoyagePortId): string; //# sourceMappingURL=voyages.d.ts.map