@datamoc/mw_games 0.30.0 → 0.33.0

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.
Files changed (71) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +1 -1
  3. package/api-surface.json +384 -0
  4. package/dist/assets/index.d.ts +2 -0
  5. package/dist/assets/index.d.ts.map +1 -1
  6. package/dist/assets/index.js +1 -0
  7. package/dist/assets/index.js.map +1 -1
  8. package/dist/assets/svg.d.ts +87 -0
  9. package/dist/assets/svg.d.ts.map +1 -0
  10. package/dist/assets/svg.js +162 -0
  11. package/dist/assets/svg.js.map +1 -0
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/mw_games.global.js +41 -41
  17. package/dist/mwl/fengari.d.ts +12 -6
  18. package/dist/mwl/fengari.d.ts.map +1 -1
  19. package/dist/mwl/fengari.js +56 -70
  20. package/dist/mwl/fengari.js.map +1 -1
  21. package/dist/mwl/runtime.d.ts +13 -0
  22. package/dist/mwl/runtime.d.ts.map +1 -1
  23. package/dist/mwl/runtime.js +72 -4
  24. package/dist/mwl/runtime.js.map +1 -1
  25. package/dist/mwl/schema.d.ts.map +1 -1
  26. package/dist/mwl/schema.js +4 -1
  27. package/dist/mwl/schema.js.map +1 -1
  28. package/dist/roguelike/Cave.d.ts +109 -0
  29. package/dist/roguelike/Cave.d.ts.map +1 -0
  30. package/dist/roguelike/Cave.js +192 -0
  31. package/dist/roguelike/Cave.js.map +1 -0
  32. package/dist/roguelike/Overworld.d.ts +82 -0
  33. package/dist/roguelike/Overworld.d.ts.map +1 -0
  34. package/dist/roguelike/Overworld.js +306 -0
  35. package/dist/roguelike/Overworld.js.map +1 -0
  36. package/dist/roguelike/index.d.ts +4 -0
  37. package/dist/roguelike/index.d.ts.map +1 -1
  38. package/dist/roguelike/index.js +2 -0
  39. package/dist/roguelike/index.js.map +1 -1
  40. package/dist/skeleton/index.d.ts +131 -0
  41. package/dist/skeleton/index.d.ts.map +1 -0
  42. package/dist/skeleton/index.js +206 -0
  43. package/dist/skeleton/index.js.map +1 -0
  44. package/dist/testing/SceneControls.d.ts +35 -0
  45. package/dist/testing/SceneControls.d.ts.map +1 -0
  46. package/dist/testing/SceneControls.js +49 -0
  47. package/dist/testing/SceneControls.js.map +1 -0
  48. package/dist/testing/index.d.ts +2 -0
  49. package/dist/testing/index.d.ts.map +1 -1
  50. package/dist/testing/index.js +1 -0
  51. package/dist/testing/index.js.map +1 -1
  52. package/dist/two-d/render/Camera.d.ts +13 -3
  53. package/dist/two-d/render/Camera.d.ts.map +1 -1
  54. package/dist/two-d/render/Camera.js +35 -25
  55. package/dist/two-d/render/Camera.js.map +1 -1
  56. package/dist/two-d/render/SkeletalSprite.d.ts +118 -0
  57. package/dist/two-d/render/SkeletalSprite.d.ts.map +1 -0
  58. package/dist/two-d/render/SkeletalSprite.js +189 -0
  59. package/dist/two-d/render/SkeletalSprite.js.map +1 -0
  60. package/dist/two-d/render/SpriteMotion.d.ts +121 -0
  61. package/dist/two-d/render/SpriteMotion.d.ts.map +1 -0
  62. package/dist/two-d/render/SpriteMotion.js +193 -0
  63. package/dist/two-d/render/SpriteMotion.js.map +1 -0
  64. package/dist/two-d/render/index.d.ts +4 -0
  65. package/dist/two-d/render/index.d.ts.map +1 -1
  66. package/dist/two-d/render/index.js +2 -0
  67. package/dist/two-d/render/index.js.map +1 -1
  68. package/dist/version.d.ts +1 -1
  69. package/dist/version.js +1 -1
  70. package/package.json +7 -2
  71. package/sbom.cdx.json +222 -222
@@ -0,0 +1,192 @@
1
+ import * as Random from '../core/Random.js';
2
+ import { DUNGEON_KINDS } from './generate.js';
3
+ import { Level } from './Level.js';
4
+ /** the four orthogonal neighbours, the square-grid cave's whole step set */
5
+ function neighbours(x, y) {
6
+ return [
7
+ [x, y - 1],
8
+ [x, y + 1],
9
+ [x - 1, y],
10
+ [x + 1, y],
11
+ ];
12
+ }
13
+ export function generateCave(options) {
14
+ const { width, height } = options;
15
+ if (width < 5 || height < 5)
16
+ throw new Error('a cave needs at least 5x5 cells');
17
+ if (options.chambers.length < 1)
18
+ throw new Error('a cave needs at least one chamber');
19
+ const wall = options.wall ?? 0;
20
+ const floor = options.floor ?? 1;
21
+ const kinds = options.kinds ?? [];
22
+ const level = new Level(width, height, [...DUNGEON_KINDS, ...kinds], wall);
23
+ const at = (x, y) => y * width + x;
24
+ const inner = (x, y) => level.insideWithBorder(x, y);
25
+ const open = new Uint8Array(width * height);
26
+ const carve = (x, y) => {
27
+ if (inner(x, y))
28
+ open[at(x, y)] = 1;
29
+ };
30
+ Random.push(options.seed);
31
+ try {
32
+ const centres = new Map();
33
+ const cellsById = new Map();
34
+ for (const chamber of options.chambers) {
35
+ if (chamber.size < 1)
36
+ throw new Error(`cave chamber ${chamber.id} needs at least one cell`);
37
+ const cx = Random.range(Math.max(1, chamber.xRange[0]), Math.min(width - 2, chamber.xRange[1]));
38
+ const cy = Random.range(Math.max(1, chamber.yRange[0]), Math.min(height - 2, chamber.yRange[1]));
39
+ centres.set(chamber.id, { x: cx, y: cy });
40
+ // random growth: absorb frontier cells until `size` are carved; `jagged` is the
41
+ // chance a step picks any frontier cell instead of the one nearest the centre
42
+ const cells = [{ x: cx, y: cy }];
43
+ const seen = new Set([at(cx, cy)]);
44
+ const frontier = [];
45
+ const push = (x, y) => {
46
+ for (const [nx, ny] of neighbours(x, y)) {
47
+ if (!inner(nx, ny) || seen.has(at(nx, ny)))
48
+ continue;
49
+ seen.add(at(nx, ny));
50
+ frontier.push([nx, ny]);
51
+ }
52
+ };
53
+ push(cx, cy);
54
+ while (cells.length < chamber.size && frontier.length) {
55
+ let pick = 0;
56
+ if (Random.int(100) < (chamber.jagged ?? 0)) {
57
+ pick = Random.int(frontier.length);
58
+ }
59
+ else {
60
+ let best = Infinity;
61
+ for (let index = 0; index < frontier.length; index++) {
62
+ const distance = Math.abs(frontier[index][0] - cx) + Math.abs(frontier[index][1] - cy);
63
+ if (distance < best) {
64
+ best = distance;
65
+ pick = index;
66
+ }
67
+ }
68
+ }
69
+ const [nx, ny] = frontier.splice(pick, 1)[0];
70
+ cells.push({ x: nx, y: ny });
71
+ push(nx, ny);
72
+ }
73
+ for (const cell of cells)
74
+ carve(cell.x, cell.y);
75
+ cellsById.set(chamber.id, cells);
76
+ }
77
+ // a passage is a biased random walk from one chamber centre to another
78
+ const walk = (from, to, widthHexes, windiness) => {
79
+ let x = from.x;
80
+ let y = from.y;
81
+ for (let step = 0; step < width * height && (x !== to.x || y !== to.y); step++) {
82
+ carve(x, y);
83
+ if (widthHexes > 1)
84
+ for (const [nx, ny] of neighbours(x, y).slice(0, widthHexes - 1))
85
+ carve(nx, ny);
86
+ const steps = neighbours(x, y).filter(([nx, ny]) => inner(nx, ny));
87
+ let next = steps[0];
88
+ if (Random.int(100) < windiness) {
89
+ next = steps[Random.int(steps.length)];
90
+ }
91
+ else {
92
+ let best = Infinity;
93
+ for (const option of steps) {
94
+ const distance = (option[0] - to.x) ** 2 + (option[1] - to.y) ** 2;
95
+ if (distance < best) {
96
+ best = distance;
97
+ next = option;
98
+ }
99
+ }
100
+ }
101
+ [x, y] = next;
102
+ }
103
+ carve(to.x, to.y);
104
+ };
105
+ for (const chamber of options.chambers) {
106
+ for (const passage of chamber.passages) {
107
+ const from = centres.get(chamber.id);
108
+ const to = centres.get(passage.to);
109
+ if (!from || !to)
110
+ throw new Error(`cave passage ${chamber.id} -> ${passage.to} names no chamber`);
111
+ if (Random.int(100) >= (passage.chance ?? 100))
112
+ continue;
113
+ walk(from, to, Math.max(1, passage.width ?? 1), passage.windiness ?? 0);
114
+ }
115
+ }
116
+ // everything the game named must be walkable, whatever the rolls did
117
+ const mustBeClear = options.mustBeClear ?? [];
118
+ for (const point of mustBeClear) {
119
+ carve(point.x, point.y);
120
+ for (const [nx, ny] of neighbours(point.x, point.y))
121
+ carve(nx, ny);
122
+ }
123
+ // force-join every chamber centre and mustBeClear cell to the first chamber, so the
124
+ // cave is always connected even where `chance` left a passage out
125
+ const first = centres.get(options.chambers[0].id);
126
+ if (first) {
127
+ const reachable = () => {
128
+ const found = new Set([at(first.x, first.y)]);
129
+ const queue = [[first.x, first.y]];
130
+ while (queue.length) {
131
+ const [x, y] = queue.pop();
132
+ for (const [nx, ny] of neighbours(x, y)) {
133
+ if (!inner(nx, ny) || !open[at(nx, ny)] || found.has(at(nx, ny)))
134
+ continue;
135
+ found.add(at(nx, ny));
136
+ queue.push([nx, ny]);
137
+ }
138
+ }
139
+ return found;
140
+ };
141
+ for (const target of [...centres.values(), ...mustBeClear]) {
142
+ if (!inner(target.x, target.y) || reachable().has(at(target.x, target.y)))
143
+ continue;
144
+ walk(target, first, 1, 15);
145
+ }
146
+ }
147
+ const reserved = new Set();
148
+ const starts = [];
149
+ for (const start of options.starts ?? []) {
150
+ const centre = centres.get(start.chamber);
151
+ if (!centre)
152
+ throw new Error(`cave start ${start.side} names no chamber`);
153
+ carve(centre.x, centre.y);
154
+ reserved.add(at(centre.x, centre.y));
155
+ if (start.ring)
156
+ for (const [nx, ny] of neighbours(centre.x, centre.y)) {
157
+ if (!inner(nx, ny))
158
+ continue;
159
+ carve(nx, ny);
160
+ reserved.add(at(nx, ny));
161
+ }
162
+ starts.push({ side: start.side, x: centre.x, y: centre.y });
163
+ }
164
+ const villages = [];
165
+ const density = options.villageDensity ?? 0;
166
+ if (density > 0) {
167
+ const candidates = [];
168
+ for (let index = 0; index < open.length; index++)
169
+ if (open[index] && !reserved.has(index))
170
+ candidates.push(index);
171
+ const wanted = Math.floor((candidates.length * density) / 1000);
172
+ for (let placed = 0; placed < wanted && candidates.length; placed++) {
173
+ const pick = Random.int(candidates.length);
174
+ const index = candidates.splice(pick, 1)[0];
175
+ villages.push({ x: index % width, y: Math.floor(index / width) });
176
+ }
177
+ }
178
+ for (let index = 0; index < open.length; index++)
179
+ if (open[index])
180
+ level.set(index % width, Math.floor(index / width), floor);
181
+ return {
182
+ level,
183
+ chambers: [...cellsById.entries()].map(([id, cells]) => ({ id, centre: centres.get(id), cells })),
184
+ starts,
185
+ villages,
186
+ };
187
+ }
188
+ finally {
189
+ Random.pop();
190
+ }
191
+ }
192
+ //# sourceMappingURL=Cave.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Cave.js","sourceRoot":"","sources":["../../src/roguelike/Cave.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * An overworld map: a whole realm as plain tile data.
3
+ *
4
+ * The world-map counterpart to `generateDungeon` and `generateCave`: elevation and moisture
5
+ * fields from seeded value noise classify each cell into water, plains, forest, hills,
6
+ * mountains, desert or swamp (the `seaLevel` knob decides how much is sea); rivers run from
7
+ * high ground down to the sea or a lake, merging when they meet and never crossing a
8
+ * mountain ridge (a ridge stops a river as a lake instead); settlements place themselves by
9
+ * suitability (near water, on buildable ground, spaced apart) and join into a road network
10
+ * that prefers flat ground and fords a river where it must cross one; points of interest
11
+ * carry a `leadsTo` id a game feeds its `Overworld` locations with; and every cell carries a
12
+ * coarse region id so encounter tables and names can hang off a region instead of a cell.
13
+ *
14
+ * Deterministic: the same seed gives the same realm on every platform, drawn from the
15
+ * framework `Random` stack. Sizes up to a few hundred tiles a side generate on load; a
16
+ * bigger realm is a `threads.spawn` task like any other long job.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { generateOverworld } from '@datamoc/mw_games/roguelike';
21
+ *
22
+ * const realm = generateOverworld({ width: 96, height: 64, seed: 42 });
23
+ * console.log(realm.terrain[0]); // 'water' | 'plains' | 'forest' | ...
24
+ * console.log(realm.settlements.length); // roads join every one of them
25
+ * ```
26
+ */
27
+ export type OverworldTerrain = 'water' | 'plains' | 'forest' | 'hills' | 'mountains' | 'desert' | 'swamp';
28
+ export interface OverworldOptions {
29
+ width: number;
30
+ height: number;
31
+ seed: number;
32
+ /** elevation below which a cell is sea; 0..1, defaults to 0.4 */
33
+ seaLevel?: number;
34
+ /** river sources attempted on high ground; defaults to `width * height / 600` */
35
+ rivers?: number;
36
+ /** settlements to place by suitability; defaults to `width * height / 500` */
37
+ settlements?: number;
38
+ /** points of interest to place; defaults to `width * height / 900` */
39
+ pointsOfInterest?: number;
40
+ /** the coarse region grid's cell side, in tiles; defaults to 12 */
41
+ regionSize?: number;
42
+ /** how stretched the noise is: larger values give broader landmasses; defaults to 6 */
43
+ noiseScale?: number;
44
+ }
45
+ export interface OverworldSettlement {
46
+ x: number;
47
+ y: number;
48
+ kind: 'village' | 'town' | 'castle';
49
+ }
50
+ export interface OverworldInterest {
51
+ x: number;
52
+ y: number;
53
+ kind: 'ruin' | 'shrine' | 'dungeon';
54
+ /** the id a game's `Overworld` location this point leads to carries */
55
+ leadsTo: string;
56
+ }
57
+ export interface OverworldResult {
58
+ /** row-major terrain ids, `width * height` entries */
59
+ terrain: OverworldTerrain[];
60
+ /** row-major elevation, 0..1, the field `terrain` was classified from */
61
+ elevation: number[];
62
+ /** row-major moisture, 0..1 */
63
+ moisture: number[];
64
+ /** each river's cells from its source to its mouth or lake */
65
+ rivers: Array<Array<{
66
+ x: number;
67
+ y: number;
68
+ }>>;
69
+ /** each road's cells, settlement to settlement; river crossings are the ford sites */
70
+ roads: Array<Array<{
71
+ x: number;
72
+ y: number;
73
+ }>>;
74
+ settlements: OverworldSettlement[];
75
+ pointsOfInterest: OverworldInterest[];
76
+ /** coarse region id per cell, row-major; region r's cells share `(y / regionSize) * cols + (x / regionSize)` */
77
+ regions: number[];
78
+ /** how many columns the coarse region grid has */
79
+ regionColumns: number;
80
+ }
81
+ export declare function generateOverworld(options: OverworldOptions): OverworldResult;
82
+ //# sourceMappingURL=Overworld.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Overworld.d.ts","sourceRoot":"","sources":["../../src/roguelike/Overworld.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE1G,MAAM,WAAW,gBAAgB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IAEb,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uFAAuF;IACvF,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IACnC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IACjC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IACpC,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC/B,sDAAsD;IACtD,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,yEAAyE;IACzE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,8DAA8D;IAC9D,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IAC/C,sFAAsF;IACtF,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IAC9C,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,gBAAgB,EAAE,iBAAiB,EAAE,CAAC;IACtC,gHAAgH;IAChH,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kDAAkD;IAClD,aAAa,EAAE,MAAM,CAAC;CACtB;AAyDD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CA0J5E"}
@@ -0,0 +1,306 @@
1
+ import * as Random from '../core/Random.js';
2
+ /** seeded value noise: a lattice of random values, smoothly interpolated, a few octaves */
3
+ function valueNoise(random, width, height, scale) {
4
+ const latticeSide = (side) => Math.max(2, Math.ceil(side / scale) + 2);
5
+ const columns = latticeSide(width);
6
+ const rows = latticeSide(height);
7
+ const lattice = new Float64Array(columns * rows);
8
+ for (let index = 0; index < lattice.length; index++)
9
+ lattice[index] = random();
10
+ const smooth = (t) => t * t * (3 - 2 * t);
11
+ const field = new Array(width * height).fill(0);
12
+ for (let octave = 0; octave < 3; octave++) {
13
+ const factor = 1 << octave;
14
+ const weight = 1 / (factor * factor);
15
+ for (let y = 0; y < height; y++) {
16
+ for (let x = 0; x < width; x++) {
17
+ const gx = (x / scale) * factor;
18
+ const gy = (y / scale) * factor;
19
+ const x0 = Math.floor(gx) % (columns - 1);
20
+ const y0 = Math.floor(gy) % (rows - 1);
21
+ const fx = smooth(gx - Math.floor(gx));
22
+ const fy = smooth(gy - Math.floor(gy));
23
+ const at = (lx, ly) => lattice[((y0 + ly) % rows) * columns + ((x0 + lx) % columns)];
24
+ const top = at(0, 0) * (1 - fx) + at(1, 0) * fx;
25
+ const bottom = at(0, 1) * (1 - fx) + at(1, 1) * fx;
26
+ field[y * width + x] += (top * (1 - fy) + bottom * fy) * weight;
27
+ }
28
+ }
29
+ }
30
+ const total = 1 + 1 / 4 + 1 / 16;
31
+ for (let index = 0; index < field.length; index++)
32
+ field[index] /= total;
33
+ return field;
34
+ }
35
+ const EIGHT = [
36
+ [0, -1],
37
+ [0, 1],
38
+ [-1, 0],
39
+ [1, 0],
40
+ [-1, -1],
41
+ [1, -1],
42
+ [-1, 1],
43
+ [1, 1],
44
+ ];
45
+ /** how much a road dislikes crossing each terrain; water is only crossable at a ford */
46
+ const ROAD_COST = {
47
+ plains: 1,
48
+ forest: 3,
49
+ hills: 5,
50
+ desert: 2,
51
+ swamp: 6,
52
+ water: 24,
53
+ mountains: 40,
54
+ };
55
+ export function generateOverworld(options) {
56
+ const { width, height } = options;
57
+ if (width < 16 || height < 16)
58
+ throw new Error('an overworld needs at least 16x16 tiles');
59
+ const seaLevel = options.seaLevel ?? 0.4;
60
+ if (!(seaLevel > 0 && seaLevel < 1))
61
+ throw new Error('seaLevel must be between 0 and 1');
62
+ const scale = options.noiseScale ?? 6;
63
+ const at = (x, y) => y * width + x;
64
+ const inside = (x, y) => x >= 0 && y >= 0 && x < width && y < height;
65
+ Random.push(options.seed);
66
+ try {
67
+ //a terrain field from elevation and moisture, both seeded; landmasses read as
68
+ //coherent shapes rather than scattered peaks because the noise octaves overlap
69
+ const elevation = valueNoise(() => Random.float(), width, height, scale);
70
+ const moisture = valueNoise(() => Random.float(), width, height, scale * 1.5);
71
+ const terrain = new Array(width * height);
72
+ const classify = (x, y) => {
73
+ const index = at(x, y);
74
+ const up = elevation[index];
75
+ const wet = moisture[index];
76
+ if (up < seaLevel)
77
+ return 'water';
78
+ if (up > 0.78)
79
+ return 'mountains';
80
+ if (up > 0.62)
81
+ return 'hills';
82
+ if (wet < 0.3)
83
+ return 'desert';
84
+ if (wet > 0.72)
85
+ return up < seaLevel + 0.08 ? 'swamp' : 'forest';
86
+ return 'plains';
87
+ };
88
+ for (let y = 0; y < height; y++)
89
+ for (let x = 0; x < width; x++)
90
+ terrain[at(x, y)] = classify(x, y);
91
+ //rivers: walk downhill from high ground to the sea or a lake; two rivers that
92
+ //meet merge (the second stops on the first), and a ridge that stops a walk
93
+ //drowns its basin cell into a lake instead of crossing the mountains
94
+ const riverCells = new Set();
95
+ const rivers = [];
96
+ const riverTarget = options.rivers ?? Math.max(1, Math.floor((width * height) / 600));
97
+ const highGround = [];
98
+ for (let index = 0; index < terrain.length; index++)
99
+ if (elevation[index] > 0.7 && terrain[index] !== 'water')
100
+ highGround.push(index);
101
+ for (let attempt = 0; attempt < riverTarget * 4 && rivers.length < riverTarget; attempt++) {
102
+ if (highGround.length === 0)
103
+ break;
104
+ const sourceIndex = highGround[Random.int(highGround.length)];
105
+ const path = [];
106
+ let x = sourceIndex % width;
107
+ let y = Math.floor(sourceIndex / width);
108
+ const walked = new Set();
109
+ for (let step = 0; step < width + height; step++) {
110
+ const index = at(x, y);
111
+ if (riverCells.has(index) || terrain[index] === 'water') {
112
+ if (path.length > 0)
113
+ path.push({ x, y });
114
+ break;
115
+ }
116
+ path.push({ x, y });
117
+ walked.add(index);
118
+ let best;
119
+ for (const [dx, dy] of EIGHT) {
120
+ const nx = x + dx;
121
+ const ny = y + dy;
122
+ if (!inside(nx, ny))
123
+ continue;
124
+ const candidate = { x: nx, y: ny, up: elevation[at(nx, ny)] };
125
+ if (!best || candidate.up < best.up)
126
+ best = candidate;
127
+ }
128
+ if (!best || best.up >= elevation[at(x, y)]) {
129
+ //no way down: a ridge or a basin. Drown the cell as a lake and stop here
130
+ terrain[at(x, y)] = 'water';
131
+ break;
132
+ }
133
+ [x, y] = [best.x, best.y];
134
+ }
135
+ if (path.length >= 2) {
136
+ for (const cell of path)
137
+ riverCells.add(at(cell.x, cell.y));
138
+ rivers.push(path);
139
+ }
140
+ }
141
+ //settlements: buildable ground near water, spaced apart; a castle prefers hills,
142
+ //a town the plains, and everything else reads as a village
143
+ const settlements = [];
144
+ const nearWater = (x, y) => {
145
+ for (let dy = -3; dy <= 3; dy++)
146
+ for (let dx = -3; dx <= 3; dx++) {
147
+ const nx = x + dx;
148
+ const ny = y + dy;
149
+ if (inside(nx, ny) && terrain[at(nx, ny)] === 'water')
150
+ return true;
151
+ }
152
+ return false;
153
+ };
154
+ const spaced = (x, y, distance) => settlements.every((settlement) => Math.abs(settlement.x - x) + Math.abs(settlement.y - y) >= distance);
155
+ const wanted = options.settlements ?? Math.max(2, Math.floor((width * height) / 500));
156
+ for (let attempt = 0; attempt < wanted * 60 && settlements.length < wanted; attempt++) {
157
+ const x = Random.int(width);
158
+ const y = Random.int(height);
159
+ const kind = terrain[at(x, y)];
160
+ if ((kind !== 'plains' && kind !== 'hills' && kind !== 'forest') || !nearWater(x, y))
161
+ continue;
162
+ if (!spaced(x, y, 8))
163
+ continue;
164
+ settlements.push({ x, y, kind: kind === 'hills' ? 'castle' : 'town' });
165
+ }
166
+ for (const settlement of settlements)
167
+ if (settlement.kind === 'town' && Random.int(2) === 0)
168
+ settlement.kind = 'village';
169
+ //roads: a Dijkstra tree over the settlements, preferring flat ground; a water or
170
+ //river cell on a route is a ford or bridge site, which is why water is expensive
171
+ //rather than impassable here
172
+ const roads = [];
173
+ const from = settlements[0];
174
+ if (from) {
175
+ const connected = [from];
176
+ const pending = settlements.slice(1);
177
+ while (pending.length) {
178
+ let bestRoute;
179
+ for (const to of pending) {
180
+ for (const start of connected) {
181
+ const path = roadBetween(terrain, width, height, start, to);
182
+ if (path && (!bestRoute || path.length < bestRoute.path.length))
183
+ bestRoute = { path, to };
184
+ }
185
+ }
186
+ if (!bestRoute)
187
+ break;
188
+ roads.push(bestRoute.path);
189
+ connected.push(bestRoute.to);
190
+ pending.splice(pending.indexOf(bestRoute.to), 1);
191
+ }
192
+ }
193
+ //points of interest away from settlements, each leading somewhere
194
+ const pointsOfInterest = [];
195
+ const wantedInterest = options.pointsOfInterest ?? Math.max(1, Math.floor((width * height) / 900));
196
+ for (let attempt = 0; attempt < wantedInterest * 40 && pointsOfInterest.length < wantedInterest; attempt++) {
197
+ const x = Random.int(width);
198
+ const y = Random.int(height);
199
+ const kind = terrain[at(x, y)];
200
+ if (kind === 'water' || kind === 'mountains')
201
+ continue;
202
+ if (!spaced(x, y, 6))
203
+ continue;
204
+ const kinds = ['ruin', 'shrine', 'dungeon'];
205
+ const interest = kinds[Random.int(kinds.length)];
206
+ pointsOfInterest.push({
207
+ x,
208
+ y,
209
+ kind: interest,
210
+ leadsTo: `overworld-${interest}-${pointsOfInterest.length}`,
211
+ });
212
+ }
213
+ //regions: a coarse id per cell, so a game hangs encounters and names off a region
214
+ const regionSize = Math.max(2, options.regionSize ?? 12);
215
+ const regionColumns = Math.ceil(width / regionSize);
216
+ const regions = new Array(width * height);
217
+ for (let y = 0; y < height; y++)
218
+ for (let x = 0; x < width; x++)
219
+ regions[at(x, y)] = Math.floor(y / regionSize) * regionColumns + Math.floor(x / regionSize);
220
+ return { terrain, elevation, moisture, rivers, roads, settlements, pointsOfInterest, regions, regionColumns };
221
+ }
222
+ finally {
223
+ Random.pop();
224
+ }
225
+ }
226
+ /** one road: Dijkstra from one settlement to another over per-terrain costs */
227
+ function roadBetween(terrain, width, height, from, to) {
228
+ const at = (x, y) => y * width + x;
229
+ const inside = (x, y) => x >= 0 && y >= 0 && x < width && y < height;
230
+ const total = width * height;
231
+ const distance = new Float64Array(total).fill(Infinity);
232
+ const previous = new Int32Array(total).fill(-1);
233
+ const start = at(from.x, from.y);
234
+ const goal = at(to.x, to.y);
235
+ distance[start] = 0;
236
+ //a binary heap keyed by distance: with per-terrain costs this stays fast at the
237
+ //'few hundred tiles a side' sizes an overworld is allowed to load with
238
+ const heap = [start];
239
+ const inHeap = new Uint8Array(total);
240
+ const swapDown = (position) => {
241
+ while (true) {
242
+ const left = position * 2 + 1;
243
+ const right = left + 1;
244
+ let smallest = position;
245
+ if (left < heap.length && distance[heap[left]] < distance[heap[smallest]])
246
+ smallest = left;
247
+ if (right < heap.length && distance[heap[right]] < distance[heap[smallest]])
248
+ smallest = right;
249
+ if (smallest === position)
250
+ return;
251
+ [heap[position], heap[smallest]] = [heap[smallest], heap[position]];
252
+ position = smallest;
253
+ }
254
+ };
255
+ const pop = () => {
256
+ const top = heap[0];
257
+ const last = heap.pop();
258
+ if (heap.length) {
259
+ heap[0] = last;
260
+ swapDown(0);
261
+ }
262
+ inHeap[top] = 0;
263
+ return top;
264
+ };
265
+ const push = (cell) => {
266
+ heap.push(cell);
267
+ inHeap[cell] = 1;
268
+ let position = heap.length - 1;
269
+ while (position > 0) {
270
+ const parent = (position - 1) >> 1;
271
+ if (distance[heap[parent]] <= distance[heap[position]])
272
+ break;
273
+ [heap[position], heap[parent]] = [heap[parent], heap[position]];
274
+ position = parent;
275
+ }
276
+ };
277
+ while (heap.length) {
278
+ const current = pop();
279
+ if (current === goal) {
280
+ const path = [];
281
+ for (let cell = goal; cell !== -1; cell = previous[cell])
282
+ path.push({ x: cell % width, y: Math.floor(cell / width) });
283
+ return path.reverse();
284
+ }
285
+ const cx = current % width;
286
+ const cy = Math.floor(current / width);
287
+ for (const [dx, dy] of EIGHT) {
288
+ const nx = cx + dx;
289
+ const ny = cy + dy;
290
+ if (!inside(nx, ny))
291
+ continue;
292
+ const next = at(nx, ny);
293
+ if (distance[current] === Infinity)
294
+ continue;
295
+ const step = ROAD_COST[terrain[next]] * (dx !== 0 && dy !== 0 ? 1.5 : 1);
296
+ if (distance[current] + step < distance[next]) {
297
+ distance[next] = distance[current] + step;
298
+ previous[next] = current;
299
+ if (!inHeap[next])
300
+ push(next);
301
+ }
302
+ }
303
+ }
304
+ return undefined;
305
+ }
306
+ //# sourceMappingURL=Overworld.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Overworld.js","sourceRoot":"","sources":["../../src/roguelike/Overworld.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,10 @@
1
1
  export { Level, WALL, FLOOR, rectCenter, rectsOverlap } from './Level.ts';
2
2
  export type { TerrainKind, Rect, LevelShape } from './Level.ts';
3
3
  export { generateDungeon, generateDungeonGraph, findFreeCell, furthestRoom, DUNGEON_KINDS } from './generate.ts';
4
+ export { generateCave } from './Cave.ts';
5
+ export { generateOverworld } from './Overworld.ts';
6
+ export type { OverworldOptions, OverworldResult, OverworldTerrain, OverworldSettlement, OverworldInterest, } from './Overworld.ts';
7
+ export type { CaveOptions, CaveResult, CaveChamber, CavePassage, CaveStart } from './Cave.ts';
4
8
  export type { DungeonOptions, DungeonGenerationHooks, RoomEdge, DungeonResult } from './generate.ts';
5
9
  export { hallBuilder, eligibleBuilders, pickBuilder } from './RoomBuilders.ts';
6
10
  export type { RoomBuilder } from './RoomBuilders.ts';