@dreadwood-types/types 0.1.361 → 0.1.363
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/attackableNpcs.d.ts.map +1 -1
- package/dist/attackableNpcs.js +2 -0
- package/dist/attackableNpcs.js.map +1 -1
- package/dist/bossSignatures.d.ts +1 -1
- package/dist/bossSignatures.d.ts.map +1 -1
- package/dist/bossSignatures.js +6 -0
- package/dist/bossSignatures.js.map +1 -1
- package/dist/campKitchens.d.ts.map +1 -1
- package/dist/campKitchens.js +5 -0
- package/dist/campKitchens.js.map +1 -1
- package/dist/campTraders.d.ts.map +1 -1
- package/dist/campTraders.js +12 -0
- package/dist/campTraders.js.map +1 -1
- package/dist/constants.d.ts +2 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/expandedContracts.d.ts.map +1 -1
- package/dist/expandedContracts.js +2 -1
- package/dist/expandedContracts.js.map +1 -1
- package/dist/gannetPointDens.js +1 -1
- package/dist/highfoldDens.d.ts +119 -0
- package/dist/highfoldDens.d.ts.map +1 -0
- package/dist/highfoldDens.js +197 -0
- package/dist/highfoldDens.js.map +1 -0
- package/dist/highfoldQuestDef.d.ts +35 -0
- package/dist/highfoldQuestDef.d.ts.map +1 -0
- package/dist/highfoldQuestDef.js +223 -0
- package/dist/highfoldQuestDef.js.map +1 -0
- package/dist/highfoldWatch.d.ts +272 -0
- package/dist/highfoldWatch.d.ts.map +1 -0
- package/dist/highfoldWatch.js +333 -0
- package/dist/highfoldWatch.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/legacy.d.ts +3 -0
- package/dist/legacy.d.ts.map +1 -1
- package/dist/legacy.js +3 -0
- package/dist/legacy.js.map +1 -1
- package/dist/quests.d.ts.map +1 -1
- package/dist/quests.js +31 -0
- package/dist/quests.js.map +1 -1
- package/dist/storyQuests.d.ts +1 -1
- package/dist/storyQuests.d.ts.map +1 -1
- package/dist/storyQuests.js +17 -0
- package/dist/storyQuests.js.map +1 -1
- package/package.json +43 -43
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HIGHFOLD WATCH (2026-10-18; plan `.cursor/task-plans/2026-10-18-highfold-watch-build.md`; design sheets `highfold-watch-1..7`, ChatGPT proposals of
|
|
3
|
+
* 2026-10-18; plan of the empty-land round `2026-10-18-sheets-1-40-empty-land.md`): the old wardens' fortress on the heights east of the Dwarf Road's
|
|
4
|
+
* Gate Court, levels 36-40, the last place before the sealed Dwarf Pass and the top of the free 1-40 band. A ruined curtain wall round a safe
|
|
5
|
+
* Watch Camp, a broken keep full of empty armour, five Beacon Towers on the south wall, a view platform over the Gate Court and the Hollow Gallery
|
|
6
|
+
* where The Hollow Watchman stands.
|
|
7
|
+
*
|
|
8
|
+
* WHERE: box x 1976-2156, z 300-399, the bare rock plateau east of the canyon's east ridge (rock to x about 1974) and west of the sea (from x about
|
|
9
|
+
* 2162), south of the Dwarf Road's wall rows (z 296-299, untouched: nothing here touches a 41+ gate; the Dwarf Pass stays sealed). The plan's box ran on to
|
|
10
|
+
* z 470 and overlapped Cairn Shelf (z 400-660); Highfold keeps z 300-399. The way in on foot is gate-free: the plateau is walkable from Riversend
|
|
11
|
+
* Halt, and the Approach path runs from the box's south edge (x 2069, z 399) north to the Highfold Gate.
|
|
12
|
+
*
|
|
13
|
+
* THE BEACON CHAIN (the signature mechanic; it reuses the Hollow Delve's ordered levers and the Cracked Bell's ordered touch, and the Vent Gorge's
|
|
14
|
+
* shared clock): five Beacon Towers stand on the south wall. The Wardens' tally board names the order they must be lit in, drawn afresh every week
|
|
15
|
+
* (hfBeaconOrder). They catch only in the WIND'S CALM (a clock the whole land shares: calm, then the wind rising a turn ahead, then a gust that puts
|
|
16
|
+
* every flame out). A beacon out of order, or a gust that catches a part-lit chain, douses them all and rings the alarm bell: the hollow guards of the
|
|
17
|
+
* Great Hall wake and come for anyone in the yard. All five in order open the Wardens' Stair, a door in the view platform's wall that takes anyone
|
|
18
|
+
* who walks it down to the Gate Court, for a while. The state is shared (everyone sees the flames), in memory (a restart douses them) and nothing in it
|
|
19
|
+
* heals. The runtime is the backend's highfoldBeacons.ts.
|
|
20
|
+
*
|
|
21
|
+
* Every number is a WORLD tile (x east, z south) and a PLACEHOLDER for the balance pass. The models are the kit's own as stand-ins (backend upgrades
|
|
22
|
+
* rows `highfold-*`).
|
|
23
|
+
*/
|
|
24
|
+
import type { LanternWakeBox, LanternWakePoint } from './lanternWake.js';
|
|
25
|
+
import type { DiscoveryZone } from './landmarks.js';
|
|
26
|
+
export declare const HIGHFOLD_ID = "highfold-watch";
|
|
27
|
+
export declare const HIGHFOLD_NAME = "Highfold Watch";
|
|
28
|
+
export declare const HIGHFOLD_BOX: LanternWakeBox;
|
|
29
|
+
/** The levels the place is for. */
|
|
30
|
+
export declare const HIGHFOLD_LEVELS: {
|
|
31
|
+
readonly min: 36;
|
|
32
|
+
readonly max: 40;
|
|
33
|
+
};
|
|
34
|
+
export declare function inHfBox(b: LanternWakeBox, x: number, z: number, pad?: number): boolean;
|
|
35
|
+
export declare const inHighfoldBox: (x: number, z: number, pad?: number) => boolean;
|
|
36
|
+
/** A ring of rock: the outer rectangle, how many tiles thick, and the gaps cut through it. */
|
|
37
|
+
export type HfRing = {
|
|
38
|
+
readonly id: string;
|
|
39
|
+
readonly outer: LanternWakeBox;
|
|
40
|
+
readonly thick: number;
|
|
41
|
+
readonly gaps: readonly LanternWakeBox[];
|
|
42
|
+
};
|
|
43
|
+
/** The curtain wall: the Highfold Gate in the south wall, a west door to the view platform. */
|
|
44
|
+
export declare const HIGHFOLD_CURTAIN: HfRing;
|
|
45
|
+
/** The broken keep: its great hall's south entrance and two breaches. */
|
|
46
|
+
export declare const HIGHFOLD_KEEP: HfRing;
|
|
47
|
+
/** The Hollow Gallery's walls: one way in, from the south. */
|
|
48
|
+
export declare const HIGHFOLD_GALLERY_WALL: HfRing;
|
|
49
|
+
export declare const HIGHFOLD_RINGS: readonly HfRing[];
|
|
50
|
+
/** The wall's height above the plateau's ground (3): stone stand-in for the dwarven masonry. */
|
|
51
|
+
export declare const HIGHFOLD_WALL_HEIGHT = 7;
|
|
52
|
+
export declare function onRing(r: HfRing, x: number, z: number): boolean;
|
|
53
|
+
/** Is this tile wall (rock the world blocks)? The keep's walls are ragged: a hashed tenth of them has fallen. */
|
|
54
|
+
export declare function isHighfoldWall(x: number, z: number): boolean;
|
|
55
|
+
/** A fallen tile of the keep wall (open rubble ground): a stable hash so the types, the backend and the tests agree. */
|
|
56
|
+
export declare function isHighfoldFallen(x: number, z: number): boolean;
|
|
57
|
+
/** The yard inside the curtain wall, and the sub-places in it. */
|
|
58
|
+
export declare const HIGHFOLD_YARD: LanternWakeBox;
|
|
59
|
+
export declare const HIGHFOLD_CAMP_BOX: LanternWakeBox;
|
|
60
|
+
export declare const HIGHFOLD_PLATFORM: LanternWakeBox;
|
|
61
|
+
export declare const HIGHFOLD_GATE_BAND: LanternWakeBox;
|
|
62
|
+
export declare const HIGHFOLD_PATHS: ReadonlyArray<{
|
|
63
|
+
id: string;
|
|
64
|
+
w: number;
|
|
65
|
+
pts: readonly LanternWakePoint[];
|
|
66
|
+
}>;
|
|
67
|
+
/**
|
|
68
|
+
* THE HIGHFOLD ROAD (2026-10-18): how a player on foot gets here. Cairn Shelf's rock rim shuts the plateau from x 1944 to 2148 at z 480-660, so the way
|
|
69
|
+
* north from Riversend Halt runs up the open shore strip east of it (x 2149 to about 2158, sea beyond) and then west along the box's south edge to the
|
|
70
|
+
* approach. It is laid as a path over the land tiles of the strip (never over water, rock or a prop); it needs no gate, and Cairn Shelf's own north path
|
|
71
|
+
* (the sheet's way in) is left for later (NEXT_STEPS).
|
|
72
|
+
*/
|
|
73
|
+
export declare const HIGHFOLD_ROAD: {
|
|
74
|
+
id: string;
|
|
75
|
+
w: number;
|
|
76
|
+
pts: readonly LanternWakePoint[];
|
|
77
|
+
};
|
|
78
|
+
export declare const HF_BEACON_NAMES: readonly ["Far West Beacon", "West Beacon", "Gate-West Beacon", "Gate-East Beacon", "East Beacon"];
|
|
79
|
+
export declare const HF_PROP: {
|
|
80
|
+
readonly beacon: "hfbeacon";
|
|
81
|
+
readonly beaconLit: "hfbeaconlit";
|
|
82
|
+
readonly tally: "hftally";
|
|
83
|
+
readonly spyglass: "hfspyglass";
|
|
84
|
+
readonly bell: "hfbell";
|
|
85
|
+
readonly stair: "hfstair";
|
|
86
|
+
readonly stairOpen: "hfstairopen";
|
|
87
|
+
};
|
|
88
|
+
export type HfQuestProp = {
|
|
89
|
+
readonly id: string;
|
|
90
|
+
readonly x: number;
|
|
91
|
+
readonly z: number;
|
|
92
|
+
readonly style: string;
|
|
93
|
+
};
|
|
94
|
+
export declare const HF_BEACON_Z = 367;
|
|
95
|
+
/** The five towers, west to east, unlit. A tower's lit look is the same id with `hfbeaconlit:` in place of `hfbeacon:`. */
|
|
96
|
+
export declare const HF_BEACONS: readonly (HfQuestProp & {
|
|
97
|
+
readonly n: number;
|
|
98
|
+
readonly name: string;
|
|
99
|
+
})[];
|
|
100
|
+
export declare const hfBeaconStyle: (n: number, lit: boolean) => string;
|
|
101
|
+
/** The beacon number (1-5) a quest-prop style names (lit or not), or 0. */
|
|
102
|
+
export declare function hfBeaconNumber(style: string | undefined | null): number;
|
|
103
|
+
/** The wind clock the whole land shares: calm (the beacons catch), rising (a turn's warning; they still catch), then the gust that puts every flame out. */
|
|
104
|
+
export declare const HF_WIND_CYCLE_MS = 120000;
|
|
105
|
+
export declare const HF_WIND_CALM_MS = 82000;
|
|
106
|
+
export declare const HF_WIND_RISING_MS = 8000;
|
|
107
|
+
export type HfWindPhase = 'calm' | 'rising' | 'gust';
|
|
108
|
+
export declare function hfWindPhase(nowMs: number): HfWindPhase;
|
|
109
|
+
/** Index of the wind cycle `nowMs` is in (the part-lit chain is doused when it changes). */
|
|
110
|
+
export declare const hfWindCycle: (nowMs: number) => number;
|
|
111
|
+
/** Seconds left of the calm (0 in the rising and the gust). */
|
|
112
|
+
export declare function hfCalmLeftMs(nowMs: number): number;
|
|
113
|
+
/** The Wardens' Stair stays open this long after the chain is lit, for everyone. */
|
|
114
|
+
export declare const HF_STAIR_OPEN_MS = 150000;
|
|
115
|
+
/** The alarm bell's reach in time: the hollow guards hunt the yard this long. */
|
|
116
|
+
export declare const HF_ALARM_MS = 40000;
|
|
117
|
+
/** One wrong beacon per player in this time (a player cannot spam the bell). */
|
|
118
|
+
export declare const HF_WRONG_COOLDOWN_MS = 4000;
|
|
119
|
+
/** Weeks run Monday 00:00 UTC; this is a Monday. */
|
|
120
|
+
export declare const HF_ORDER_EPOCH_MS: number;
|
|
121
|
+
export declare const hfWeekIndex: (nowMs: number) => number;
|
|
122
|
+
/** This week's order the five beacons are lit in (beacon numbers, west to east): a permutation, never the same as last week's. */
|
|
123
|
+
export declare function hfBeaconOrder(week: number): number[];
|
|
124
|
+
export declare function hfOrderNames(order: readonly number[]): string;
|
|
125
|
+
/** The tally board's words for a week. */
|
|
126
|
+
export declare function hfTallyText(week: number): string;
|
|
127
|
+
export declare const HF_TEXT: {
|
|
128
|
+
readonly lit: (name: string) => string;
|
|
129
|
+
readonly litLast: "The fifth beacon catches and the whole chain flares along the wall. High in the view platform's wall the Wardens' Stair grinds open.";
|
|
130
|
+
readonly wrong: "That beacon was out of turn. Every flame on the wall dies, and the alarm bell begins to toll. The hollow guards are waking!";
|
|
131
|
+
readonly gustWait: "The wind is tearing at the wall and no flame will catch. Wait for the calm.";
|
|
132
|
+
readonly gustOut: "The gust takes every flame on the wall, and the alarm bell tolls: the chain was not finished in the calm.";
|
|
133
|
+
readonly rising: "The wind is rising on the heights. Whatever is burning on the wall will not last the gust.";
|
|
134
|
+
readonly burning: "That beacon is already burning.";
|
|
135
|
+
readonly held: "The Wardens' chain is lit and the stair is open. Leave the beacons be.";
|
|
136
|
+
readonly cool: "You have only just rung the bell on yourself. Wait a moment.";
|
|
137
|
+
readonly stairShut: "The Wardens' Stair is barred with old iron. Light the five beacons in the tally board's order within the calm and it will open.";
|
|
138
|
+
readonly stairDown: "You go down the Wardens' Stair, a long switchback of worn steps, and come out in the east of the Gate Court.";
|
|
139
|
+
readonly stairClosing: "The Wardens' Stair grinds shut again and the beacons burn down.";
|
|
140
|
+
readonly bell: "The alarm bell hangs from its post by the keep, rope worn smooth. When a beacon is lit out of turn or the gust catches the chain, it tolls and the hollow guards wake.";
|
|
141
|
+
};
|
|
142
|
+
/** The Wardens' Stair: a door in the view platform's west wall that takes you to the Gate Court, when the chain is lit. */
|
|
143
|
+
export declare const HF_STAIR: HfQuestProp;
|
|
144
|
+
export declare const HF_STAIR_OPEN_STYLE: string;
|
|
145
|
+
/** Where the stair lets out: the Gate Court's east side (the backend finds the nearest standable tile). */
|
|
146
|
+
export declare const HF_STAIR_LANDING: {
|
|
147
|
+
readonly x: 1904;
|
|
148
|
+
readonly z: 332;
|
|
149
|
+
};
|
|
150
|
+
export declare const HF_BELL: HfQuestProp;
|
|
151
|
+
export declare const HF_TALLY: HfQuestProp;
|
|
152
|
+
export declare const HF_SPYGLASS: HfQuestProp;
|
|
153
|
+
export declare const HIGHFOLD_QUEST_PROPS: readonly HfQuestProp[];
|
|
154
|
+
export declare const HIGHFOLD_QUEST_PROP_NAMES: Readonly<Record<string, string>>;
|
|
155
|
+
/** The model a Highfold quest prop draws with (frontend models that already exist), or null if not one of them. */
|
|
156
|
+
export declare function highfoldPropModel(prop: string): string | null;
|
|
157
|
+
/** The verb on the hover for each prop. */
|
|
158
|
+
export declare const HIGHFOLD_PROP_VERBS: Readonly<Record<string, string>>;
|
|
159
|
+
/** One thing laid on the ground: the kit's own kinds and styles, placed by the backend's ground placer. */
|
|
160
|
+
export type HighfoldProp = {
|
|
161
|
+
readonly id: string;
|
|
162
|
+
readonly kind: 'dreadmodel' | 'dreadprop' | 'campfire' | 'barrel' | 'bountyboard' | 'furnace' | 'anvil' | 'workbench' | 'stove' | 'signpost';
|
|
163
|
+
readonly style: string;
|
|
164
|
+
readonly x: number;
|
|
165
|
+
readonly z: number;
|
|
166
|
+
readonly scale?: number;
|
|
167
|
+
};
|
|
168
|
+
/** The camp's pieces and working stations (Ashfall's layout, moved). No bank anywhere in Highfold. */
|
|
169
|
+
export declare const HIGHFOLD_CAMP_PIECES: readonly HighfoldProp[];
|
|
170
|
+
/** Dressing on the wall and in the ruins: banners at the gate and the stair, braziers (unlit stand-ins) at the Hollow Gallery's door. */
|
|
171
|
+
export declare const HIGHFOLD_DRESSING: readonly HighfoldProp[];
|
|
172
|
+
/** The signs (the placard signpost). */
|
|
173
|
+
export declare const HIGHFOLD_SIGNS: ReadonlyArray<{
|
|
174
|
+
readonly id: string;
|
|
175
|
+
readonly x: number;
|
|
176
|
+
readonly z: number;
|
|
177
|
+
readonly text: string;
|
|
178
|
+
}>;
|
|
179
|
+
export type HighfoldFolk = {
|
|
180
|
+
readonly id: string;
|
|
181
|
+
readonly name: string;
|
|
182
|
+
readonly place: string;
|
|
183
|
+
readonly x: number;
|
|
184
|
+
readonly z: number;
|
|
185
|
+
readonly faceX: number;
|
|
186
|
+
readonly faceZ: number;
|
|
187
|
+
readonly leash: number;
|
|
188
|
+
readonly speak: string;
|
|
189
|
+
readonly extras?: ReadonlyArray<{
|
|
190
|
+
readonly id: string;
|
|
191
|
+
readonly label: string;
|
|
192
|
+
readonly say: string;
|
|
193
|
+
}>;
|
|
194
|
+
};
|
|
195
|
+
/** The plan's six names (design sheet 5 invented others; see the plan file for the mapping). The cook lives in campTraders.ts. */
|
|
196
|
+
export declare const HIGHFOLD_FOLK_NAMES: {
|
|
197
|
+
readonly captain: "Captain Berrin Holt";
|
|
198
|
+
readonly lamplighter: "Lamplighter Nessa Tarn";
|
|
199
|
+
readonly smith: "Smith Dunmar Cole";
|
|
200
|
+
readonly cook: "Agnes Burr";
|
|
201
|
+
readonly scout: "Scout Ivo Dray";
|
|
202
|
+
readonly chronicler: "Chronicler Mabel Orrin";
|
|
203
|
+
};
|
|
204
|
+
/** The five residents who are not the cook (named residents on the default look, stationary). */
|
|
205
|
+
export declare const HIGHFOLD_FOLK: ReadonlyArray<HighfoldFolk>;
|
|
206
|
+
export declare function highfoldFolkByName(name: string | null | undefined): HighfoldFolk | null;
|
|
207
|
+
/** The camp's cook, which lives in CAMP_TRADERS (campTraders.ts) beside the other camps' cooks. */
|
|
208
|
+
export declare const HIGHFOLD_COOK: {
|
|
209
|
+
readonly id: "camp-highfold";
|
|
210
|
+
readonly name: "Agnes Burr";
|
|
211
|
+
readonly x: 2027;
|
|
212
|
+
readonly z: 346;
|
|
213
|
+
readonly faceX: 2029;
|
|
214
|
+
readonly faceZ: 343;
|
|
215
|
+
};
|
|
216
|
+
/** Standable tiles for teleports, smokes and the helper. */
|
|
217
|
+
export declare const HIGHFOLD_STANDS: {
|
|
218
|
+
readonly approach: {
|
|
219
|
+
readonly x: 2069;
|
|
220
|
+
readonly z: 396;
|
|
221
|
+
};
|
|
222
|
+
readonly gate: {
|
|
223
|
+
readonly x: 2069;
|
|
224
|
+
readonly z: 376;
|
|
225
|
+
};
|
|
226
|
+
readonly camp: {
|
|
227
|
+
readonly x: 2030;
|
|
228
|
+
readonly z: 351;
|
|
229
|
+
};
|
|
230
|
+
readonly smithy: {
|
|
231
|
+
readonly x: 2010;
|
|
232
|
+
readonly z: 349;
|
|
233
|
+
};
|
|
234
|
+
readonly board: {
|
|
235
|
+
readonly x: 2020;
|
|
236
|
+
readonly z: 357;
|
|
237
|
+
};
|
|
238
|
+
readonly beacons: {
|
|
239
|
+
readonly x: 2069;
|
|
240
|
+
readonly z: 362;
|
|
241
|
+
};
|
|
242
|
+
readonly hall: {
|
|
243
|
+
readonly x: 2085;
|
|
244
|
+
readonly z: 340;
|
|
245
|
+
};
|
|
246
|
+
readonly gallery: {
|
|
247
|
+
readonly x: 2129;
|
|
248
|
+
readonly z: 336;
|
|
249
|
+
};
|
|
250
|
+
readonly platform: {
|
|
251
|
+
readonly x: 1989;
|
|
252
|
+
readonly z: 328;
|
|
253
|
+
};
|
|
254
|
+
readonly barracks: {
|
|
255
|
+
readonly x: 2118;
|
|
256
|
+
readonly z: 357;
|
|
257
|
+
};
|
|
258
|
+
readonly outerWatch: {
|
|
259
|
+
readonly x: 2040;
|
|
260
|
+
readonly z: 388;
|
|
261
|
+
};
|
|
262
|
+
readonly crag: {
|
|
263
|
+
readonly x: 2125;
|
|
264
|
+
readonly z: 388;
|
|
265
|
+
};
|
|
266
|
+
};
|
|
267
|
+
export declare const HIGHFOLD_PLACE_TEXT = "Highfold Watch is the old wardens' fortress on the heights east of the Gate Court, on the open plateau above the Dwarf Road: a camp inside its wall with a smithy, a furnace, an anvil, a workbench, a cookhouse, a fire and a Bounty Board, a broken keep full of empty armour, five beacon towers on the south wall and a view platform over the Gate Court. There is no bank. The Dwarf Pass below stays sealed. On foot from Riversend Halt, go north over the open plateau and up the shore strip east of Cairn Shelf: the Highfold Road leads along the fortress's south edge to its gate.";
|
|
268
|
+
export declare const HIGHFOLD_CHAIN_TEXT = "Five beacons stand on Highfold's south wall. The Wardens' tally board names the order to light them in, drawn afresh every week, and they catch only in the calm of the wind, which runs on a two-minute clock: calm, a few seconds of rising wind, then a gust that puts every flame out. A beacon lit out of turn, or a gust that catches a part-lit chain, puts them all out and rings the alarm bell, and the hollow guards of the Great Hall wake. All five in order open the Wardens' Stair, a door down to the Gate Court, for two and a half minutes.";
|
|
269
|
+
export declare const HIGHFOLD_CAMP_DISCOVERY_ZONE: DiscoveryZone;
|
|
270
|
+
export declare const HIGHFOLD_PLATFORM_DISCOVERY_ZONE: DiscoveryZone;
|
|
271
|
+
export declare const HIGHFOLD_UMBRELLA_DISCOVERY_ZONE: DiscoveryZone;
|
|
272
|
+
//# sourceMappingURL=highfoldWatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"highfoldWatch.d.ts","sourceRoot":"","sources":["../src/highfoldWatch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
export const HIGHFOLD_ID = 'highfold-watch';
|
|
2
|
+
export const HIGHFOLD_NAME = 'Highfold Watch';
|
|
3
|
+
export const HIGHFOLD_BOX = { minX: 1976, maxX: 2156, minZ: 300, maxZ: 399 };
|
|
4
|
+
/** The levels the place is for. */
|
|
5
|
+
export const HIGHFOLD_LEVELS = { min: 36, max: 40 };
|
|
6
|
+
export function inHfBox(b, x, z, pad = 0) {
|
|
7
|
+
return x >= b.minX - pad && x <= b.maxX + pad && z >= b.minZ - pad && z <= b.maxZ + pad;
|
|
8
|
+
}
|
|
9
|
+
export const inHighfoldBox = (x, z, pad = 0) => inHfBox(HIGHFOLD_BOX, x, z, pad);
|
|
10
|
+
/** The curtain wall: the Highfold Gate in the south wall, a west door to the view platform. */
|
|
11
|
+
export const HIGHFOLD_CURTAIN = {
|
|
12
|
+
id: 'curtain',
|
|
13
|
+
outer: { minX: 1996, maxX: 2144, minZ: 312, maxZ: 372 },
|
|
14
|
+
thick: 2,
|
|
15
|
+
gaps: [{ minX: 2066, maxX: 2072, minZ: 371, maxZ: 372 }, { minX: 1996, maxX: 1997, minZ: 326, maxZ: 330 }],
|
|
16
|
+
};
|
|
17
|
+
/** The broken keep: its great hall's south entrance and two breaches. */
|
|
18
|
+
export const HIGHFOLD_KEEP = {
|
|
19
|
+
id: 'keep',
|
|
20
|
+
outer: { minX: 2058, maxX: 2112, minZ: 318, maxZ: 346 },
|
|
21
|
+
thick: 2,
|
|
22
|
+
gaps: [{ minX: 2082, maxX: 2088, minZ: 345, maxZ: 346 }, { minX: 2058, maxX: 2059, minZ: 330, maxZ: 333 }, { minX: 2111, maxX: 2112, minZ: 326, maxZ: 329 }],
|
|
23
|
+
};
|
|
24
|
+
/** The Hollow Gallery's walls: one way in, from the south. */
|
|
25
|
+
export const HIGHFOLD_GALLERY_WALL = {
|
|
26
|
+
id: 'gallery',
|
|
27
|
+
outer: { minX: 2118, maxX: 2140, minZ: 316, maxZ: 344 },
|
|
28
|
+
thick: 2,
|
|
29
|
+
gaps: [{ minX: 2127, maxX: 2131, minZ: 343, maxZ: 344 }],
|
|
30
|
+
};
|
|
31
|
+
export const HIGHFOLD_RINGS = [HIGHFOLD_CURTAIN, HIGHFOLD_KEEP, HIGHFOLD_GALLERY_WALL];
|
|
32
|
+
/** The wall's height above the plateau's ground (3): stone stand-in for the dwarven masonry. */
|
|
33
|
+
export const HIGHFOLD_WALL_HEIGHT = 7;
|
|
34
|
+
export function onRing(r, x, z) {
|
|
35
|
+
if (!inHfBox(r.outer, x, z))
|
|
36
|
+
return false;
|
|
37
|
+
const t = r.thick;
|
|
38
|
+
if (x >= r.outer.minX + t && x <= r.outer.maxX - t && z >= r.outer.minZ + t && z <= r.outer.maxZ - t)
|
|
39
|
+
return false;
|
|
40
|
+
return !r.gaps.some((g) => inHfBox(g, x, z));
|
|
41
|
+
}
|
|
42
|
+
/** Is this tile wall (rock the world blocks)? The keep's walls are ragged: a hashed tenth of them has fallen. */
|
|
43
|
+
export function isHighfoldWall(x, z) {
|
|
44
|
+
if (onRing(HIGHFOLD_CURTAIN, x, z) || onRing(HIGHFOLD_GALLERY_WALL, x, z))
|
|
45
|
+
return true;
|
|
46
|
+
if (!onRing(HIGHFOLD_KEEP, x, z))
|
|
47
|
+
return false;
|
|
48
|
+
return !isHighfoldFallen(x, z);
|
|
49
|
+
}
|
|
50
|
+
/** A fallen tile of the keep wall (open rubble ground): a stable hash so the types, the backend and the tests agree. */
|
|
51
|
+
export function isHighfoldFallen(x, z) {
|
|
52
|
+
const n = Math.imul(x, 374761393) ^ Math.imul(z, 668265263);
|
|
53
|
+
const h = Math.imul(n ^ (n >>> 13), 1274126177);
|
|
54
|
+
return ((h ^ (h >>> 16)) >>> 0) % 10 === 0;
|
|
55
|
+
}
|
|
56
|
+
/** The yard inside the curtain wall, and the sub-places in it. */
|
|
57
|
+
export const HIGHFOLD_YARD = { minX: 1998, maxX: 2142, minZ: 314, maxZ: 370 };
|
|
58
|
+
export const HIGHFOLD_CAMP_BOX = { minX: 2000, maxX: 2042, minZ: 330, maxZ: 364 };
|
|
59
|
+
export const HIGHFOLD_PLATFORM = { minX: 1982, maxX: 1994, minZ: 321, maxZ: 335 };
|
|
60
|
+
export const HIGHFOLD_GATE_BAND = { minX: 2066, maxX: 2072, minZ: 371, maxZ: 372 };
|
|
61
|
+
export const HIGHFOLD_PATHS = [
|
|
62
|
+
{ id: 'approach', w: 3, pts: [[2069, 399], [2069, 372], [2069, 360]] },
|
|
63
|
+
{ id: 'camp-road', w: 3, pts: [[2069, 360], [2050, 354], [2030, 352]] },
|
|
64
|
+
{ id: 'keep-road', w: 3, pts: [[2069, 360], [2085, 350], [2085, 344], [2085, 330]] },
|
|
65
|
+
{ id: 'gallery-road', w: 2, pts: [[2085, 350], [2110, 351], [2129, 349], [2129, 330]] },
|
|
66
|
+
{ id: 'platform-road', w: 2, pts: [[2020, 336], [2020, 330], [1998, 328], [1986, 328]] },
|
|
67
|
+
];
|
|
68
|
+
/**
|
|
69
|
+
* THE HIGHFOLD ROAD (2026-10-18): how a player on foot gets here. Cairn Shelf's rock rim shuts the plateau from x 1944 to 2148 at z 480-660, so the way
|
|
70
|
+
* north from Riversend Halt runs up the open shore strip east of it (x 2149 to about 2158, sea beyond) and then west along the box's south edge to the
|
|
71
|
+
* approach. It is laid as a path over the land tiles of the strip (never over water, rock or a prop); it needs no gate, and Cairn Shelf's own north path
|
|
72
|
+
* (the sheet's way in) is left for later (NEXT_STEPS).
|
|
73
|
+
*/
|
|
74
|
+
export const HIGHFOLD_ROAD = {
|
|
75
|
+
id: 'highfold-road', w: 3, pts: [[2153, 664], [2153, 430], [2132, 408], [2069, 399]],
|
|
76
|
+
};
|
|
77
|
+
// ---- The Beacon Chain ------------------------------------------------------------------------------------------------------------------
|
|
78
|
+
export const HF_BEACON_NAMES = ['Far West Beacon', 'West Beacon', 'Gate-West Beacon', 'Gate-East Beacon', 'East Beacon'];
|
|
79
|
+
export const HF_PROP = { beacon: 'hfbeacon', beaconLit: 'hfbeaconlit', tally: 'hftally', spyglass: 'hfspyglass', bell: 'hfbell', stair: 'hfstair', stairOpen: 'hfstairopen' };
|
|
80
|
+
const BEACON_X = [2036, 2048, 2060, 2078, 2090];
|
|
81
|
+
export const HF_BEACON_Z = 367;
|
|
82
|
+
/** The five towers, west to east, unlit. A tower's lit look is the same id with `hfbeaconlit:` in place of `hfbeacon:`. */
|
|
83
|
+
export const HF_BEACONS = BEACON_X.map((x, k) => ({
|
|
84
|
+
id: `hf-beacon-${k + 1}`, n: k + 1, name: HF_BEACON_NAMES[k], x, z: HF_BEACON_Z, style: `${HF_PROP.beacon}:${k + 1}`,
|
|
85
|
+
}));
|
|
86
|
+
export const hfBeaconStyle = (n, lit) => `${lit ? HF_PROP.beaconLit : HF_PROP.beacon}:${n}`;
|
|
87
|
+
/** The beacon number (1-5) a quest-prop style names (lit or not), or 0. */
|
|
88
|
+
export function hfBeaconNumber(style) {
|
|
89
|
+
const m = /^hfbeacon(?:lit)?:([1-5])$/.exec(style ?? '');
|
|
90
|
+
return m ? Number(m[1]) : 0;
|
|
91
|
+
}
|
|
92
|
+
/** The wind clock the whole land shares: calm (the beacons catch), rising (a turn's warning; they still catch), then the gust that puts every flame out. */
|
|
93
|
+
export const HF_WIND_CYCLE_MS = 120_000;
|
|
94
|
+
export const HF_WIND_CALM_MS = 82_000;
|
|
95
|
+
export const HF_WIND_RISING_MS = 8_000;
|
|
96
|
+
export function hfWindPhase(nowMs) {
|
|
97
|
+
const t = ((nowMs % HF_WIND_CYCLE_MS) + HF_WIND_CYCLE_MS) % HF_WIND_CYCLE_MS;
|
|
98
|
+
if (t < HF_WIND_CALM_MS)
|
|
99
|
+
return 'calm';
|
|
100
|
+
if (t < HF_WIND_CALM_MS + HF_WIND_RISING_MS)
|
|
101
|
+
return 'rising';
|
|
102
|
+
return 'gust';
|
|
103
|
+
}
|
|
104
|
+
/** Index of the wind cycle `nowMs` is in (the part-lit chain is doused when it changes). */
|
|
105
|
+
export const hfWindCycle = (nowMs) => Math.floor(nowMs / HF_WIND_CYCLE_MS);
|
|
106
|
+
/** Seconds left of the calm (0 in the rising and the gust). */
|
|
107
|
+
export function hfCalmLeftMs(nowMs) {
|
|
108
|
+
const t = ((nowMs % HF_WIND_CYCLE_MS) + HF_WIND_CYCLE_MS) % HF_WIND_CYCLE_MS;
|
|
109
|
+
return t < HF_WIND_CALM_MS + HF_WIND_RISING_MS ? HF_WIND_CALM_MS + HF_WIND_RISING_MS - t : 0;
|
|
110
|
+
}
|
|
111
|
+
/** The Wardens' Stair stays open this long after the chain is lit, for everyone. */
|
|
112
|
+
export const HF_STAIR_OPEN_MS = 150_000;
|
|
113
|
+
/** The alarm bell's reach in time: the hollow guards hunt the yard this long. */
|
|
114
|
+
export const HF_ALARM_MS = 40_000;
|
|
115
|
+
/** One wrong beacon per player in this time (a player cannot spam the bell). */
|
|
116
|
+
export const HF_WRONG_COOLDOWN_MS = 4_000;
|
|
117
|
+
/** Weeks run Monday 00:00 UTC; this is a Monday. */
|
|
118
|
+
export const HF_ORDER_EPOCH_MS = Date.UTC(2026, 9, 5);
|
|
119
|
+
const WEEK_MS = 7 * 24 * 3600 * 1000;
|
|
120
|
+
export const hfWeekIndex = (nowMs) => Math.floor((nowMs - HF_ORDER_EPOCH_MS) / WEEK_MS);
|
|
121
|
+
function rawOrder(week, salt) {
|
|
122
|
+
let s = (Math.imul(week + 7919, 2654435761) ^ Math.imul(salt + 1, 40503)) >>> 0;
|
|
123
|
+
const rnd = () => {
|
|
124
|
+
s = (s + 0x6d2b79f5) >>> 0;
|
|
125
|
+
let t = s;
|
|
126
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
127
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
128
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
129
|
+
};
|
|
130
|
+
const a = [1, 2, 3, 4, 5];
|
|
131
|
+
for (let i = a.length - 1; i > 0; i--) {
|
|
132
|
+
const j = Math.floor(rnd() * (i + 1));
|
|
133
|
+
[a[i], a[j]] = [a[j], a[i]];
|
|
134
|
+
}
|
|
135
|
+
return a;
|
|
136
|
+
}
|
|
137
|
+
/** This week's order the five beacons are lit in (beacon numbers, west to east): a permutation, never the same as last week's. */
|
|
138
|
+
export function hfBeaconOrder(week) {
|
|
139
|
+
const prev = rawOrder(week - 1, 0).join('');
|
|
140
|
+
for (let salt = 0; salt < 8; salt++) {
|
|
141
|
+
const o = rawOrder(week, salt);
|
|
142
|
+
if (o.join('') !== prev)
|
|
143
|
+
return o;
|
|
144
|
+
}
|
|
145
|
+
return rawOrder(week, 8);
|
|
146
|
+
}
|
|
147
|
+
export function hfOrderNames(order) {
|
|
148
|
+
return order.map((n) => HF_BEACON_NAMES[n - 1]).join(', then the ');
|
|
149
|
+
}
|
|
150
|
+
/** The tally board's words for a week. */
|
|
151
|
+
export function hfTallyText(week) {
|
|
152
|
+
return `The Wardens' tally, for this week: light the ${hfOrderNames(hfBeaconOrder(week))}. The wind gives you the calm to do it in; a beacon out of turn puts them all out and rings the alarm bell.`;
|
|
153
|
+
}
|
|
154
|
+
export const HF_TEXT = {
|
|
155
|
+
lit: (name) => `The ${name} catches and burns.`,
|
|
156
|
+
litLast: "The fifth beacon catches and the whole chain flares along the wall. High in the view platform's wall the Wardens' Stair grinds open.",
|
|
157
|
+
wrong: 'That beacon was out of turn. Every flame on the wall dies, and the alarm bell begins to toll. The hollow guards are waking!',
|
|
158
|
+
gustWait: 'The wind is tearing at the wall and no flame will catch. Wait for the calm.',
|
|
159
|
+
gustOut: 'The gust takes every flame on the wall, and the alarm bell tolls: the chain was not finished in the calm.',
|
|
160
|
+
rising: 'The wind is rising on the heights. Whatever is burning on the wall will not last the gust.',
|
|
161
|
+
burning: 'That beacon is already burning.',
|
|
162
|
+
held: 'The Wardens\' chain is lit and the stair is open. Leave the beacons be.',
|
|
163
|
+
cool: 'You have only just rung the bell on yourself. Wait a moment.',
|
|
164
|
+
stairShut: 'The Wardens\' Stair is barred with old iron. Light the five beacons in the tally board\'s order within the calm and it will open.',
|
|
165
|
+
stairDown: 'You go down the Wardens\' Stair, a long switchback of worn steps, and come out in the east of the Gate Court.',
|
|
166
|
+
stairClosing: 'The Wardens\' Stair grinds shut again and the beacons burn down.',
|
|
167
|
+
bell: 'The alarm bell hangs from its post by the keep, rope worn smooth. When a beacon is lit out of turn or the gust catches the chain, it tolls and the hollow guards wake.',
|
|
168
|
+
};
|
|
169
|
+
/** The Wardens' Stair: a door in the view platform's west wall that takes you to the Gate Court, when the chain is lit. */
|
|
170
|
+
export const HF_STAIR = { id: 'hf-stair', x: 1983, z: 328, style: `${HF_PROP.stair}:1` };
|
|
171
|
+
export const HF_STAIR_OPEN_STYLE = `${HF_PROP.stairOpen}:1`;
|
|
172
|
+
/** Where the stair lets out: the Gate Court's east side (the backend finds the nearest standable tile). */
|
|
173
|
+
export const HF_STAIR_LANDING = { x: 1904, z: 332 };
|
|
174
|
+
export const HF_BELL = { id: 'hf-bell', x: 2077, z: 352, style: `${HF_PROP.bell}:1` };
|
|
175
|
+
export const HF_TALLY = { id: 'hf-tally', x: 2035, z: 346, style: `${HF_PROP.tally}:1` };
|
|
176
|
+
export const HF_SPYGLASS = { id: 'hf-spyglass', x: 1986, z: 322, style: `${HF_PROP.spyglass}:1` };
|
|
177
|
+
export const HIGHFOLD_QUEST_PROPS = [...HF_BEACONS, HF_STAIR, HF_BELL, HF_TALLY, HF_SPYGLASS];
|
|
178
|
+
export const HIGHFOLD_QUEST_PROP_NAMES = {
|
|
179
|
+
...Object.fromEntries(HF_BEACONS.flatMap((b) => [[b.style, b.name], [hfBeaconStyle(b.n, true), b.name]])),
|
|
180
|
+
[HF_STAIR.style]: "Wardens' Stair (barred)",
|
|
181
|
+
[HF_STAIR_OPEN_STYLE]: "Wardens' Stair",
|
|
182
|
+
[HF_BELL.style]: 'Alarm Bell',
|
|
183
|
+
[HF_TALLY.style]: "Wardens' Tally Board",
|
|
184
|
+
[HF_SPYGLASS.style]: 'Watch Spyglass',
|
|
185
|
+
};
|
|
186
|
+
/** The model a Highfold quest prop draws with (frontend models that already exist), or null if not one of them. */
|
|
187
|
+
export function highfoldPropModel(prop) {
|
|
188
|
+
if (prop === HF_PROP.beacon)
|
|
189
|
+
return 'lwbeacontower';
|
|
190
|
+
if (prop === HF_PROP.beaconLit)
|
|
191
|
+
return 'lwbeacontowerlit';
|
|
192
|
+
if (prop === HF_PROP.stair)
|
|
193
|
+
return 'evchaingateclosed';
|
|
194
|
+
if (prop === HF_PROP.stairOpen)
|
|
195
|
+
return 'evchaingateopen';
|
|
196
|
+
if (prop === HF_PROP.bell)
|
|
197
|
+
return 'questbeacon';
|
|
198
|
+
if (prop === HF_PROP.tally)
|
|
199
|
+
return 'landingpost';
|
|
200
|
+
if (prop === HF_PROP.spyglass)
|
|
201
|
+
return 'lwspyglass';
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
/** The verb on the hover for each prop. */
|
|
205
|
+
export const HIGHFOLD_PROP_VERBS = {
|
|
206
|
+
[HF_PROP.beacon]: 'Light', [HF_PROP.beaconLit]: 'Inspect', [HF_PROP.stair]: 'Try', [HF_PROP.stairOpen]: 'Go down',
|
|
207
|
+
[HF_PROP.bell]: 'Inspect', [HF_PROP.tally]: 'Read', [HF_PROP.spyglass]: 'Look through',
|
|
208
|
+
};
|
|
209
|
+
const kit = (id, model, x, z, scale) => ({ id, kind: 'dreadmodel', style: `${model}-s`, x, z, ...(scale ? { scale } : {}) });
|
|
210
|
+
const lamp = (id, x, z) => kit(id, 'townlantern1x1', x, z);
|
|
211
|
+
/** The camp's pieces and working stations (Ashfall's layout, moved). No bank anywhere in Highfold. */
|
|
212
|
+
export const HIGHFOLD_CAMP_PIECES = [
|
|
213
|
+
kit('hf-smithy', 'bcsmithy', 2010, 336),
|
|
214
|
+
kit('hf-cookhouse', 'towncookhouse5x3', 2029, 336),
|
|
215
|
+
kit('hf-quench', 'hbtrough', 2003, 341),
|
|
216
|
+
kit('hf-racks', 'toolrack', 2003, 347),
|
|
217
|
+
kit('hf-logs', 'birchlogpile', 2003, 353),
|
|
218
|
+
kit('hf-crates', 'hbcrates', 2014, 359),
|
|
219
|
+
kit('hf-sacks', 'hubsack', 2016, 357),
|
|
220
|
+
kit('hf-cratestack', 'evcratestack', 2024, 360),
|
|
221
|
+
kit('hf-wagon', 'hbtinkerwagon', 2006, 359),
|
|
222
|
+
kit('hf-bench', 'hbbench', 2022, 347),
|
|
223
|
+
{ id: 'hf-barrel', kind: 'barrel', style: 'barrel', x: 2002, z: 356, scale: 1 },
|
|
224
|
+
lamp('hf-lamp-nw', 2001, 332),
|
|
225
|
+
lamp('hf-lamp-ne', 2039, 333),
|
|
226
|
+
lamp('hf-lamp-se', 2039, 355),
|
|
227
|
+
lamp('hf-lamp-sw', 2009, 357),
|
|
228
|
+
{ id: 'hf-furnace', kind: 'furnace', style: '', x: 2008, z: 345 },
|
|
229
|
+
{ id: 'hf-anvil', kind: 'anvil', style: '', x: 2011, z: 345 },
|
|
230
|
+
{ id: 'hf-bench-station', kind: 'workbench', style: 'face0', x: 2015, z: 347 },
|
|
231
|
+
{ id: 'hf-stove', kind: 'stove', style: '', x: 2029, z: 343 },
|
|
232
|
+
{ id: 'hf-fire', kind: 'campfire', style: 'beach-pit', x: 2021, z: 355, scale: 1 },
|
|
233
|
+
{ id: 'hf-board', kind: 'bountyboard', style: 'wall-s', x: 2018, z: 360 },
|
|
234
|
+
];
|
|
235
|
+
/** Dressing on the wall and in the ruins: banners at the gate and the stair, braziers (unlit stand-ins) at the Hollow Gallery's door. */
|
|
236
|
+
export const HIGHFOLD_DRESSING = [
|
|
237
|
+
kit('hf-banner-gate-w', 'westbanner', 2064, 374),
|
|
238
|
+
kit('hf-banner-gate-e', 'westbanner', 2074, 374),
|
|
239
|
+
kit('hf-banner-stair-n', 'westbanner', 1984, 324),
|
|
240
|
+
kit('hf-banner-stair-s', 'westbanner', 1984, 332),
|
|
241
|
+
kit('hf-brazier-gallery-w', 'evwatchbrazierlit', 2126, 346),
|
|
242
|
+
kit('hf-brazier-gallery-e', 'evwatchbrazierlit', 2132, 346),
|
|
243
|
+
kit('hf-brazier-keep-w', 'evwatchbrazierlit', 2081, 348),
|
|
244
|
+
kit('hf-brazier-keep-e', 'evwatchbrazierlit', 2089, 348),
|
|
245
|
+
];
|
|
246
|
+
/** The signs (the placard signpost). */
|
|
247
|
+
export const HIGHFOLD_SIGNS = [
|
|
248
|
+
{ id: 'hf-sign-approach', x: 2074, z: 396, text: 'Highfold Watch. The old wardens\' fortress above the Gate Court: a camp with a smith, a cook and a Bounty Board behind its gate, and a keep full of empty armour. Combat 36+. The Dwarf Pass below stays sealed.' },
|
|
249
|
+
{ id: 'hf-sign-gate', x: 2063, z: 376, text: 'THE HIGHFOLD GATE. Beyond it, the Watch Camp lies west and the broken keep north. Deserters hold the ground outside the walls and hollow guards the hall within: keep to the road.' },
|
|
250
|
+
{ id: 'hf-sign-beacons', x: 2069, z: 365, text: 'THE BEACON CHAIN. Five beacons on the south wall, lit in the order on the Wardens\' tally board, which changes every week. They catch only in the calm of the wind. A beacon out of turn puts them all out and rings the alarm bell.' },
|
|
251
|
+
{ id: 'hf-sign-camp', x: 2046, z: 351, text: 'Watch Camp. A smithy, a cookhouse and a Bounty Board for the heights. The cook buys what you cook. There is no bank here: carry what you need and bank in the towns.' },
|
|
252
|
+
{ id: 'hf-sign-platform', x: 1990, z: 331, text: 'THE VIEW PLATFORM. Below, the Gate Court; in the far cliff, the sealed Dwarf Pass. A painted mark on the flagstones shows where it lies. The Wardens\' Stair beside you opens when the beacon chain is lit.' },
|
|
253
|
+
{ id: 'hf-sign-hall', x: 2085, z: 348, text: 'THE GREAT HALL. The hall\'s armour stands empty and still walks. The Hollow Gallery lies east of the keep: its warden has not left his post in a hundred years.' },
|
|
254
|
+
];
|
|
255
|
+
/** The plan's six names (design sheet 5 invented others; see the plan file for the mapping). The cook lives in campTraders.ts. */
|
|
256
|
+
export const HIGHFOLD_FOLK_NAMES = {
|
|
257
|
+
captain: 'Captain Berrin Holt',
|
|
258
|
+
lamplighter: 'Lamplighter Nessa Tarn',
|
|
259
|
+
smith: 'Smith Dunmar Cole',
|
|
260
|
+
cook: 'Agnes Burr',
|
|
261
|
+
scout: 'Scout Ivo Dray',
|
|
262
|
+
chronicler: 'Chronicler Mabel Orrin',
|
|
263
|
+
};
|
|
264
|
+
const CAMP_PLACE = 'Watch Camp, Highfold Watch above the Gate Court';
|
|
265
|
+
/** The five residents who are not the cook (named residents on the default look, stationary). */
|
|
266
|
+
export const HIGHFOLD_FOLK = [
|
|
267
|
+
{
|
|
268
|
+
id: 'hf-captain',
|
|
269
|
+
name: HIGHFOLD_FOLK_NAMES.captain,
|
|
270
|
+
place: CAMP_PLACE,
|
|
271
|
+
x: 2038, z: 354, faceX: 2050, faceZ: 356, leash: 1,
|
|
272
|
+
speak: 'Berrin Holt, captain of what is left of the Watch. We hold the camp, the beacons and not much else. The keep behind the wall is full of the old garrison\'s armour, and it does not know the garrison is dead. If you are looking for work, the hounds and deserters outside the walls are the first of it.',
|
|
273
|
+
extras: [{ id: 'pass', label: 'The Pass', say: 'The Dwarf Pass is below us, in the far cliff over the Gate Court, and it is sealed. Nothing up here opens it. We watch it, that is all, as the wardens did.' }],
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
id: 'hf-lamplighter',
|
|
277
|
+
name: HIGHFOLD_FOLK_NAMES.lamplighter,
|
|
278
|
+
place: CAMP_PLACE,
|
|
279
|
+
x: 2040, z: 362, faceX: 2040, faceZ: 367, leash: 1,
|
|
280
|
+
speak: 'Nessa Tarn, lamplighter. Five beacons on the south wall, one tally board, and a wind that comes in over the cliffs every two minutes and puts every flame out. Light them in the order on the board while the wind is calm and the old Wardens\' Stair opens. Light one out of turn and the bell tolls and the whole hall wakes.',
|
|
281
|
+
extras: [{ id: 'wind', label: 'The wind', say: 'The wind runs on a clock: about a minute and a half of calm, then it rises, and then comes the gust and every flame on the wall goes out. Start straight after a gust and you have the longest calm. The rising gives you a few seconds of warning.' }],
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
id: 'hf-smith',
|
|
285
|
+
name: HIGHFOLD_FOLK_NAMES.smith,
|
|
286
|
+
place: CAMP_PLACE,
|
|
287
|
+
x: 2010, z: 342, faceX: 2010, faceZ: 345, leash: 1,
|
|
288
|
+
speak: 'Dunmar Cole, smith. The furnace came with the fortress and the anvil is free to anyone who brings something to hammer. I repair what the wall does to people. I sell nothing: bring me metal, not coin.',
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
id: 'hf-scout',
|
|
292
|
+
name: HIGHFOLD_FOLK_NAMES.scout,
|
|
293
|
+
place: 'The View Platform, Highfold Watch above the Gate Court',
|
|
294
|
+
x: 1988, z: 326, faceX: 1980, faceZ: 326, leash: 1,
|
|
295
|
+
speak: 'Ivo Dray, scout. From this platform you can see the whole Gate Court and the Iron Warden walking his round, and the Dwarf Pass in the far cliff. It is sealed and I have never seen it move. The gale eagles nest in the crags beyond the wall and they are the only thing that watches me back.',
|
|
296
|
+
extras: [{ id: 'stair', label: 'The Stair', say: 'The Wardens\' Stair is the door behind me. It opens when the beacon chain is lit: a long way down to the Gate Court, a short way back to the Iron Warden. It only goes down.' }],
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
id: 'hf-chronicler',
|
|
300
|
+
name: HIGHFOLD_FOLK_NAMES.chronicler,
|
|
301
|
+
place: CAMP_PLACE,
|
|
302
|
+
x: 2036, z: 348, faceX: 2035, faceZ: 346, leash: 1,
|
|
303
|
+
speak: 'Mabel Orrin, chronicler. I keep the Wardens\' tally board: it names the order of the beacon chain for the week, and I copy it out each Monday from the garrison\'s old book. The order is never the same twice running. The old wardens liked it that way. A beacon that could be lit by habit could be lit by an enemy.',
|
|
304
|
+
extras: [{ id: 'wardens', label: 'The wardens', say: 'The Watch held Highfold for the Hold and kept the Pass in sight. When the Hold sealed the Pass the garrison stayed, and over the years the armour in the hall stopped needing anyone inside it.' }],
|
|
305
|
+
},
|
|
306
|
+
];
|
|
307
|
+
export function highfoldFolkByName(name) {
|
|
308
|
+
return name ? HIGHFOLD_FOLK.find((p) => p.name === name) ?? null : null;
|
|
309
|
+
}
|
|
310
|
+
/** The camp's cook, which lives in CAMP_TRADERS (campTraders.ts) beside the other camps' cooks. */
|
|
311
|
+
export const HIGHFOLD_COOK = { id: 'camp-highfold', name: HIGHFOLD_FOLK_NAMES.cook, x: 2027, z: 346, faceX: 2029, faceZ: 343 };
|
|
312
|
+
// ---- Stands and texts ------------------------------------------------------------------------------------------------------------------
|
|
313
|
+
/** Standable tiles for teleports, smokes and the helper. */
|
|
314
|
+
export const HIGHFOLD_STANDS = {
|
|
315
|
+
approach: { x: 2069, z: 396 },
|
|
316
|
+
gate: { x: 2069, z: 376 },
|
|
317
|
+
camp: { x: 2030, z: 351 },
|
|
318
|
+
smithy: { x: 2010, z: 349 },
|
|
319
|
+
board: { x: 2020, z: 357 },
|
|
320
|
+
beacons: { x: 2069, z: 362 },
|
|
321
|
+
hall: { x: 2085, z: 340 },
|
|
322
|
+
gallery: { x: 2129, z: 336 },
|
|
323
|
+
platform: { x: 1989, z: 328 },
|
|
324
|
+
barracks: { x: 2118, z: 357 },
|
|
325
|
+
outerWatch: { x: 2040, z: 388 },
|
|
326
|
+
crag: { x: 2125, z: 388 },
|
|
327
|
+
};
|
|
328
|
+
export const HIGHFOLD_PLACE_TEXT = "Highfold Watch is the old wardens' fortress on the heights east of the Gate Court, on the open plateau above the Dwarf Road: a camp inside its wall with a smithy, a furnace, an anvil, a workbench, a cookhouse, a fire and a Bounty Board, a broken keep full of empty armour, five beacon towers on the south wall and a view platform over the Gate Court. There is no bank. The Dwarf Pass below stays sealed. On foot from Riversend Halt, go north over the open plateau and up the shore strip east of Cairn Shelf: the Highfold Road leads along the fortress's south edge to its gate.";
|
|
329
|
+
export const HIGHFOLD_CHAIN_TEXT = "Five beacons stand on Highfold's south wall. The Wardens' tally board names the order to light them in, drawn afresh every week, and they catch only in the calm of the wind, which runs on a two-minute clock: calm, a few seconds of rising wind, then a gust that puts every flame out. A beacon lit out of turn, or a gust that catches a part-lit chain, puts them all out and rings the alarm bell, and the hollow guards of the Great Hall wake. All five in order open the Wardens' Stair, a door down to the Gate Court, for two and a half minutes.";
|
|
330
|
+
export const HIGHFOLD_CAMP_DISCOVERY_ZONE = { id: 'highfold-camp', label: 'Watch Camp', coordinateFrame: 'world', ...HIGHFOLD_CAMP_BOX };
|
|
331
|
+
export const HIGHFOLD_PLATFORM_DISCOVERY_ZONE = { id: 'highfold-platform', label: 'The View Platform', coordinateFrame: 'world', ...HIGHFOLD_PLATFORM };
|
|
332
|
+
export const HIGHFOLD_UMBRELLA_DISCOVERY_ZONE = { id: HIGHFOLD_ID, label: HIGHFOLD_NAME, coordinateFrame: 'world', ...HIGHFOLD_BOX };
|
|
333
|
+
//# sourceMappingURL=highfoldWatch.js.map
|