/** * THE BATTLEFIELD, levels 6-14 (T96 2026-10-14; plan `.cursor/task-plans/2026-10-14-t96-battlefield.md`; audit `dreadwoods-backend/BATTLEFIELD_AUDIT.md`). * The first place a newcomer meets goblins is a sealed soldiers' shore: the only way in is the Battlefield Captain's compound, and until now the * compound had a Captain, a table and a fire. This turns it into a camp worth stopping at, and gives the goblin bank across the lake a reason to be * crossed. NO new land: every position is a WORLD tile on ground that was already there. * * - THE CAPTAIN'S MUSTER (the compound, x 106-132, z 771-791): a cook (Hob Tasker, a camp trader), a Bounty Board, three training dummies, a supply * wagon, three named residents (Lieutenant Corin Vale, Scout Merrin Quill, Sapper Joss Thorne) and a banner pair at the rear door. The walk * from the south gate to the rear door (x 117-121) is kept clear. * - THE LAKE BANK: three lookout posts for the scout, two bridge piers for the sapper, and danger signs (the far bank is goblin country). * - THE NORTH LANDING: a second Rupert Row (the same name, so the client needs nothing new) on the goblin bank by the bridge's north foot, because * until now a newcomer rowed across for 200 coins had no boat home. * - THE GOBLIN RAID: a clock-read event on the shore north of the compound (like the Redcap patrol and the Passing Bay): windows every two hours * read off the wall clock, lighter than a lone creature of the level, scaled to the players there. Lieutenant Vale can also sound a drill. * - THE WARCHIEF'S HOLD: a hill fort on the goblin side (x 142-158, z 658-672) where Warchief Skragg (level 15) keeps a telegraphed slam and four guards. * * The chain is battlefieldQuests.ts ("The Muster", five quests, Combat 7-14). EVERY NUMBER HERE IS A PLACEHOLDER for the balance pass. Models are kit * stand-ins (logged in dreadwoods-backend/upgrades). */ import type { LanternWakeBox } from './lanternWake.js'; import type { CalvertonFolk } from './calvertonExtension.js'; import type { DiscoveryZone } from './landmarks.js'; export declare const BATTLEFIELD_MUSTER_NAME = "The Captain's Muster"; export declare const WARCHIEF_HOLD_NAME = "The Warchief's Hold"; export declare const SAPPERS_SPAN_NAME = "The Sappers' Span"; /** The Captain's compound, final-world tiles: its centre (types landmarks.ts BATTLEFIELD_CAPTAIN_CAMP in the final frame), walls at x 105 and 133. */ export declare const MUSTER_CENTRE: { readonly x: 119; readonly z: 780; }; /** The floor inside the walls (the walls are at x 105/133, z 769 north and z 793 south). */ export declare const MUSTER_BOX: LanternWakeBox; /** The corridor from the south gate to the rear door: nothing is placed in it. */ export declare const MUSTER_CORRIDOR: LanternWakeBox; export declare const MUSTER_SOUTH_GATE: { readonly x: 119; readonly z: 793; }; export declare const MUSTER_NORTH_DOOR: { readonly x: 119; readonly z: 769; }; export type MusterProp = { id: string; kind: 'dreadmodel' | 'dreadprop' | 'campfire' | 'barrel' | 'bountyboard' | 'yardprop'; style: string; x: number; z: number; scale?: number; }; /** The Muster's pieces: the cook's corner in the west, the board and the dummies in the east, banners at the rear door. */ export declare const MUSTER_PIECES: readonly MusterProp[]; export declare const MUSTER_FOLK_NAMES: { readonly lieutenant: "Lieutenant Corin Vale"; readonly scout: "Scout Merrin Quill"; readonly sapper: "Sapper Joss Thorne"; readonly cook: "Hob Tasker"; }; /** Residents on the default look (stand-ins, logged in upgrades). The cook is a camp trader (campTraders.ts), not here. */ export declare const MUSTER_FOLK: ReadonlyArray; export declare function musterFolkByName(name: string | null | undefined): CalvertonFolk | null; export type MusterQuestProp = { id: string; x: number; z: number; style: string; }; export declare const BF_PROP: { readonly post: "bfpost"; readonly wagon: "bfwagon"; readonly pier: "bfpier"; readonly drum: "bfdrum"; }; /** Merrin's three lookout posts along the soldiers' lake bank (between the cabbage plots; she counts the far bank's fires from each). */ export declare const BF_POST_WEST: MusterQuestProp; export declare const BF_POST_BRIDGE: MusterQuestProp; export declare const BF_POST_EAST: MusterQuestProp; export declare const BF_POSTS: readonly MusterQuestProp[]; /** The supply wagon in the compound (Supplies for the Line loads it). */ export declare const BF_WAGON: MusterQuestProp; /** The two bridge piers at the south foot the sapper has you look over (The Sappers' Span). */ export declare const BF_PIER_WEST: MusterQuestProp; export declare const BF_PIER_EAST: MusterQuestProp; export declare const BF_PIERS: readonly MusterQuestProp[]; /** The war drum on top of the Warchief's Hold (silenced at the end of The Warchief's Hold). */ export declare const BF_DRUM: MusterQuestProp; export declare const BATTLEFIELD_QUEST_PROPS: readonly MusterQuestProp[]; export declare const BATTLEFIELD_QUEST_PROP_NAMES: Readonly>; export declare const BATTLEFIELD_PROP_IDLE_LINES: Readonly>; /** The kit model a Battlefield quest prop draws with (CAPITAL_BUILDING_MODELS stand-ins), or null if not one of them. */ export declare function battlefieldPropModel(prop: string): string | null; /** The signs. The first two stand on the soldiers' lake bank, the third on the goblin bank, the fourth below the Hold, the fifth inside the Muster. */ export declare const BATTLEFIELD_SIGNS: ReadonlyArray<{ id: string; x: number; z: number; text: string; }>; /** * Rupert Row's brother rows the other way. He is the SAME NAME so every dialog, marker and server rule keyed on "Rupert Row" works unchanged * (the server rows south from the north bank: world.ts handleRupertRowBridgeCrossing). The boat is tied in the water at the shore. */ export declare const RUPERT_ROW_NORTH: { readonly x: 86; readonly z: 710; readonly faceX: 86; readonly faceZ: 713; readonly boatX: 86; readonly boatZ: 713; }; export declare const NORTH_LANDING_BOX: LanternWakeBox; /** * A goblin band crosses the lake and storms the shore north of the Muster's rear door every two hours, at ten to the hour on the ODD hours * (01:50, 03:50, ... UTC) for twelve minutes, read off the wall clock (nothing rolled or stored, so every server agrees and a restart changes * nothing). Odd hours keep it off the Fishing Derby (even hours at :40) and clear of the Redcap patrol (:20) and the lairs (:10). * The band is a small copy of the Random World Events stream (scaled levels, lighter than a lone creature of the level, never respawning in * place, leaving with the last player on the shore). */ export declare const GOBLIN_RAID: { readonly periodMs: number; /** Milliseconds past 00:00 UTC the first window opens at (01:50). */ readonly offsetMs: number; readonly durationMs: number; readonly kind: "goblin"; readonly name: "Goblin raider"; readonly levels: [number, number]; readonly cap: 4; readonly perExtraPlayer: 1; readonly everyMs: 9000; readonly firstWave: 2; /** The band ignores anyone below this Combat (a green newcomer on the shore is left alone). */ readonly aggroCombat: 8; /** They storm the whole shore: the nests are fifteen tiles apart, so one band reaches any fighter between them. */ readonly aggroRadius: 16; readonly leashRadius: 40; readonly aggroText: "A goblin band swarms up the bank: \"Kill the soft ones!\""; }; /** A muster drill (the Lieutenant sounds the horn): a short raid anyone on the shore can fight, paid nothing, at most once every ten minutes. */ export declare const GOBLIN_DRILL: { readonly durationMs: number; readonly cooldownMs: number; }; export declare const GOBLIN_RAID_ID_PREFIX = "bfr-"; /** The shore the raid keeps: north of the compound's rear door to the lake bank, between the camps' fences. */ export declare const GOBLIN_RAID_ZONE: { readonly minX: 96; readonly maxX: 142; readonly minZ: 747; readonly maxZ: 768; }; export declare function inGoblinRaidZone(x: number, z: number): boolean; /** Where the band forms: along the lake bank (NPCs, so no entity rule applies). */ export declare const GOBLIN_RAID_NESTS: ReadonlyArray<{ x: number; z: number; }>; export declare const GOBLIN_RAID_KILLS_TO_PAY = 4; export declare const GOBLIN_RAID_REWARD: { readonly coins: 150; readonly explorerXp: 250; }; export declare const GOBLIN_RAID_DIFFICULTY = 1; /** The raid is not a quest creature by its kind: the kill key the story engine counts. */ export declare const GOBLIN_RAID_QUEST_KEY = "bf-raider"; export declare const GOBLIN_RAID_TEXTS: { readonly start: "A goblin band is storming the shore north of the Muster! Hold the line until it breaks."; readonly endPaid: "The goblins break and run for the lake. The Muster's horn sounds for you."; readonly endPlain: "The goblin band breaks and runs for the lake."; readonly quiet: "A goblin band is storming the shore, but they have no interest in someone so green. Keep to the camp."; readonly warn: "The Muster horn sounds: a goblin band will storm the shore in a minute or so."; readonly drill: "Lieutenant Vale sounds the horn: a drill raid! Goblin raiders come up the bank. Hold the line, and nothing is paid for a drill."; readonly drillWait: "The Lieutenant shakes his head: the last drill was not ten minutes ago. Give the camp a breather."; readonly drillActive: "The line is already holding a raid. Go and fight it."; }; export declare const GOBLIN_RAID_WARN_MS = 90000; export type GoblinRaidWindow = { slot: number; startMs: number; endMs: number; active: boolean; nextStartMs: number; }; /** The raid window `nowMs` is in or the next one: a pure function of the clock. */ export declare function goblinRaidWindow(nowMs: number): GoblinRaidWindow; /** The slot whose window is open or the NEXT one to open (the slot the warning belongs to). */ export declare function goblinRaidSlotAfter(nowMs: number): number; /** The hold: a ring of logs on the hilltop mesa (heights 6-7 at x 144-154, z 660-670), its gap on the south-west where the track comes up. */ export declare const WARCHIEF_HOLD: LanternWakeBox; export declare const WARCHIEF_HOLD_CENTRE: { readonly x: 149; readonly z: 665; }; /** The hold's ring wall: a square of logs round the mesa, with a three-wide gap at the south-west corner. */ export declare const WARCHIEF_HOLD_GAP: { readonly minX: 142; readonly maxX: 144; readonly minZ: 670; readonly maxZ: 672; }; /** The foot of the hill where the quest's reach step lands and the approach is signed. */ export declare const WARCHIEF_HOLD_FOOT: { readonly minX: 134; readonly maxX: 146; readonly minZ: 674; readonly maxZ: 682; }; export declare const WARCHIEF_HOLD_STANDS: { readonly foot: { readonly x: 140; readonly z: 678; }; readonly gate: { readonly x: 143; readonly z: 671; }; readonly top: { readonly x: 149; readonly z: 665; }; }; export declare const WARCHIEF_HOLD_PIECES: readonly MusterProp[]; export declare const WARCHIEF_KIND = "goblinwarchief"; export declare const WARCHIEF_NAME = "Warchief Skragg"; export declare const WARCHIEF: { readonly name: "Warchief Skragg"; readonly level: readonly [number, number]; readonly maxHit: 9; readonly healthFactor: 1.8; readonly respawnMs: 240000; readonly aggro: 7; readonly leash: 14; readonly x: 150; readonly z: 664; readonly spawnLeash: 2; readonly text: "Warchief Skragg slams his maul on the drum frame. \"Little soldier come to die on my hill!\""; readonly note: "The goblins' warchief, a head taller than his band, with a maul made from a wagon axle. He keeps a hill fort on the goblin side of the lake with four guards. Every fourth blow is a slam, announced a full turn ahead and twice an ordinary hit: step out of his reach before it lands and it misses."; }; export declare function isBattlefieldHostileKind(kind: string): boolean; /** The four guards: ordinary goblins (ids `bfh-`) inside the ring, who hold the hold. */ export declare const WARCHIEF_GUARD_ID_PREFIX = "bfh-"; export declare const WARCHIEF_GUARDS: ReadonlyArray<{ x: number; z: number; }>; export declare function inWarchiefHold(x: number, z: number): boolean; /** The Battlefield's lines (marked by the server, ids are the marks it writes; explorerLedger.ts section `field`). */ export declare const LEDGER_FIELD_LINES: readonly { id: string; label: string; }[]; export declare const BATTLEFIELD_DISCOVERY_ZONES: readonly DiscoveryZone[]; /** Where the quest helper and the guide say each place is. */ export declare const BATTLEFIELD_PLACE_TEXT: Readonly>; /** Standable tiles (teleport links, smokes). */ export declare const BATTLEFIELD_STANDS: { readonly muster: { readonly x: 119; readonly z: 784; }; readonly gate: { readonly x: 119; readonly z: 791; }; readonly cook: { readonly x: 112; readonly z: 781; }; readonly board: { readonly x: 123; readonly z: 777; }; readonly rearDoor: { readonly x: 119; readonly z: 767; }; readonly dock: { readonly x: 80; readonly z: 746; }; readonly bridgeSouth: { readonly x: 91; readonly z: 746; }; readonly bridgeNorth: { readonly x: 91; readonly z: 709; }; readonly northLanding: { readonly x: 86; readonly z: 709; }; readonly hold: { readonly foot: { readonly x: 140; readonly z: 678; }; readonly gate: { readonly x: 143; readonly z: 671; }; readonly top: { readonly x: 149; readonly z: 665; }; }; }; //# sourceMappingURL=battlefieldMuster.d.ts.map