lpc-forge 1.0.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.
- package/CREDITS.csv +22985 -0
- package/LICENSE +674 -0
- package/README.md +281 -0
- package/assets/music/.gitkeep +0 -0
- package/dist/character/batch.d.ts +17 -0
- package/dist/character/batch.js +48 -0
- package/dist/character/batch.js.map +1 -0
- package/dist/character/composer.d.ts +3 -0
- package/dist/character/composer.js +164 -0
- package/dist/character/composer.js.map +1 -0
- package/dist/character/definitions.d.ts +16 -0
- package/dist/character/definitions.js +116 -0
- package/dist/character/definitions.js.map +1 -0
- package/dist/character/presets.d.ts +6 -0
- package/dist/character/presets.js +246 -0
- package/dist/character/presets.js.map +1 -0
- package/dist/character/slicer.d.ts +8 -0
- package/dist/character/slicer.js +66 -0
- package/dist/character/slicer.js.map +1 -0
- package/dist/character/types.d.ts +48 -0
- package/dist/character/types.js +32 -0
- package/dist/character/types.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +938 -0
- package/dist/export/frames.d.ts +5 -0
- package/dist/export/frames.js +15 -0
- package/dist/export/frames.js.map +1 -0
- package/dist/export/godot.d.ts +17 -0
- package/dist/export/godot.js +464 -0
- package/dist/export/godot.js.map +1 -0
- package/dist/export/types.d.ts +11 -0
- package/dist/export/types.js +2 -0
- package/dist/export/types.js.map +1 -0
- package/dist/license.d.ts +49 -0
- package/dist/license.js +271 -0
- package/dist/map/cellular.d.ts +3 -0
- package/dist/map/cellular.js +191 -0
- package/dist/map/cellular.js.map +1 -0
- package/dist/map/dungeon.d.ts +3 -0
- package/dist/map/dungeon.js +238 -0
- package/dist/map/dungeon.js.map +1 -0
- package/dist/map/multifloor.d.ts +20 -0
- package/dist/map/multifloor.js +57 -0
- package/dist/map/multifloor.js.map +1 -0
- package/dist/map/overworld.d.ts +3 -0
- package/dist/map/overworld.js +205 -0
- package/dist/map/overworld.js.map +1 -0
- package/dist/map/town.d.ts +7 -0
- package/dist/map/town.js +181 -0
- package/dist/map/town.js.map +1 -0
- package/dist/map/types.d.ts +65 -0
- package/dist/map/types.js +16 -0
- package/dist/map/types.js.map +1 -0
- package/dist/map/wfc.d.ts +18 -0
- package/dist/map/wfc.js +192 -0
- package/dist/map/wfc.js.map +1 -0
- package/dist/tileset/atlas.d.ts +15 -0
- package/dist/tileset/atlas.js +55 -0
- package/dist/tileset/atlas.js.map +1 -0
- package/dist/tileset/registry.d.ts +12 -0
- package/dist/tileset/registry.js +71 -0
- package/dist/tileset/registry.js.map +1 -0
- package/dist/tileset/terrain.d.ts +3 -0
- package/dist/tileset/terrain.js +110 -0
- package/dist/tileset/terrain.js.map +1 -0
- package/dist/utils/credits.d.ts +11 -0
- package/dist/utils/credits.js +74 -0
- package/dist/utils/credits.js.map +1 -0
- package/dist/utils/image.d.ts +17 -0
- package/dist/utils/image.js +94 -0
- package/dist/utils/image.js.map +1 -0
- package/dist/utils/rng.d.ts +18 -0
- package/dist/utils/rng.js +48 -0
- package/dist/utils/rng.js.map +1 -0
- package/package.json +77 -0
package/dist/map/town.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { SeededRNG } from '../utils/rng.js';
|
|
2
|
+
import { TileType as TT } from './types.js';
|
|
3
|
+
const DEFAULT_BUILDINGS = 6;
|
|
4
|
+
const DEFAULT_MARKET_SIZE = 8;
|
|
5
|
+
export function generateTown(config) {
|
|
6
|
+
const { width, height, seed = Date.now(), buildings = DEFAULT_BUILDINGS, hasWall = false, marketSize = DEFAULT_MARKET_SIZE, } = config;
|
|
7
|
+
const rng = new SeededRNG(seed);
|
|
8
|
+
const numBuildings = Math.max(4, Math.min(8, buildings));
|
|
9
|
+
// Initialize grid with grass
|
|
10
|
+
const tiles = Array.from({ length: height }, () => Array(width).fill(TT.GRASS));
|
|
11
|
+
// Place trees around the perimeter
|
|
12
|
+
for (let y = 0; y < height; y++) {
|
|
13
|
+
for (let x = 0; x < width; x++) {
|
|
14
|
+
if (y < 3 || y >= height - 3 || x < 3 || x >= width - 3) {
|
|
15
|
+
if (rng.random() < 0.6)
|
|
16
|
+
tiles[y][x] = TT.TREE;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// Town wall (optional)
|
|
21
|
+
if (hasWall) {
|
|
22
|
+
const wMargin = 5;
|
|
23
|
+
for (let x = wMargin; x < width - wMargin; x++) {
|
|
24
|
+
tiles[wMargin][x] = TT.WALL;
|
|
25
|
+
tiles[height - wMargin - 1][x] = TT.WALL;
|
|
26
|
+
}
|
|
27
|
+
for (let y = wMargin; y < height - wMargin; y++) {
|
|
28
|
+
tiles[y][wMargin] = TT.WALL;
|
|
29
|
+
tiles[y][width - wMargin - 1] = TT.WALL;
|
|
30
|
+
}
|
|
31
|
+
// Gate openings
|
|
32
|
+
const midX = Math.floor(width / 2);
|
|
33
|
+
const midY = Math.floor(height / 2);
|
|
34
|
+
tiles[wMargin][midX] = TT.DOOR;
|
|
35
|
+
tiles[wMargin][midX + 1] = TT.DOOR;
|
|
36
|
+
tiles[height - wMargin - 1][midX] = TT.DOOR;
|
|
37
|
+
tiles[height - wMargin - 1][midX + 1] = TT.DOOR;
|
|
38
|
+
tiles[midY][wMargin] = TT.DOOR;
|
|
39
|
+
tiles[midY + 1][wMargin] = TT.DOOR;
|
|
40
|
+
tiles[midY][width - wMargin - 1] = TT.DOOR;
|
|
41
|
+
tiles[midY + 1][width - wMargin - 1] = TT.DOOR;
|
|
42
|
+
}
|
|
43
|
+
// Central town square
|
|
44
|
+
const sqSize = Math.min(marketSize, Math.floor(Math.min(width, height) / 4));
|
|
45
|
+
const sqX = Math.floor(width / 2 - sqSize / 2);
|
|
46
|
+
const sqY = Math.floor(height / 2 - sqSize / 2);
|
|
47
|
+
for (let dy = 0; dy < sqSize; dy++) {
|
|
48
|
+
for (let dx = 0; dx < sqSize; dx++) {
|
|
49
|
+
tiles[sqY + dy][sqX + dx] = TT.STONE;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Market stalls in the square (small 2x2 structures)
|
|
53
|
+
const stallCount = Math.min(4, Math.floor(sqSize / 3));
|
|
54
|
+
for (let s = 0; s < stallCount; s++) {
|
|
55
|
+
const sx = sqX + 1 + s * 2 + s;
|
|
56
|
+
const sy = sqY + 1;
|
|
57
|
+
if (sx + 1 < sqX + sqSize - 1 && sy + 1 < sqY + sqSize - 1) {
|
|
58
|
+
tiles[sy][sx] = TT.WALL;
|
|
59
|
+
tiles[sy][sx + 1] = TT.WALL;
|
|
60
|
+
tiles[sy + 1][sx] = TT.FLOOR;
|
|
61
|
+
tiles[sy + 1][sx + 1] = TT.FLOOR;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Place buildings around the square
|
|
65
|
+
const rooms = [];
|
|
66
|
+
const buildingPositions = [];
|
|
67
|
+
const zones = [
|
|
68
|
+
{ baseX: sqX - 10, baseY: sqY - 10 }, // top-left
|
|
69
|
+
{ baseX: sqX + sqSize + 2, baseY: sqY - 10 }, // top-right
|
|
70
|
+
{ baseX: sqX - 10, baseY: sqY + sqSize + 2 }, // bottom-left
|
|
71
|
+
{ baseX: sqX + sqSize + 2, baseY: sqY + sqSize + 2 }, // bottom-right
|
|
72
|
+
{ baseX: sqX - 10, baseY: sqY }, // left
|
|
73
|
+
{ baseX: sqX + sqSize + 2, baseY: sqY }, // right
|
|
74
|
+
{ baseX: sqX, baseY: sqY - 10 }, // top
|
|
75
|
+
{ baseX: sqX, baseY: sqY + sqSize + 2 }, // bottom
|
|
76
|
+
];
|
|
77
|
+
for (let b = 0; b < numBuildings && b < zones.length; b++) {
|
|
78
|
+
const zone = zones[b];
|
|
79
|
+
const bw = rng.randomInt(4, 7);
|
|
80
|
+
const bh = rng.randomInt(4, 6);
|
|
81
|
+
const bx = Math.max(6, Math.min(width - bw - 3, zone.baseX + rng.randomInt(0, 3)));
|
|
82
|
+
const by = Math.max(6, Math.min(height - bh - 3, zone.baseY + rng.randomInt(0, 3)));
|
|
83
|
+
// Check for overlap
|
|
84
|
+
const overlaps = buildingPositions.some((bp) => bx < bp.x + bp.w + 1 &&
|
|
85
|
+
bx + bw + 1 > bp.x &&
|
|
86
|
+
by < bp.y + bp.h + 1 &&
|
|
87
|
+
by + bh + 1 > bp.y);
|
|
88
|
+
if (overlaps)
|
|
89
|
+
continue;
|
|
90
|
+
buildingPositions.push({ x: bx, y: by, w: bw, h: bh });
|
|
91
|
+
// Draw building: walls on edges, floor inside
|
|
92
|
+
for (let dy = 0; dy < bh; dy++) {
|
|
93
|
+
for (let dx = 0; dx < bw; dx++) {
|
|
94
|
+
const ty = by + dy;
|
|
95
|
+
const tx = bx + dx;
|
|
96
|
+
if (ty >= 0 && ty < height && tx >= 0 && tx < width) {
|
|
97
|
+
if (dy === 0 || dy === bh - 1 || dx === 0 || dx === bw - 1) {
|
|
98
|
+
tiles[ty][tx] = TT.WALL;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
tiles[ty][tx] = TT.FLOOR;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Door on the south wall
|
|
107
|
+
const doorX = bx + Math.floor(bw / 2);
|
|
108
|
+
if (by + bh - 1 < height) {
|
|
109
|
+
tiles[by + bh - 1][doorX] = TT.DOOR;
|
|
110
|
+
}
|
|
111
|
+
rooms.push({
|
|
112
|
+
id: rooms.length,
|
|
113
|
+
x: bx,
|
|
114
|
+
y: by,
|
|
115
|
+
width: bw,
|
|
116
|
+
height: bh,
|
|
117
|
+
connections: [],
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// Roads connecting buildings to the town square center
|
|
121
|
+
const sqCenterX = sqX + Math.floor(sqSize / 2);
|
|
122
|
+
const sqCenterY = sqY + Math.floor(sqSize / 2);
|
|
123
|
+
for (const bp of buildingPositions) {
|
|
124
|
+
const doorX = bp.x + Math.floor(bp.w / 2);
|
|
125
|
+
const doorY = bp.y + bp.h;
|
|
126
|
+
carvePath(tiles, doorX, doorY, sqCenterX, sqCenterY, width, height);
|
|
127
|
+
}
|
|
128
|
+
// Connect rooms sequentially
|
|
129
|
+
for (let i = 0; i < rooms.length - 1; i++) {
|
|
130
|
+
rooms[i].connections.push(rooms[i + 1].id);
|
|
131
|
+
rooms[i + 1].connections.push(rooms[i].id);
|
|
132
|
+
}
|
|
133
|
+
// POIs
|
|
134
|
+
const pois = [];
|
|
135
|
+
pois.push({ x: sqCenterX, y: sqCenterY, type: 'spawn', label: 'Town Square' });
|
|
136
|
+
for (let i = 0; i < rooms.length && i < 3; i++) {
|
|
137
|
+
const r = rooms[i];
|
|
138
|
+
pois.push({
|
|
139
|
+
x: r.x + Math.floor(r.width / 2),
|
|
140
|
+
y: r.y + Math.floor(r.height / 2),
|
|
141
|
+
type: 'npc',
|
|
142
|
+
label: `Shopkeeper ${i + 1}`,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
if (rooms.length > 0) {
|
|
146
|
+
const lastRoom = rooms[rooms.length - 1];
|
|
147
|
+
pois.push({
|
|
148
|
+
x: lastRoom.x + 1,
|
|
149
|
+
y: lastRoom.y + 1,
|
|
150
|
+
type: 'treasure',
|
|
151
|
+
label: 'Town Treasury',
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
width,
|
|
156
|
+
height,
|
|
157
|
+
tiles,
|
|
158
|
+
rooms,
|
|
159
|
+
seed,
|
|
160
|
+
pois,
|
|
161
|
+
spawnPoint: { x: sqCenterX, y: sqCenterY },
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function carvePath(tiles, x1, y1, x2, y2, width, height) {
|
|
165
|
+
let x = x1;
|
|
166
|
+
let y = y1;
|
|
167
|
+
while (x !== x2 || y !== y2) {
|
|
168
|
+
if (x !== x2) {
|
|
169
|
+
x += x < x2 ? 1 : -1;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
y += y < y2 ? 1 : -1;
|
|
173
|
+
}
|
|
174
|
+
if (y >= 0 && y < height && x >= 0 && x < width) {
|
|
175
|
+
if (tiles[y][x] === TT.GRASS || tiles[y][x] === TT.TREE) {
|
|
176
|
+
tiles[y][x] = TT.PATH;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=town.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"town.js","sourceRoot":"","sources":["../../src/map/town.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export interface MapConfig {
|
|
2
|
+
width: number;
|
|
3
|
+
height: number;
|
|
4
|
+
seed?: string | number;
|
|
5
|
+
}
|
|
6
|
+
export interface DungeonConfig extends MapConfig {
|
|
7
|
+
roomMinSize?: number;
|
|
8
|
+
roomMaxSize?: number;
|
|
9
|
+
maxRooms?: number;
|
|
10
|
+
corridorWidth?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface CellularConfig extends MapConfig {
|
|
13
|
+
birthLimit?: number;
|
|
14
|
+
deathLimit?: number;
|
|
15
|
+
iterations?: number;
|
|
16
|
+
initialDensity?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface OverworldConfig extends MapConfig {
|
|
19
|
+
biomes?: string[];
|
|
20
|
+
temperature?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface PointOfInterest {
|
|
23
|
+
x: number;
|
|
24
|
+
y: number;
|
|
25
|
+
type: 'spawn' | 'treasure' | 'npc' | 'exit' | 'entrance' | 'boss';
|
|
26
|
+
label?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare enum TileType {
|
|
29
|
+
VOID = 0,
|
|
30
|
+
FLOOR = 1,
|
|
31
|
+
WALL = 2,
|
|
32
|
+
DOOR = 3,
|
|
33
|
+
CORRIDOR = 4,
|
|
34
|
+
WATER = 5,
|
|
35
|
+
GRASS = 6,
|
|
36
|
+
TREE = 7,
|
|
37
|
+
PATH = 8,
|
|
38
|
+
SAND = 9,
|
|
39
|
+
STONE = 10,
|
|
40
|
+
BRIDGE = 11
|
|
41
|
+
}
|
|
42
|
+
export interface Room {
|
|
43
|
+
x: number;
|
|
44
|
+
y: number;
|
|
45
|
+
width: number;
|
|
46
|
+
height: number;
|
|
47
|
+
id: number;
|
|
48
|
+
connections: number[];
|
|
49
|
+
}
|
|
50
|
+
export interface GeneratedMap {
|
|
51
|
+
width: number;
|
|
52
|
+
height: number;
|
|
53
|
+
tiles: TileType[][];
|
|
54
|
+
rooms: Room[];
|
|
55
|
+
seed: string | number;
|
|
56
|
+
pois: PointOfInterest[];
|
|
57
|
+
spawnPoint?: {
|
|
58
|
+
x: number;
|
|
59
|
+
y: number;
|
|
60
|
+
};
|
|
61
|
+
exitPoint?: {
|
|
62
|
+
x: number;
|
|
63
|
+
y: number;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export var TileType;
|
|
2
|
+
(function (TileType) {
|
|
3
|
+
TileType[TileType["VOID"] = 0] = "VOID";
|
|
4
|
+
TileType[TileType["FLOOR"] = 1] = "FLOOR";
|
|
5
|
+
TileType[TileType["WALL"] = 2] = "WALL";
|
|
6
|
+
TileType[TileType["DOOR"] = 3] = "DOOR";
|
|
7
|
+
TileType[TileType["CORRIDOR"] = 4] = "CORRIDOR";
|
|
8
|
+
TileType[TileType["WATER"] = 5] = "WATER";
|
|
9
|
+
TileType[TileType["GRASS"] = 6] = "GRASS";
|
|
10
|
+
TileType[TileType["TREE"] = 7] = "TREE";
|
|
11
|
+
TileType[TileType["PATH"] = 8] = "PATH";
|
|
12
|
+
TileType[TileType["SAND"] = 9] = "SAND";
|
|
13
|
+
TileType[TileType["STONE"] = 10] = "STONE";
|
|
14
|
+
TileType[TileType["BRIDGE"] = 11] = "BRIDGE";
|
|
15
|
+
})(TileType || (TileType = {}));
|
|
16
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/map/types.ts"],"names":[],"mappings":"AAgCA,MAAM,CAAN,IAAY,QAaX;AAbD,WAAY,QAAQ;IAClB,uCAAQ,CAAA;IACR,yCAAS,CAAA;IACT,uCAAQ,CAAA;IACR,uCAAQ,CAAA;IACR,+CAAY,CAAA;IACZ,yCAAS,CAAA;IACT,yCAAS,CAAA;IACT,uCAAQ,CAAA;IACR,uCAAQ,CAAA;IACR,uCAAQ,CAAA;IACR,0CAAU,CAAA;IACV,4CAAW,CAAA;AACb,CAAC,EAbW,QAAQ,KAAR,QAAQ,QAanB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { MapConfig, GeneratedMap } from './types.js';
|
|
2
|
+
import { type TileType } from './types.js';
|
|
3
|
+
export interface WFCTileDef {
|
|
4
|
+
name: string;
|
|
5
|
+
tile: TileType;
|
|
6
|
+
weight: number;
|
|
7
|
+
/** Which tiles are allowed in each direction [up, right, down, left] */
|
|
8
|
+
adjacency: [string[], string[], string[], string[]];
|
|
9
|
+
}
|
|
10
|
+
/** Default terrain adjacency rules */
|
|
11
|
+
export declare const DEFAULT_WFC_TILES: WFCTileDef[];
|
|
12
|
+
interface WFCConfig extends MapConfig {
|
|
13
|
+
tiles?: WFCTileDef[];
|
|
14
|
+
maxRetries?: number;
|
|
15
|
+
}
|
|
16
|
+
/** Generate a map using Wave Function Collapse */
|
|
17
|
+
export declare function generateWFC(config: WFCConfig): GeneratedMap;
|
|
18
|
+
export {};
|
package/dist/map/wfc.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { SeededRNG } from '../utils/rng.js';
|
|
2
|
+
import { TileType as TT } from './types.js';
|
|
3
|
+
/** Default terrain adjacency rules */
|
|
4
|
+
export const DEFAULT_WFC_TILES = [
|
|
5
|
+
{
|
|
6
|
+
name: 'grass',
|
|
7
|
+
tile: TT.GRASS,
|
|
8
|
+
weight: 4,
|
|
9
|
+
adjacency: [
|
|
10
|
+
['grass', 'tree', 'path', 'sand'],
|
|
11
|
+
['grass', 'tree', 'path', 'sand'],
|
|
12
|
+
['grass', 'tree', 'path', 'sand'],
|
|
13
|
+
['grass', 'tree', 'path', 'sand'],
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: 'tree',
|
|
18
|
+
tile: TT.TREE,
|
|
19
|
+
weight: 2,
|
|
20
|
+
adjacency: [
|
|
21
|
+
['grass', 'tree'],
|
|
22
|
+
['grass', 'tree'],
|
|
23
|
+
['grass', 'tree'],
|
|
24
|
+
['grass', 'tree'],
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'water',
|
|
29
|
+
tile: TT.WATER,
|
|
30
|
+
weight: 2,
|
|
31
|
+
adjacency: [
|
|
32
|
+
['water', 'sand'],
|
|
33
|
+
['water', 'sand'],
|
|
34
|
+
['water', 'sand'],
|
|
35
|
+
['water', 'sand'],
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'sand',
|
|
40
|
+
tile: TT.SAND,
|
|
41
|
+
weight: 1,
|
|
42
|
+
adjacency: [
|
|
43
|
+
['grass', 'sand', 'water', 'path'],
|
|
44
|
+
['grass', 'sand', 'water', 'path'],
|
|
45
|
+
['grass', 'sand', 'water', 'path'],
|
|
46
|
+
['grass', 'sand', 'water', 'path'],
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'path',
|
|
51
|
+
tile: TT.PATH,
|
|
52
|
+
weight: 1,
|
|
53
|
+
adjacency: [
|
|
54
|
+
['grass', 'path', 'sand', 'stone'],
|
|
55
|
+
['grass', 'path', 'sand', 'stone'],
|
|
56
|
+
['grass', 'path', 'sand', 'stone'],
|
|
57
|
+
['grass', 'path', 'sand', 'stone'],
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'stone',
|
|
62
|
+
tile: TT.STONE,
|
|
63
|
+
weight: 1,
|
|
64
|
+
adjacency: [
|
|
65
|
+
['stone', 'grass', 'path'],
|
|
66
|
+
['stone', 'grass', 'path'],
|
|
67
|
+
['stone', 'grass', 'path'],
|
|
68
|
+
['stone', 'grass', 'path'],
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
/** Generate a map using Wave Function Collapse */
|
|
73
|
+
export function generateWFC(config) {
|
|
74
|
+
const { width, height, seed = Date.now(), tiles: tileDefs = DEFAULT_WFC_TILES, maxRetries = 10, } = config;
|
|
75
|
+
const rng = new SeededRNG(seed);
|
|
76
|
+
const tileNames = tileDefs.map((t) => t.name);
|
|
77
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
78
|
+
const result = tryCollapse(width, height, tileDefs, tileNames, rng);
|
|
79
|
+
if (result) {
|
|
80
|
+
return {
|
|
81
|
+
width,
|
|
82
|
+
height,
|
|
83
|
+
tiles: result,
|
|
84
|
+
rooms: [],
|
|
85
|
+
seed,
|
|
86
|
+
pois: [],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Fallback: fill with grass
|
|
91
|
+
const fallback = Array.from({ length: height }, () => Array(width).fill(TT.GRASS));
|
|
92
|
+
return { width, height, tiles: fallback, rooms: [], seed, pois: [] };
|
|
93
|
+
}
|
|
94
|
+
function tryCollapse(width, height, tileDefs, tileNames, rng) {
|
|
95
|
+
// Each cell has a set of possible tile indices
|
|
96
|
+
const grid = Array.from({ length: height }, () => Array.from({ length: width }, () => new Set(tileDefs.map((_, i) => i))));
|
|
97
|
+
const totalCells = width * height;
|
|
98
|
+
for (let step = 0; step < totalCells; step++) {
|
|
99
|
+
// Find cell with lowest entropy (fewest possibilities)
|
|
100
|
+
let minEntropy = Infinity;
|
|
101
|
+
let minCells = [];
|
|
102
|
+
for (let y = 0; y < height; y++) {
|
|
103
|
+
for (let x = 0; x < width; x++) {
|
|
104
|
+
const size = grid[y][x].size;
|
|
105
|
+
if (size <= 1)
|
|
106
|
+
continue;
|
|
107
|
+
if (size < minEntropy) {
|
|
108
|
+
minEntropy = size;
|
|
109
|
+
minCells = [{ x, y }];
|
|
110
|
+
}
|
|
111
|
+
else if (size === minEntropy) {
|
|
112
|
+
minCells.push({ x, y });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (minCells.length === 0)
|
|
117
|
+
break; // All collapsed
|
|
118
|
+
// Pick random cell among minimum entropy
|
|
119
|
+
const cell = rng.pick(minCells);
|
|
120
|
+
// Collapse: pick one tile weighted by weight
|
|
121
|
+
const possible = [...grid[cell.y][cell.x]];
|
|
122
|
+
const weights = possible.map((i) => tileDefs[i].weight);
|
|
123
|
+
const totalWeight = weights.reduce((a, b) => a + b, 0);
|
|
124
|
+
let r = rng.randomFloat(0, totalWeight);
|
|
125
|
+
let chosen = possible[0];
|
|
126
|
+
for (let i = 0; i < possible.length; i++) {
|
|
127
|
+
r -= weights[i];
|
|
128
|
+
if (r <= 0) {
|
|
129
|
+
chosen = possible[i];
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
grid[cell.y][cell.x] = new Set([chosen]);
|
|
134
|
+
// Propagate constraints
|
|
135
|
+
if (!propagate(grid, cell.x, cell.y, width, height, tileDefs, tileNames)) {
|
|
136
|
+
return null; // Contradiction
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Convert to tile types
|
|
140
|
+
const result = Array.from({ length: height }, (_, y) => Array.from({ length: width }, (_, x) => {
|
|
141
|
+
const possible = [...grid[y][x]];
|
|
142
|
+
if (possible.length === 0)
|
|
143
|
+
return TT.VOID;
|
|
144
|
+
return tileDefs[possible[0]].tile;
|
|
145
|
+
}));
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
function propagate(grid, startX, startY, width, height, tileDefs, tileNames) {
|
|
149
|
+
const stack = [[startX, startY]];
|
|
150
|
+
// Directions: [dy, dx, dirIndex, oppositeIndex]
|
|
151
|
+
const dirs = [
|
|
152
|
+
[-1, 0, 0, 2], // up
|
|
153
|
+
[0, 1, 1, 3], // right
|
|
154
|
+
[1, 0, 2, 0], // down
|
|
155
|
+
[0, -1, 3, 1], // left
|
|
156
|
+
];
|
|
157
|
+
while (stack.length > 0) {
|
|
158
|
+
const [cx, cy] = stack.pop();
|
|
159
|
+
const currentPossible = grid[cy][cx];
|
|
160
|
+
for (const [dy, dx, dirIdx, oppIdx] of dirs) {
|
|
161
|
+
const nx = cx + dx;
|
|
162
|
+
const ny = cy + dy;
|
|
163
|
+
if (nx < 0 || nx >= width || ny < 0 || ny >= height)
|
|
164
|
+
continue;
|
|
165
|
+
const neighborPossible = grid[ny][nx];
|
|
166
|
+
if (neighborPossible.size <= 1 && grid[ny][nx].size > 0)
|
|
167
|
+
continue;
|
|
168
|
+
// Compute allowed tiles for neighbor based on current cell
|
|
169
|
+
const allowed = new Set();
|
|
170
|
+
for (const tileIdx of currentPossible) {
|
|
171
|
+
const adjNames = tileDefs[tileIdx].adjacency[dirIdx];
|
|
172
|
+
for (const name of adjNames) {
|
|
173
|
+
const idx = tileNames.indexOf(name);
|
|
174
|
+
if (idx !== -1 && neighborPossible.has(idx)) {
|
|
175
|
+
// Also check reverse: neighbor must allow current tile in opposite direction
|
|
176
|
+
if (tileDefs[idx].adjacency[oppIdx].includes(tileDefs[tileIdx].name)) {
|
|
177
|
+
allowed.add(idx);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (allowed.size === 0)
|
|
183
|
+
return false; // Contradiction
|
|
184
|
+
if (allowed.size < neighborPossible.size) {
|
|
185
|
+
grid[ny][nx] = allowed;
|
|
186
|
+
stack.push([nx, ny]);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=wfc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wfc.js","sourceRoot":"","sources":["../../src/map/wfc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface AtlasResult {
|
|
2
|
+
imagePath: string;
|
|
3
|
+
metadataPath: string;
|
|
4
|
+
tilePositions: Record<string, {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
}>;
|
|
10
|
+
columns: number;
|
|
11
|
+
rows: number;
|
|
12
|
+
}
|
|
13
|
+
/** Build a texture atlas from individual tile images */
|
|
14
|
+
export declare function buildAtlas(tiles: Record<string, string>, // tileName → file path
|
|
15
|
+
tileSize: number, outputPath: string): Promise<AtlasResult>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
/** Build a texture atlas from individual tile images */
|
|
5
|
+
export async function buildAtlas(tiles, // tileName → file path
|
|
6
|
+
tileSize, outputPath) {
|
|
7
|
+
const tileEntries = Object.entries(tiles);
|
|
8
|
+
const count = tileEntries.length;
|
|
9
|
+
const columns = Math.ceil(Math.sqrt(count));
|
|
10
|
+
const rows = Math.ceil(count / columns);
|
|
11
|
+
const atlasWidth = columns * tileSize;
|
|
12
|
+
const atlasHeight = rows * tileSize;
|
|
13
|
+
const composites = [];
|
|
14
|
+
const positions = {};
|
|
15
|
+
for (let i = 0; i < tileEntries.length; i++) {
|
|
16
|
+
const [name, filePath] = tileEntries[i];
|
|
17
|
+
const col = i % columns;
|
|
18
|
+
const row = Math.floor(i / columns);
|
|
19
|
+
const x = col * tileSize;
|
|
20
|
+
const y = row * tileSize;
|
|
21
|
+
try {
|
|
22
|
+
const buf = await sharp(filePath).resize(tileSize, tileSize).png().toBuffer();
|
|
23
|
+
composites.push({ input: buf, top: y, left: x });
|
|
24
|
+
positions[name] = { x, y, width: tileSize, height: tileSize };
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Skip missing tiles
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
await mkdir(join(outputPath, '..'), { recursive: true });
|
|
31
|
+
const atlasBuffer = await sharp({
|
|
32
|
+
create: {
|
|
33
|
+
width: atlasWidth,
|
|
34
|
+
height: atlasHeight,
|
|
35
|
+
channels: 4,
|
|
36
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
.png()
|
|
40
|
+
.composite(composites)
|
|
41
|
+
.toBuffer();
|
|
42
|
+
const imagePath = outputPath.endsWith('.png') ? outputPath : `${outputPath}.png`;
|
|
43
|
+
const metadataPath = imagePath.replace('.png', '.json');
|
|
44
|
+
await writeFile(imagePath, atlasBuffer);
|
|
45
|
+
const metadata = { tileSize, columns, rows, tiles: positions };
|
|
46
|
+
await writeFile(metadataPath, JSON.stringify(metadata, null, 2));
|
|
47
|
+
return {
|
|
48
|
+
imagePath,
|
|
49
|
+
metadataPath,
|
|
50
|
+
tilePositions: positions,
|
|
51
|
+
columns,
|
|
52
|
+
rows,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=atlas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atlas.js","sourceRoot":"","sources":["../../src/tileset/atlas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TileType } from '../map/types.js';
|
|
2
|
+
export interface TilesetManifest {
|
|
3
|
+
name: string;
|
|
4
|
+
tileSize: number;
|
|
5
|
+
tiles: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
/** Generate default placeholder tiles programmatically */
|
|
8
|
+
export declare function generateDefaultTileset(outputDir: string): Promise<TilesetManifest>;
|
|
9
|
+
/** Load a tileset manifest from a directory */
|
|
10
|
+
export declare function loadTileset(tilesetDir: string): Promise<TilesetManifest>;
|
|
11
|
+
/** Map TileType enum to tile name */
|
|
12
|
+
export declare function tileTypeToName(t: TileType): string;
|