/** * STORY QUESTS (James, 2026-09-26): the quests after the first dozen are data, * not hand-written handlers. A quest is a giver, an optional gate ("I don't * trust strangers" until you have helped Anne), what the giver hands you when * you accept, and a list of steps; the backend's storyQuests.ts runs every * one of them the same way, and the client draws the journal card from the * same list. Adding a quest is one entry in STORY_QUESTS plus whatever NPCs * and props it needs in the world. * * The design sheets are in the backend's design-references, one per quest * (`quest-fredsletter`, `quest-wilsonbigcatch`, ...). * * Rewards are deliberately large next to the first quests: Explorer has no * repeatable source beyond discoveries (33 XP), so quests are how it levels. * A `choiceXp` reward is a lump the player puts into any skill they pick, * from a picker that stays open (and is saved) until they choose. */ import { type SkillQuestId } from './skillQuests.js'; import { type LongWinterQuestId } from './longWinter.js'; import { type HoldHubQuestId } from './dwarfHoldHub.js'; import { type DelversLadderId } from './delversLadder.js'; import { type MiningQuestId } from './miningQuests.js'; import { type SnowForagingId } from './snowForaging.js'; import { type BrewersQuestId } from './campBrewing.js'; import { type LongRoadBrewId } from './longRoadBrewing.js'; import { type NobleIntrigueId } from './nobleIntrigue.js'; import { type CloisterRoundId } from './cloisterRound.js'; import { type ThawFishingId } from './thawFishing.js'; import { type RoadTableId } from './longRoadTable.js'; import { type TimberErrandId } from './timberErrands.js'; import { type WarCampQuestId } from './warCampDrill.js'; import { type MarksmenQuestId } from './marksmenRange.js'; import { type WardensWritId } from './wardensBounty.js'; import { type EarlyWritId } from './earlyWrits.js'; import { type BorderJobId } from './borderJobs.js'; import { type WoodsJobId } from './woodsBelts.js'; import { type QuarryQuestId } from './northQuarryQuest.js'; import { type HopeBrewId } from './hopeBrewing.js'; import { type EarlyBrewId } from './earlyBrewing.js'; import { type ProspectingId } from './prospecting.js'; import { type HeartwoodQuestId } from './heartwoodQuests.js'; import { type IronjawWatchQuestId } from './ironjawWatchQuests.js'; import { type CapitalQuestId } from './capitalQuests.js'; import { type CapitalShopQuestId } from './capitalShops.js'; import { type VoyageQuestId } from './voyages.js'; import { type FishCookQuestId } from './fishCookQuests.js'; import { type ReachQuestId } from './reachQuests.js'; import { type MammothTableId } from './mammothTable.js'; import { type BayPetQuestId } from './bayPets.js'; import type { StoryWindow } from './storyWindows.js'; /** The skills a reward can pay into, keyed as the stats are (`precision` is shown as Mastery). */ export type StorySkill = 'strength' | 'archery' | 'precision' | 'fishing' | 'cooking' | 'foraging' | 'woodwork' | 'mining' | 'blacksmithing' | 'potionmaking' | 'explorer'; export declare const STORY_SKILLS: readonly StorySkill[]; export declare const STORY_COMBAT_SKILLS: readonly StorySkill[]; export declare const STORY_SKILL_NAMES: Record; export declare function isStorySkill(value: unknown): value is StorySkill; /** * Who a step talks to. `id` picks one NPC out of a kind (the Capital's Rimdel, not the prisoner). A `resident` is told * apart by its name (the South Fields' Hettie, Nye and Wren are residents): see npcMatches. */ export type StoryNpcRef = { kind: string; id?: string; name: string; }; /** The kind whose people a story quest knows by name, not by kind (every villager is a `resident`). */ export declare const NAMED_STORY_NPC_KIND = "resident"; /** Any one of `kinds` counts: "a cooked fish" is several items. */ export type StoryItemNeed = { kinds: readonly string[]; qty: number; label: string; }; export type StoryReward = { coins?: number; xp?: Partial>; /** XP the player puts into one skill of their choice, from `skills` (every skill when absent). */ choiceXp?: { qty: number; skills?: readonly StorySkill[]; }; items?: readonly { kind: string; qty: number; }[]; /** A lasting perk, shown on the card as a line of its own (Fred's Pass). */ perk?: string; }; type StepBase = { /** The line on the journal card and the tracker. */ label: string; /** What the quest helper says under the arrow. */ hint: string; /** * Where the helper points from the surface when what the step counts is * underground (a cave's mouth): the arrow cannot lead to a place the paper * map does not hold. Underground the helper stands down anyway. */ place?: { x: number; z: number; label: string; }; }; /** * One step. `talk` and `deliver` finish when the player speaks to the NPC * (holding the items, for a delivery, which are taken); `kill` counts the * player's own kills; `catch` counts fish landed; `touch` counts distinct * quest props clicked (`questprop` entities whose style starts with `prop`); * `shoot` counts distinct archery targets drilled (one beat of the training drill at each); * `gather` counts things picked from the world (a herb patch); `reach` is done * the moment the player stands in its area; `brew` counts * potions brewed at a cauldron, one of each kind listed; * `choose` offers the NPC's options, and each can pay its own reward and end * the quest early. */ export type StoryStep = (StepBase & { kind: 'talk'; npc: StoryNpcRef; say: string; /** * The NPC finishes this step only once the player's Explorer's Ledger holds every one of `marks` (the Capital sparring yard's * `yard:sergeant-mott`, written when a bout is won); until then they say `short` and nothing moves (skillQuests.ts). */ ledger?: { marks: readonly string[]; short: string; }; }) | (StepBase & { /** * Win every bout in `marks` (Explorer's Ledger marks, the Capital sparring yard's `yard:sergeant-mott`, written when a bout is won). * Counts by itself the moment the last mark is held (marks won before the quest count too); the marks done go in `touched`. */ kind: 'bout'; marks: readonly string[]; /** What the count chip calls them ("Bout"). */ boutLabel: string; /** Where the helper points when no sergeant is in reach of the map: the yard. */ at: { x: number; z: number; label: string; }; }) | (StepBase & { kind: 'deliver'; npc: StoryNpcRef; items: readonly StoryItemNeed[]; say: string; short: string; /** The NPC takes the goods only from a player this skilled (Five Arches: the trestles want Woodwork); `short` is said otherwise. */ skill?: { skill: StorySkill; level: number; }; /** Something the world does on the hand-in, named for the host (Five Arches: `span-stage-1` raises the bridge). */ effect?: string; }) | (StepBase & { kind: 'kill'; npcKinds: readonly string[]; qty: number; npcLabel: string; /** Only kills of NPCs standing inside count (Port Blackwake's Crooked Gull). */ inArea?: { minX: number; maxX: number; minZ: number; maxZ: number; }; }) | (StepBase & { kind: 'catch'; fish: readonly string[]; qty: number; /** Handed over with the last catch, e.g. Wilson's big trout. */ give?: { kind: string; qty: number; notice: string; }; }) | (StepBase & { kind: 'touch'; prop: string; qty: number; /** Said by the player on each new prop, keyed by the prop's full style. */ notices: Readonly>; /** Handed over with each new prop. */ give?: { kind: string; qty: number; }; /** * Handed over by one prop only, keyed by the prop's full style (The First Beacon: the rope crate gives the rope, the * oil crate the oil). Found again at that prop while a later step still wants it, as `give` is. */ gives?: Readonly>; /** Handed over with it but never found again (a tool the giver also sells: Corvin's pestle and mortar). */ alsoGive?: readonly { kind: string; qty: number; }[]; /** * What the click needs from the bag, and takes (The First Beacon: the rope to mend the winch). Without it the prop is * not counted and the player hears `short` and what is still missing. */ takes?: readonly StoryItemNeed[]; /** Said when `takes` is not all in the bag. */ short?: string; /** * An ordered touch (The Cracked Bell's bell ropes): the props' full styles in the order they must be touched. A prop out of order * is not counted, the count and the touched list start over and `wrong` is said and its effect done; the last in order finishes * the step. `qty` is the length of the order. */ order?: readonly string[]; wrong?: { notice: string; effect?: string; }; /** * Only counts in this window of the wall clock (storyWindows.ts): `low-tide` (the Sea Grotto's tide, gullsLowWater.ts; outside it * an `order` step starts again), `night` (Saltmark Light's lamp hours, 18:00 to 06:00 UTC), or the Blood Mire's `blood-low`, * `blood-moon` and `red-low` (tideOfBlood.ts). Outside it `wait` is said and nothing is taken or given. */ when?: StoryWindow; /** Said outside the `when` window. */ wait?: string; }) | (StepBase & { /** * Drill `qty` distinct archery targets out of `targets` (yardprop ids; The First Beacon: the Beacon Gallery's lanterns), * each counted on the training drill's first beat at it, capped at the drill's level or not. The ids done go in `touched`. */ kind: 'shoot'; targets: readonly string[]; qty: number; /** What the count chip calls them ("Lantern"). */ targetLabel: string; /** `notices[n]` is said on the nth target. */ notices: readonly string[]; /** Where the helper points when no target is in reach of the map. */ at: { x: number; z: number; label: string; }; }) | (StepBase & { /** Counts dishes cooked at a fire or range, any of `dishes` (First Steps: frog legs or cooked crab). */ kind: 'cook'; dishes: readonly string[]; qty: number; }) | (StepBase & { kind: 'gather'; /** Any of these picked counts. */ items: readonly string[]; qty: number; /** Where the helper points (a farm, a cave mouth): gathering has no one entity to aim at. */ at?: { x: number; z: number; label: string; }; }) | (StepBase & { kind: 'reach'; /** * The ground that counts as arriving, world tiles, inclusive. Speaking to * the next step's person counts too, so a player who walks straight up to * them along the box's edge is never stuck. */ area: { minX: number; maxX: number; minZ: number; maxZ: number; }; /** Where the helper points: an area has no one entity to aim at. */ at: { x: number; z: number; label: string; }; }) | (StepBase & { kind: 'brew'; /** One of each, in any order (`touched` holds the kinds already brewed). */ potions: readonly string[]; /** Where the helper points: this cauldron (Herbal Remedies: the porters' cauldron), not the nearest. Any cauldron brews it. */ cauldron?: string; }) | (StepBase & { /** * Hand an animal something from the bag, `qty` times (Hog Wild: a rotten turnip to a wild warthog, through its * Feed option). `notices[n]` is said on the nth. With `tame`, the last one makes the animal the player's pet, * following them from where it stood. */ kind: 'feed'; npcKinds: readonly string[]; /** Only the animal with this name counts (The Lost Goat: Clover, not the fair's pen goat). */ npcName?: string; item: string; qty: number; npcLabel: string; notices: readonly string[]; tame?: 'warthog'; }) | (StepBase & { /** * Walk your pet to a place: done when it and you are both within `to.radius` tiles of it. A `sheep` is a stray * ewe you led off from where it grazed (Nye's Strays, the backend's southFieldsQuests.ts), not a pet you keep. */ kind: 'lead'; /** `goat` is Bren's Clover (The Lost Goat, the backend's hopewoodQuests.ts), led as the ewes are. */ pet: 'warthog' | 'sheep' | 'goat'; to: { x: number; z: number; radius: number; label: string; }; /** Said as it gets there. */ notice: string; }) | (StepBase & { /** Do something to your own pet from its menu (Hog Wild: rub its belly). */ kind: 'pet'; pet: 'warthog'; action: 'rub'; notice: string; }) | (StepBase & { kind: 'choose'; npc: StoryNpcRef; say: string; options: readonly { id: string; label: string; say: string; /** Paid on top of the quest's own reward. */ bonus?: StoryReward; /** Finish the quest straight away instead of going on to the next step. */ finish?: boolean; }[]; }); export type StoryQuestDef = { giver: StoryNpcRef; /** * The giver has an older quest of their own (Forbes, Wilson). Until this * quest's gate quest is done they answer as they always have, rather than * with this quest's refusal. */ sharedGiver?: boolean; /** Until this is met the giver will not offer the quest and says `refuse`. */ requires?: { quest?: string; /** * A Combat level the player must have (a quest that sends you to a 41+ fight asks for GATE_PLACEHOLDER_41, the * build-focus rule: the Ice-Cutter's Key, decision D10 2026-10-12). Checked with the skills. */ combat?: number; skill?: { skill: StorySkill; level: number; }; /** More than one skill to reach (Bob's brew wants Foraging and Potion Making). */ skills?: readonly { skill: StorySkill; level: number; }[]; refuse: string; /** * A bonus quest (skillQuests.ts): until its gate opens the giver says nothing of it, so the giver's other lines (an `after`, * an older quest's refusal) are unchanged for players who do not meet it yet. `refuse` stays for the journal and guide. */ silent?: boolean; /** * A members' quest: what the giver says to a player who is not a member * (admins count as members, as they do at Pell's Gap). Checked after the * quest and skill gates, so a free player hears the older quest first. */ member?: string; }; /** What the giver says when they offer it (the card's giver line). */ offer: string; accept: string; decline: string; /** Handed over on accept. `ifMissing`: only to a player whose bag holds none (Nye's spare shears). */ onAccept?: readonly { kind: string; qty: number; ifMissing?: boolean; }[]; /** * The props this quest's touch steps dealt with stay dealt with once it is done (a mended fence stays mended for the * player who mended it). Without it the list goes with the quest and the props show as they were. */ keepTouched?: boolean; /** * Items the quest cannot go on without. Lose one before the step that * uses it and the giver hands you another. */ keep?: readonly { kind: string; untilStep: number; say: string; }[]; /** * A timed quest (Ride the Line's Night Mail): the clock starts when the quest is accepted and runs on while the player is * logged out. At `warnAtMs` left (largest first) `warn` is said, with `{left}` ("4 minutes") and `{next}` (the step's label) * filled in; at nothing left the run is lost: progress and state go back to the start, `fail` is said, and the giver offers it again. */ clock?: { durationMs: number; warnAtMs: readonly number[]; warn: string; fail: string; }; /** * A passenger who must not be hurt (voyages.ts The Nervous Passenger): from step `fromStep` to step `toStep` (inclusive) every hit the * player takes frightens them (`hurt`, with `{n}` and `{max}` filled in); at the `boltsAt`th fright the passenger bolts, `fail` is * said and the run starts again at `restartStep`. The count is saved with the progress (`touched`: one `hurt:` mark per fright), so a * logout or a restart does not forgive it. */ passenger?: { name: string; fromStep: number; toStep: number; restartStep: number; boltsAt: number; hurt: string; fail: string; }; steps: readonly StoryStep[]; /** The giver's closing line, with the reward. */ done: string; /** What the giver says ever after. */ after: string; rewards: StoryReward; }; export type StoryQuestId = 'fredsLetter' | 'beagleBirthday' | 'wilsonBigCatch' | 'smithsApprentice' | 'spiderHollowEggs' | 'harbourThief' | 'coldFeet' | 'livoniasDiary' | 'charcoalBurner' | 'iceCuttersKey' | 'hopeWreck' | 'firstSteps' | 'trappersLine' | 'gristForTheMill' | 'shearingDay' | 'dryBarrels' | 'freshLinen' | 'troubleOnTheRoad' | 'everyRoadPays' | 'maribelsLog' | 'mammothRoad' | 'marigoldsStrongbox' | 'tansysCauldron' | 'poulticesForTheLine' | 'frostbiteSalve' | 'cellsBelow' | 'breakingTheIronjaw' | 'floeWatch' | 'samsSecretBait' | 'travellersTonic' | 'bountyHuntersBrew' | 'corvinsRecipes' | 'hogWild' | 'fiveArches' | 'theNewGate' | 'hettiesSails' | 'geeseInTheWheat' | 'nyesStrays' | 'nyesPup' | 'missingShipment' | 'wrensHoney' | 'harvestSupper' | 'goatLookout' | 'jettyPot' | 'theLostGoat' | 'theScarecrowsHat' | 'theHatchetHandle' | 'stonesThatWhisper' | 'crowTrouble' | 'tamsinsLostBasket' | 'theLeakingSluice' | 'haresInTheBeans' | 'whatWokeOldGnasher' | 'theMissingMule' | 'theFallenLimb' | 'troubleOnTheSnareLine' | 'oldTusk' | 'shinyTrouble' | 'nestOfThieves' | 'matterOfWeight' | 'ledgerInTheDust' | 'brokenSignal' | 'flagsAgainstTheWind' | 'bellForTheBeacon' | 'shellGame' | 'brokenExtraction' | 'underTheWhiteStone' | 'silentBells' | 'webInTheReeds' | 'brokenTrestle' | 'matriarchOfTheMere' | 'peatAndSnapper' | 'theBlueDoor' | 'lanternsOfTheRing' | 'theMissingFolios' | 'theRuneboundWarden' | 'lightAtGullhook' | 'lostOnTheTide' | 'salvageRights' | 'theBeaconStair' | 'theLampSnuffer' | 'theColdSignal' | 'gunsOfTheWindbreak' | 'salvageAtTheCleft' | 'theWinchLine' | 'theDarkKeeper' | 'passRoadMarks' | 'chocksForTheSpur' | 'goldForTheGantry' | 'eyesOnTheDens' | 'theRailEater' | 'chartingTheVents' | 'slagAndSilver' | 'lostInTheAsh' | 'scoutingTheBasin' | 'theAshmaw' | 'markingTheLanes' | 'pennantIrons' | 'theLiftCrewsPacks' | 'readingTheRing' | 'oldThunderhorn' | 'theOrderOfStones' | 'theSerpentsMouth' | 'oldBasaltback' | 'readingTheTide' | 'weightsForTheNets' | 'halesLamp' | 'countingGannets' | 'oldSkerrywing' | 'lamplightersErrand' | 'theWholeCommon' | 'mothsOnTheMeadow' | 'theWardensWalk' | 'oldDimwing' | 'readTheTally' | 'lightTheChain' | 'eyesOnThePass' | 'gateHinges' | 'theHollowWatchman' | 'freshSign' | 'spruceAndAsh' | 'aHoundGoneAstray' | 'snaresInTheDark' | 'theRangersTrial' | 'theFirstDrove' | 'fleeceAndFang' | 'saltForThePot' | 'theRustlersCut' | 'greybackOfTheDowns' | 'learnersLap' | 'theHeathDash' | 'oldGorsetusk' | 'saltOnTheWind' | 'theLostNets' | 'theBeaconsLastOil' | 'fuelForTheKilns' | 'theWashingPools' | 'raidersOnTheRim' | 'cracksInTheCut' | 'ironForTheHoists' | 'theMarkerCairns' | 'theNorthLedge' | 'reedsForTheRoofs' | 'theFerryErrand' | 'marshFish' | 'oldGreyneck' | 'wreckSalvage' | 'deadMensDig' | 'theFiveBells' | 'skullIsleHunt' | 'reevesNotices' | 'strawAndSteel' | 'supperForTheMuster' | 'aSmithsOrder' | 'planksForTheHall' | 'theNightWatch' | 'marketDayRush' | 'theCaravanRun' | 'surveyorsLine' | 'anchorsInTheIce' | 'acrossTheThaw' | 'theWraithOfTheFall' | 'theStuckWheel' | 'boarsInTheBeans' | 'wennasTonic' | 'aDozenLoaves' | 'theLostCart' | 'theMissingTollMoney' | 'lightTheBeacon' | 'birdsInTheHops' | 'grandfatherGull' | 'lostSupplies' | 'herbalRemedies' | 'fieldShrineMystery' | 'theFirstBeacon' | 'troubleAtCrossing' | 'gullsMap' | 'gullsLowWater' | 'readingTheRed' | 'theLowFord' | 'nightOfTheRedMoon' | 'theSurge' | 'tideOfBlood' | 'gullsFortRook' | 'theCrookedGull' | 'theGuardedJetty' | 'clearingTheAnchorage' | 'theCaptainsStash' | 'theDampNote' | 'thePaleRibs' | 'feathersOnTheCliff' | 'theTideBoard' | 'theTideBroker' | 'gatewardenRounds' | 'strongerBridge' | 'raidersOfTheRedWaste' | 'greenwardensGlade' | 'clearTheLine' | 'ticketsPlease' | 'coalForTheLine' | 'nightMail' | 'emberSeals' | 'cinderAndAsh' | 'crackedBell' | 'crowsOnTheRope' | 'lampsForTheChapel' | 'wardensKey' | 'sextonsLantern' | 'namesOnTheStones' | 'threeBraziers' | 'theTombWarden' | 'sealTheCrypt' | 'tollsAndTallies' | 'theMissingPayroll' | 'whisperInTheReeds' | 'theCaptainsCellar' | 'readingTheEbb' | 'theCrabWarren' | 'theReevesCache' | 'eyesOnTheFarBank' | 'suppliesForTheLine' | 'sappersSpan' | 'holdTheLine' | 'warchiefsHold' | SkillQuestId | LongWinterQuestId | HeartwoodQuestId | IronjawWatchQuestId | DelversLadderId | MiningQuestId | SnowForagingId | BrewersQuestId | LongRoadBrewId | NobleIntrigueId | CloisterRoundId | ThawFishingId | RoadTableId | TimberErrandId | MarksmenQuestId | WarCampQuestId | WardensWritId | EarlyWritId | BorderJobId | WoodsJobId | QuarryQuestId | HopeBrewId | EarlyBrewId | ProspectingId | CapitalQuestId | CapitalShopQuestId | HoldHubQuestId | VoyageQuestId | FishCookQuestId | ReachQuestId | MammothTableId | BayPetQuestId; export declare const STORY_QUEST_IDS: readonly StoryQuestId[]; /** The npc_action id for a story choice. */ export declare const STORY_CHOICE_PREFIX = "story:"; export declare function storyChoiceAction(quest: StoryQuestId, option: string): string; export declare function parseStoryChoiceAction(action: string): { quest: StoryQuestId; option: string; } | null; export declare function isStoryQuestId(value: unknown): value is StoryQuestId; /** Where a player has got to in one story quest. */ export type StoryProgress = { step: number; /** Kills, catches or props for a counting step. */ count: number; /** The props already clicked on a `touch` step, so one prop is not five. */ touched?: string[]; /** A timed quest's (StoryQuestDef `clock`) deadline, epoch ms: wall-clock, so a logout does not stop it. */ endsAtMs?: number; }; export type StoryProgressMap = Partial>; /** An XP lump waiting for the player to pick its skill. Saved, so closing the picker loses nothing. */ export type PendingXpChoice = { quest: string; qty: number; skills: StorySkill[]; }; export declare const FREDS_LETTER_KIND = "fredsletter"; export declare const BOAT_TICKET_KIND = "boatticket"; export declare const TROPHY_TROUT_KIND = "trophytrout"; export declare const LIVONIA_PAGE_KIND = "livoniapage"; /** A cargo crate off the wreck on Hope Beach, for Old Pell. */ export declare const SALVAGE_CRATE_KIND = "salvagecrate"; /** First Steps of Hope Beach's food: a small travelling ration that heals a little (cooking.ts FOOD_INFO). */ export declare const RATION_KIND = "ration"; export declare const STORY_ITEM_KINDS: readonly string[]; /** The reward items (Blender models, armour-workshop quest_*): worn, or Haldren's tool. */ export declare const FUR_HAT_KIND = "furhat"; export declare const LIVONIAS_RING_KIND = "livoniasring"; export declare const BURNERS_GLOVES_KIND = "burnersgloves"; /** A smith's hammer that never breaks (the anvil takes it as the Blacksmithing Hammer). */ export declare const BRONZE_HAMMER_KIND = "bronzehammer"; export declare const STORY_REWARD_ITEM_KINDS: readonly string[]; /** The Blender model a quest prop draws with (CAPITAL_BUILDING_MODELS), from its style's prop. */ export declare function questPropModel(style: string | undefined): string; /** * The starter props a player clicks (`questprop` entities, style `:1`). Each does its own thing whether or * not First Steps is under way (the backend's starterHub.ts): the crate hands back a saw, the sawbench cuts a birch * log, the rack a net and a rod, the boards say what to do next and what the pond gives. */ export declare const STARTER_PROP: { readonly crate: "losttools"; readonly sawbench: "sawbench"; readonly board: "starterboard"; readonly rodrack: "rodrack"; readonly catchboard: "catchboard"; }; /** The world entity a `touch` step counts. Its style is `:`, e.g. `spideregg:3`. */ export declare const QUEST_PROP_KIND = "questprop"; export declare const FRED: StoryNpcRef; /** Rimdel after his escape: a clerk at the Trade Hall. The prisoner keeps the id `rimdel`. */ export declare const CAPITAL_RIMDEL_ID = "rimdel-capital"; export declare const CAPITAL_RIMDEL: StoryNpcRef; export declare const FORBES: StoryNpcRef; export declare const WILSON: StoryNpcRef; export declare const HALDREN: StoryNpcRef; export declare const TOBIN: StoryNpcRef; export declare const MARLOW: StoryNpcRef; /** Wears the Castle Guard's steel, but is his own kind: a guard is attackable, and a click on Crane must talk. */ export declare const CRANE: StoryNpcRef; export declare const EXPLORER: StoryNpcRef; export declare const SCHOLAR: StoryNpcRef; export declare const BURNER: StoryNpcRef; export declare const ULF: StoryNpcRef; /** The beachcomber who sits by the wreck on Hope Beach, east of the Long Pier. */ export declare const PELL: StoryNpcRef; /** Meets newcomers by the starter notice board, at her workshop east of Hope Town square (storyPlaces.ts STARTER_HUB). */ export declare const ROWAN: StoryNpcRef; /** Old Tom at Henson Pond, who teaches beginner fishing (backend oldTomsCamp.ts); his own words stay his. */ export declare const OLD_TOM: StoryNpcRef; /** The trapper in his log cabin out on the snowfields (snowfields.ts). */ export declare const TRAPPER: StoryNpcRef; export declare const MILLER: StoryNpcRef; export declare const SHEPHERD: StoryNpcRef; export declare const INNKEEPER: StoryNpcRef; /** Every Road Pays (highwaymansRidge.ts): the Calverton guard's sergeant at the Ridge's gate track, and the robbed carter. */ export declare const MABRY: StoryNpcRef; export declare const NELL_CARTER: StoryNpcRef; /** Calverton's apothecary, reopening the shuttered potion shop on the square (potionMaking.ts). */ export declare const TANSY: StoryNpcRef; /** Older people with a herb-site quest (Potion Making phase 1c): their own menus stay, the quest joins them. */ export declare const CAPTAIN: StoryNpcRef; export declare const QUARTERMASTER: StoryNpcRef; export declare const SAM: StoryNpcRef; export declare const BOB: StoryNpcRef; /** Hog Wild (hogWild.ts): the farmer east of Calverton whose turnips the warthogs eat. */ export declare const BRAMBLE: StoryNpcRef; export declare const OLD_HOGGER: StoryNpcRef; /** Five Arches: the King's last bridge keeper, at the bridgehead camp south of Base Camp (southExpansion.ts SUNDERED_SPAN.osmundSpot). */ export declare const BRIDGEWARDEN: StoryNpcRef; /** No Harm Farm's farmer (his son gives Clark's Chores), and the South Fields' people, residents known by name. */ export declare const CLARK: StoryNpcRef; export declare const HETTIE: StoryNpcRef; export declare const NYE: StoryNpcRef; export declare const WREN: StoryNpcRef; /** Hopewood Common's people (fairFolk.ts), residents known by name like the South Fields' three. */ export declare const BREN: StoryNpcRef; export declare const LIA: StoryNpcRef; export declare const TAMS: StoryNpcRef; export declare const HETH: StoryNpcRef; export declare const NELL: StoryNpcRef; /** Hollin Brook's miller, fisher and tinker (fairFolk.ts), residents known by name. */ export declare const HOBB: StoryNpcRef; export declare const TAMSIN: StoryNpcRef; export declare const JORY: StoryNpcRef; /** Hopewood Copse's people (fairFolk.ts), residents known by name. */ export declare const TARN: StoryNpcRef; export declare const BRAM: StoryNpcRef; export declare const NELL_QUICKFOOT: StoryNpcRef; export declare const HESTIA: StoryNpcRef; export declare const MALLIN: StoryNpcRef; export declare const GARRICK: StoryNpcRef; /** The Marches Edge's people (fairFolk.ts), residents known by name. */ export declare const OSRIC: StoryNpcRef; export declare const DUNSTAN: StoryNpcRef; export declare const HETTIE_HOPWOOD: StoryNpcRef; export declare const MARROW: StoryNpcRef; export declare const PRU: StoryNpcRef; export declare const MOLL: StoryNpcRef; /** The Western Entrance station hub's porter and station master (westernEntrance.ts WESTERN_STATION_FOLK). */ export declare const DUNNA: StoryNpcRef; export declare const HAMRIK: StoryNpcRef; /** Beacon Keeper Hale on Lantern Wake's Beacon Gallery (lanternWakeGallery.ts), the only one of his kind. */ export declare const HALE: StoryNpcRef; /** Every kind a story quest adds to the world, for the NpcKind union and the name table. */ export declare const STORY_NPC_NAMES: Readonly>; export declare const STORY_QUESTS: Record; /** Every skill level a quest's gate asks for (`requires.skill` and `requires.skills` together). */ export declare function storySkillGates(def: StoryQuestDef): { skill: StorySkill; level: number; }[]; /** * True when the gate's quest and skills are met (the member gate aside): the giver would offer it now. * `levels` is keyed as the stats are, which is how StorySkill is keyed. */ export declare function storyGateOpen(def: StoryQuestDef, questState: (id: string) => string | undefined, levels: Partial>): boolean; /** The step a player is on, or null once past the last one. */ export declare function storyStep(id: StoryQuestId, progress: StoryProgress | undefined): StoryStep | null; /** The quantity a counting step needs, or 0 for a step that does not count. */ export declare function storyStepTarget(step: StoryStep): number; export declare function npcMatches(ref: StoryNpcRef, npc: { kind: string; id: string; name?: string; }): boolean; /** Reward lines for the offer card, as QuestReward rows. */ export declare function storyRewardRows(reward: StoryReward): { kind: string; qty: number; }[]; export declare function normalizeStoryProgress(raw: unknown): StoryProgressMap; export declare function normalizePendingXpChoices(raw: unknown): PendingXpChoice[]; export {}; //# sourceMappingURL=storyQuests.d.ts.map