@datamoc/mw_games 0.15.0 → 0.17.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/CHANGELOG.md +154 -1
- package/README.md +21 -1
- package/dist/ai/lua.d.ts.map +1 -1
- package/dist/ai/lua.js +1 -0
- package/dist/ai/lua.js.map +1 -1
- package/dist/core/ActionJournal.d.ts +5 -0
- package/dist/core/ActionJournal.d.ts.map +1 -1
- package/dist/core/ActionJournal.js +12 -1
- package/dist/core/ActionJournal.js.map +1 -1
- package/dist/core/Clone.d.ts +31 -0
- package/dist/core/Clone.d.ts.map +1 -0
- package/dist/core/Clone.js +84 -0
- package/dist/core/Clone.js.map +1 -0
- package/dist/core/Collection.d.ts +1 -0
- package/dist/core/Collection.d.ts.map +1 -1
- package/dist/core/Collection.js +6 -2
- package/dist/core/Collection.js.map +1 -1
- package/dist/core/HttpTransport.d.ts +17 -0
- package/dist/core/HttpTransport.d.ts.map +1 -1
- package/dist/core/HttpTransport.js +61 -0
- package/dist/core/HttpTransport.js.map +1 -1
- package/dist/core/Multiplayer.d.ts +9 -0
- package/dist/core/Multiplayer.d.ts.map +1 -1
- package/dist/core/Multiplayer.js +48 -4
- package/dist/core/Multiplayer.js.map +1 -1
- package/dist/core/News.d.ts.map +1 -1
- package/dist/core/News.js +1 -2
- package/dist/core/News.js.map +1 -1
- package/dist/core/Sanitize.d.ts +19 -0
- package/dist/core/Sanitize.d.ts.map +1 -1
- package/dist/core/Sanitize.js +37 -0
- package/dist/core/Sanitize.js.map +1 -1
- package/dist/core/Save.d.ts +18 -9
- package/dist/core/Save.d.ts.map +1 -1
- package/dist/core/Save.js +37 -21
- package/dist/core/Save.js.map +1 -1
- package/dist/core/SaveSync.js +4 -4
- package/dist/core/SaveSync.js.map +1 -1
- package/dist/core/Settings.d.ts.map +1 -1
- package/dist/core/Settings.js +2 -1
- package/dist/core/Settings.js.map +1 -1
- package/dist/core/State.d.ts.map +1 -1
- package/dist/core/State.js +8 -7
- package/dist/core/State.js.map +1 -1
- package/dist/core/StoredValue.d.ts +1 -1
- package/dist/core/StoredValue.d.ts.map +1 -1
- package/dist/core/StoredValue.js +3 -2
- package/dist/core/StoredValue.js.map +1 -1
- package/dist/core/Telemetry.d.ts +19 -1
- package/dist/core/Telemetry.d.ts.map +1 -1
- package/dist/core/Telemetry.js +26 -1
- package/dist/core/Telemetry.js.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/mw_games.global.js +107 -107
- package/dist/mwl/MapFile.js +11 -1
- package/dist/mwl/MapFile.js.map +1 -1
- package/dist/mwl/expression.js +38 -5
- package/dist/mwl/expression.js.map +1 -1
- package/dist/mwl/fengari.d.ts +8 -0
- package/dist/mwl/fengari.d.ts.map +1 -1
- package/dist/mwl/fengari.js +72 -2
- package/dist/mwl/fengari.js.map +1 -1
- package/dist/mwl/persistence.d.ts.map +1 -1
- package/dist/mwl/persistence.js +2 -1
- package/dist/mwl/persistence.js.map +1 -1
- package/dist/mwl/runtime.d.ts.map +1 -1
- package/dist/mwl/runtime.js +6 -1
- package/dist/mwl/runtime.js.map +1 -1
- package/dist/rpg/Marshal.d.ts.map +1 -1
- package/dist/rpg/Marshal.js +13 -0
- package/dist/rpg/Marshal.js.map +1 -1
- package/dist/simulation/Campaign.d.ts.map +1 -1
- package/dist/simulation/Campaign.js +9 -5
- package/dist/simulation/Campaign.js.map +1 -1
- package/dist/simulation/Harness.d.ts.map +1 -1
- package/dist/simulation/Harness.js +2 -1
- package/dist/simulation/Harness.js.map +1 -1
- package/dist/simulation/Runtime.d.ts +10 -0
- package/dist/simulation/Runtime.d.ts.map +1 -1
- package/dist/simulation/Runtime.js +25 -4
- package/dist/simulation/Runtime.js.map +1 -1
- package/dist/testing/index.d.ts +105 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +134 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/two-d/render/RpgmAutotile.d.ts +217 -0
- package/dist/two-d/render/RpgmAutotile.d.ts.map +1 -1
- package/dist/two-d/render/RpgmAutotile.js +756 -0
- package/dist/two-d/render/RpgmAutotile.js.map +1 -1
- package/dist/two-d/render/TileMap.d.ts +90 -0
- package/dist/two-d/render/TileMap.d.ts.map +1 -1
- package/dist/two-d/render/TileMap.js +319 -31
- package/dist/two-d/render/TileMap.js.map +1 -1
- package/dist/two-d/render/index.d.ts +3 -3
- package/dist/two-d/render/index.d.ts.map +1 -1
- package/dist/two-d/render/index.js +1 -1
- package/dist/two-d/render/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +90 -25
- package/sbom.cdx.json +5589 -0
- package/tools/benchmark-browser.d.mts +33 -0
- package/tools/benchmark-browser.mjs +163 -0
- package/tools/benchmark-history.d.mts +8 -0
- package/tools/benchmark-history.mjs +31 -0
- package/tools/browser-smoke.d.mts +30 -0
- package/tools/browser-smoke.mjs +167 -0
- package/tools/bundle-size.d.mts +11 -0
- package/tools/bundle-size.mjs +138 -0
- package/tools/csp.d.mts +7 -0
- package/tools/csp.mjs +56 -0
- package/tools/emit-page.d.mts +44 -0
- package/tools/emit-page.mjs +188 -0
- package/tools/extract-rgssad.d.mts +5 -0
- package/tools/extract-rgssad.mjs +64 -0
- package/tools/find-chrome.d.mts +7 -0
- package/tools/find-chrome.mjs +104 -0
- package/tools/i18n-edit.d.mts +29 -0
- package/tools/i18n-edit.mjs +748 -0
- package/tools/make-example-assets.d.mts +2 -0
- package/tools/make-example-assets.mjs +727 -0
- package/tools/multiplayer-server.d.mts +27 -0
- package/tools/multiplayer-server.mjs +195 -0
- package/tools/mwl.mjs +1 -0
- package/tools/sbom.d.mts +83 -0
- package/tools/sbom.mjs +330 -0
- package/tools/vendored/rgssad-wasm/LICENSE-MIT +21 -0
- package/tools/vendored/rgssad-wasm/README.md +15 -0
- package/tools/vendored/rgssad-wasm/package.json +17 -0
- package/tools/vendored/rgssad-wasm/rgssad_wasm.d.ts +41 -0
- package/tools/vendored/rgssad-wasm/rgssad_wasm.js +6 -0
- package/tools/vendored/rgssad-wasm/rgssad_wasm_bg.js +399 -0
- package/tools/vendored/rgssad-wasm/rgssad_wasm_bg.wasm +0 -0
- package/tools/vendored/rgssad-wasm/rgssad_wasm_bg.wasm.d.ts +17 -0
- package/tools/vite.d.mts +17 -0
- package/tools/vite.mjs +83 -0
|
@@ -107,4 +107,760 @@ export class RpgmAutotileAtlas {
|
|
|
107
107
|
this.cache.clear();
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* The first MV tile id of each autotile family (A1-A4): slot 0 covers
|
|
112
|
+
* 2048-2815, slot 1 covers 2816-4351, slot 2 covers 4352-5887 and slot 3
|
|
113
|
+
* covers 5888-8191. Measured against real A-sheets rather than assumed.
|
|
114
|
+
*/
|
|
115
|
+
export const RPGM_AUTOTILE_SLOT_BASES = [2048, 2816, 4352, 5888];
|
|
116
|
+
/**
|
|
117
|
+
* How many MV tile ids each family holds: 16, 32, 32 and 48 kinds of
|
|
118
|
+
* 48 shapes each. A sheet holding fewer cells than its slot needs is a
|
|
119
|
+
* truncated custom sheet, not a different layout.
|
|
120
|
+
*/
|
|
121
|
+
export const RPGM_AUTOTILE_SLOT_COUNTS = [768, 1536, 1536, 2304];
|
|
122
|
+
/**
|
|
123
|
+
* Which MV autotile family a raw map tile id belongs to, or null when the id
|
|
124
|
+
* is not an autotile at all (an `EMPTY` cell, a static B-E tile, an A5 tile).
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```ts
|
|
128
|
+
* import {
|
|
129
|
+
* rpgmAutotileSlot,
|
|
130
|
+
* RPGM_AUTOTILE_SLOT_BASES,
|
|
131
|
+
* RPGM_AUTOTILE_SLOT_COUNTS,
|
|
132
|
+
* } from '@datamoc/mw_games/two-d/render';
|
|
133
|
+
*
|
|
134
|
+
* console.log(rpgmAutotileSlot(2048)); // 0 - the first A1 tile
|
|
135
|
+
* console.log(rpgmAutotileSlot(3000)); // 1 - inside the A2 range
|
|
136
|
+
* console.log(rpgmAutotileSlot(42)); // null - a static tile, not an autotile
|
|
137
|
+
* console.log(rpgmAutotileSlot(-1)); // null - EMPTY reads as blank, never as a slot
|
|
138
|
+
* console.log(RPGM_AUTOTILE_SLOT_BASES[0]); // 2048 - where slot 0 starts
|
|
139
|
+
* console.log(RPGM_AUTOTILE_SLOT_COUNTS[0]); // 768 - 16 kinds times 48 shapes
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export function rpgmAutotileSlot(tile) {
|
|
143
|
+
if (!Number.isInteger(tile))
|
|
144
|
+
return null;
|
|
145
|
+
for (let slot = 0; slot < 4; slot++) {
|
|
146
|
+
if (tile >= RPGM_AUTOTILE_SLOT_BASES[slot] &&
|
|
147
|
+
tile < RPGM_AUTOTILE_SLOT_BASES[slot] + RPGM_AUTOTILE_SLOT_COUNTS[slot]) {
|
|
148
|
+
return slot;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The standard MV floor-autotile shape table (48 shapes), for slots 0-1:
|
|
155
|
+
* which four atlas quadrants each baked shape assembles, in 24px source
|
|
156
|
+
* cells. Entries are `[x, y]` offsets, row-major `[topLeft, topRight,
|
|
157
|
+
* bottomLeft, bottomRight]`, exactly the shape numbering MV bakes into map
|
|
158
|
+
* tile ids (`shape = (tile - base) % 48`).
|
|
159
|
+
*
|
|
160
|
+
* Functional interop data, the same category as `BLOB_SHAPES`: every game
|
|
161
|
+
* reading MV maps needs these numbers, so they live here once rather than
|
|
162
|
+
* pasted into every port.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* import { RPGM_FLOOR_AUTOTILE_TABLE, RPGM_WALL_AUTOTILE_TABLE } from '@datamoc/mw_games/two-d/render';
|
|
167
|
+
*
|
|
168
|
+
* console.log(RPGM_FLOOR_AUTOTILE_TABLE.length); // 48 - one entry per baked shape
|
|
169
|
+
* console.log(RPGM_WALL_AUTOTILE_TABLE.length); // 16 - walls cycle every 16 shapes
|
|
170
|
+
* console.log(RPGM_FLOOR_AUTOTILE_TABLE[47]); // [[0,0],[1,0],[0,1],[1,1]] - the full tile
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
export const RPGM_FLOOR_AUTOTILE_TABLE = [
|
|
174
|
+
[
|
|
175
|
+
[2, 4],
|
|
176
|
+
[1, 4],
|
|
177
|
+
[2, 3],
|
|
178
|
+
[1, 3],
|
|
179
|
+
],
|
|
180
|
+
[
|
|
181
|
+
[2, 0],
|
|
182
|
+
[1, 4],
|
|
183
|
+
[2, 3],
|
|
184
|
+
[1, 3],
|
|
185
|
+
],
|
|
186
|
+
[
|
|
187
|
+
[2, 4],
|
|
188
|
+
[3, 0],
|
|
189
|
+
[2, 3],
|
|
190
|
+
[1, 3],
|
|
191
|
+
],
|
|
192
|
+
[
|
|
193
|
+
[2, 0],
|
|
194
|
+
[3, 0],
|
|
195
|
+
[2, 3],
|
|
196
|
+
[1, 3],
|
|
197
|
+
],
|
|
198
|
+
[
|
|
199
|
+
[2, 4],
|
|
200
|
+
[1, 4],
|
|
201
|
+
[2, 3],
|
|
202
|
+
[3, 1],
|
|
203
|
+
],
|
|
204
|
+
[
|
|
205
|
+
[2, 0],
|
|
206
|
+
[1, 4],
|
|
207
|
+
[2, 3],
|
|
208
|
+
[3, 1],
|
|
209
|
+
],
|
|
210
|
+
[
|
|
211
|
+
[2, 4],
|
|
212
|
+
[3, 0],
|
|
213
|
+
[2, 3],
|
|
214
|
+
[3, 1],
|
|
215
|
+
],
|
|
216
|
+
[
|
|
217
|
+
[2, 0],
|
|
218
|
+
[3, 0],
|
|
219
|
+
[2, 3],
|
|
220
|
+
[3, 1],
|
|
221
|
+
],
|
|
222
|
+
[
|
|
223
|
+
[2, 4],
|
|
224
|
+
[1, 4],
|
|
225
|
+
[2, 1],
|
|
226
|
+
[1, 3],
|
|
227
|
+
],
|
|
228
|
+
[
|
|
229
|
+
[2, 0],
|
|
230
|
+
[1, 4],
|
|
231
|
+
[2, 1],
|
|
232
|
+
[1, 3],
|
|
233
|
+
],
|
|
234
|
+
[
|
|
235
|
+
[2, 4],
|
|
236
|
+
[3, 0],
|
|
237
|
+
[2, 1],
|
|
238
|
+
[1, 3],
|
|
239
|
+
],
|
|
240
|
+
[
|
|
241
|
+
[2, 0],
|
|
242
|
+
[3, 0],
|
|
243
|
+
[2, 1],
|
|
244
|
+
[1, 3],
|
|
245
|
+
],
|
|
246
|
+
[
|
|
247
|
+
[2, 4],
|
|
248
|
+
[1, 4],
|
|
249
|
+
[2, 1],
|
|
250
|
+
[3, 1],
|
|
251
|
+
],
|
|
252
|
+
[
|
|
253
|
+
[2, 0],
|
|
254
|
+
[1, 4],
|
|
255
|
+
[2, 1],
|
|
256
|
+
[3, 1],
|
|
257
|
+
],
|
|
258
|
+
[
|
|
259
|
+
[2, 4],
|
|
260
|
+
[3, 0],
|
|
261
|
+
[2, 1],
|
|
262
|
+
[3, 1],
|
|
263
|
+
],
|
|
264
|
+
[
|
|
265
|
+
[2, 0],
|
|
266
|
+
[3, 0],
|
|
267
|
+
[2, 1],
|
|
268
|
+
[3, 1],
|
|
269
|
+
],
|
|
270
|
+
[
|
|
271
|
+
[0, 4],
|
|
272
|
+
[1, 4],
|
|
273
|
+
[0, 3],
|
|
274
|
+
[1, 3],
|
|
275
|
+
],
|
|
276
|
+
[
|
|
277
|
+
[0, 4],
|
|
278
|
+
[3, 0],
|
|
279
|
+
[0, 3],
|
|
280
|
+
[1, 3],
|
|
281
|
+
],
|
|
282
|
+
[
|
|
283
|
+
[0, 4],
|
|
284
|
+
[1, 4],
|
|
285
|
+
[0, 3],
|
|
286
|
+
[3, 1],
|
|
287
|
+
],
|
|
288
|
+
[
|
|
289
|
+
[0, 4],
|
|
290
|
+
[3, 0],
|
|
291
|
+
[0, 3],
|
|
292
|
+
[3, 1],
|
|
293
|
+
],
|
|
294
|
+
[
|
|
295
|
+
[2, 2],
|
|
296
|
+
[1, 2],
|
|
297
|
+
[2, 3],
|
|
298
|
+
[1, 3],
|
|
299
|
+
],
|
|
300
|
+
[
|
|
301
|
+
[2, 2],
|
|
302
|
+
[1, 2],
|
|
303
|
+
[2, 3],
|
|
304
|
+
[3, 1],
|
|
305
|
+
],
|
|
306
|
+
[
|
|
307
|
+
[2, 2],
|
|
308
|
+
[1, 2],
|
|
309
|
+
[2, 1],
|
|
310
|
+
[1, 3],
|
|
311
|
+
],
|
|
312
|
+
[
|
|
313
|
+
[2, 2],
|
|
314
|
+
[1, 2],
|
|
315
|
+
[2, 1],
|
|
316
|
+
[3, 1],
|
|
317
|
+
],
|
|
318
|
+
[
|
|
319
|
+
[2, 4],
|
|
320
|
+
[3, 4],
|
|
321
|
+
[2, 3],
|
|
322
|
+
[3, 3],
|
|
323
|
+
],
|
|
324
|
+
[
|
|
325
|
+
[2, 4],
|
|
326
|
+
[3, 4],
|
|
327
|
+
[2, 1],
|
|
328
|
+
[3, 3],
|
|
329
|
+
],
|
|
330
|
+
[
|
|
331
|
+
[2, 0],
|
|
332
|
+
[3, 4],
|
|
333
|
+
[2, 3],
|
|
334
|
+
[3, 3],
|
|
335
|
+
],
|
|
336
|
+
[
|
|
337
|
+
[2, 0],
|
|
338
|
+
[3, 4],
|
|
339
|
+
[2, 1],
|
|
340
|
+
[3, 3],
|
|
341
|
+
],
|
|
342
|
+
[
|
|
343
|
+
[2, 4],
|
|
344
|
+
[1, 4],
|
|
345
|
+
[2, 5],
|
|
346
|
+
[1, 5],
|
|
347
|
+
],
|
|
348
|
+
[
|
|
349
|
+
[2, 0],
|
|
350
|
+
[1, 4],
|
|
351
|
+
[2, 5],
|
|
352
|
+
[1, 5],
|
|
353
|
+
],
|
|
354
|
+
[
|
|
355
|
+
[2, 4],
|
|
356
|
+
[3, 0],
|
|
357
|
+
[2, 5],
|
|
358
|
+
[1, 5],
|
|
359
|
+
],
|
|
360
|
+
[
|
|
361
|
+
[2, 0],
|
|
362
|
+
[3, 0],
|
|
363
|
+
[2, 5],
|
|
364
|
+
[1, 5],
|
|
365
|
+
],
|
|
366
|
+
[
|
|
367
|
+
[0, 4],
|
|
368
|
+
[3, 4],
|
|
369
|
+
[0, 3],
|
|
370
|
+
[3, 3],
|
|
371
|
+
],
|
|
372
|
+
[
|
|
373
|
+
[2, 2],
|
|
374
|
+
[1, 2],
|
|
375
|
+
[2, 5],
|
|
376
|
+
[1, 5],
|
|
377
|
+
],
|
|
378
|
+
[
|
|
379
|
+
[0, 2],
|
|
380
|
+
[1, 2],
|
|
381
|
+
[0, 3],
|
|
382
|
+
[1, 3],
|
|
383
|
+
],
|
|
384
|
+
[
|
|
385
|
+
[0, 2],
|
|
386
|
+
[1, 2],
|
|
387
|
+
[0, 3],
|
|
388
|
+
[3, 1],
|
|
389
|
+
],
|
|
390
|
+
[
|
|
391
|
+
[2, 2],
|
|
392
|
+
[3, 2],
|
|
393
|
+
[2, 3],
|
|
394
|
+
[3, 3],
|
|
395
|
+
],
|
|
396
|
+
[
|
|
397
|
+
[2, 2],
|
|
398
|
+
[3, 2],
|
|
399
|
+
[2, 1],
|
|
400
|
+
[3, 3],
|
|
401
|
+
],
|
|
402
|
+
[
|
|
403
|
+
[2, 4],
|
|
404
|
+
[3, 4],
|
|
405
|
+
[2, 5],
|
|
406
|
+
[3, 5],
|
|
407
|
+
],
|
|
408
|
+
[
|
|
409
|
+
[2, 0],
|
|
410
|
+
[3, 4],
|
|
411
|
+
[2, 5],
|
|
412
|
+
[3, 5],
|
|
413
|
+
],
|
|
414
|
+
[
|
|
415
|
+
[0, 4],
|
|
416
|
+
[1, 4],
|
|
417
|
+
[0, 5],
|
|
418
|
+
[1, 5],
|
|
419
|
+
],
|
|
420
|
+
[
|
|
421
|
+
[0, 4],
|
|
422
|
+
[3, 0],
|
|
423
|
+
[0, 5],
|
|
424
|
+
[1, 5],
|
|
425
|
+
],
|
|
426
|
+
[
|
|
427
|
+
[0, 2],
|
|
428
|
+
[3, 2],
|
|
429
|
+
[0, 3],
|
|
430
|
+
[3, 3],
|
|
431
|
+
],
|
|
432
|
+
[
|
|
433
|
+
[0, 2],
|
|
434
|
+
[1, 2],
|
|
435
|
+
[0, 5],
|
|
436
|
+
[1, 5],
|
|
437
|
+
],
|
|
438
|
+
[
|
|
439
|
+
[0, 4],
|
|
440
|
+
[3, 4],
|
|
441
|
+
[0, 5],
|
|
442
|
+
[3, 5],
|
|
443
|
+
],
|
|
444
|
+
[
|
|
445
|
+
[2, 2],
|
|
446
|
+
[3, 2],
|
|
447
|
+
[2, 5],
|
|
448
|
+
[3, 5],
|
|
449
|
+
],
|
|
450
|
+
[
|
|
451
|
+
[0, 2],
|
|
452
|
+
[3, 2],
|
|
453
|
+
[0, 3],
|
|
454
|
+
[3, 5],
|
|
455
|
+
],
|
|
456
|
+
[
|
|
457
|
+
[0, 0],
|
|
458
|
+
[1, 0],
|
|
459
|
+
[0, 1],
|
|
460
|
+
[1, 1],
|
|
461
|
+
],
|
|
462
|
+
];
|
|
463
|
+
/**
|
|
464
|
+
* The standard MV wall-autotile shape table (16 shapes), for slots 2-3.
|
|
465
|
+
* Wall shapes cycle every 16 (`table[shape % 16]`), so a wall family holds
|
|
466
|
+
* three full cycles where a floor family holds one run of 48.
|
|
467
|
+
*/
|
|
468
|
+
export const RPGM_WALL_AUTOTILE_TABLE = [
|
|
469
|
+
[
|
|
470
|
+
[2, 2],
|
|
471
|
+
[1, 2],
|
|
472
|
+
[2, 1],
|
|
473
|
+
[1, 1],
|
|
474
|
+
],
|
|
475
|
+
[
|
|
476
|
+
[0, 2],
|
|
477
|
+
[1, 2],
|
|
478
|
+
[0, 1],
|
|
479
|
+
[1, 1],
|
|
480
|
+
],
|
|
481
|
+
[
|
|
482
|
+
[2, 0],
|
|
483
|
+
[1, 0],
|
|
484
|
+
[2, 1],
|
|
485
|
+
[1, 1],
|
|
486
|
+
],
|
|
487
|
+
[
|
|
488
|
+
[0, 0],
|
|
489
|
+
[1, 0],
|
|
490
|
+
[0, 1],
|
|
491
|
+
[1, 1],
|
|
492
|
+
],
|
|
493
|
+
[
|
|
494
|
+
[2, 2],
|
|
495
|
+
[3, 2],
|
|
496
|
+
[2, 1],
|
|
497
|
+
[3, 1],
|
|
498
|
+
],
|
|
499
|
+
[
|
|
500
|
+
[0, 2],
|
|
501
|
+
[3, 2],
|
|
502
|
+
[0, 1],
|
|
503
|
+
[3, 1],
|
|
504
|
+
],
|
|
505
|
+
[
|
|
506
|
+
[2, 0],
|
|
507
|
+
[3, 0],
|
|
508
|
+
[2, 1],
|
|
509
|
+
[3, 1],
|
|
510
|
+
],
|
|
511
|
+
[
|
|
512
|
+
[0, 0],
|
|
513
|
+
[3, 0],
|
|
514
|
+
[0, 1],
|
|
515
|
+
[3, 1],
|
|
516
|
+
],
|
|
517
|
+
[
|
|
518
|
+
[2, 2],
|
|
519
|
+
[1, 2],
|
|
520
|
+
[2, 3],
|
|
521
|
+
[1, 3],
|
|
522
|
+
],
|
|
523
|
+
[
|
|
524
|
+
[0, 2],
|
|
525
|
+
[1, 2],
|
|
526
|
+
[0, 3],
|
|
527
|
+
[1, 3],
|
|
528
|
+
],
|
|
529
|
+
[
|
|
530
|
+
[2, 0],
|
|
531
|
+
[1, 0],
|
|
532
|
+
[2, 3],
|
|
533
|
+
[1, 3],
|
|
534
|
+
],
|
|
535
|
+
[
|
|
536
|
+
[0, 0],
|
|
537
|
+
[1, 0],
|
|
538
|
+
[0, 3],
|
|
539
|
+
[1, 3],
|
|
540
|
+
],
|
|
541
|
+
[
|
|
542
|
+
[2, 2],
|
|
543
|
+
[3, 2],
|
|
544
|
+
[2, 3],
|
|
545
|
+
[3, 3],
|
|
546
|
+
],
|
|
547
|
+
[
|
|
548
|
+
[0, 2],
|
|
549
|
+
[3, 2],
|
|
550
|
+
[0, 3],
|
|
551
|
+
[3, 3],
|
|
552
|
+
],
|
|
553
|
+
[
|
|
554
|
+
[2, 0],
|
|
555
|
+
[3, 0],
|
|
556
|
+
[2, 3],
|
|
557
|
+
[3, 3],
|
|
558
|
+
],
|
|
559
|
+
[
|
|
560
|
+
[0, 0],
|
|
561
|
+
[3, 0],
|
|
562
|
+
[0, 3],
|
|
563
|
+
[3, 3],
|
|
564
|
+
],
|
|
565
|
+
];
|
|
566
|
+
/**
|
|
567
|
+
* The standard XP autotile pattern table (48 patterns). An XP autotile image
|
|
568
|
+
* is a 96 by 128 template: a 6-column grid of 16px mini-blocks, and each
|
|
569
|
+
* baked pattern assembles four of them. `tile % 48` selects the pattern;
|
|
570
|
+
* `tile / 48` (floored) selects which of the map's autotile images.
|
|
571
|
+
*
|
|
572
|
+
* Miniblock entries are 0-based here (block `n` sits at `(n % 6) * 16`,
|
|
573
|
+
* `(n / 6) * 16`). Learned from real XP autotile images and map data rather
|
|
574
|
+
* than assumed: the 6 by 8 mini-grid fits the measured 96 by 128 template
|
|
575
|
+
* exactly, and the neighbor table below reproduces baked map patterns.
|
|
576
|
+
*
|
|
577
|
+
* @example
|
|
578
|
+
* ```ts
|
|
579
|
+
* import { XP_AUTOTILE_PATTERNS, XP_NEIGHBORS_TO_PATTERN } from '@datamoc/mw_games/two-d/render';
|
|
580
|
+
*
|
|
581
|
+
* console.log(XP_AUTOTILE_PATTERNS.length); // 48 - one entry per baked pattern
|
|
582
|
+
* console.log(XP_AUTOTILE_PATTERNS[0]); // [26,27,32,33] - the filled interior tile
|
|
583
|
+
* console.log(XP_NEIGHBORS_TO_PATTERN.length); // 256 - one entry per 8-neighbour mask
|
|
584
|
+
* console.log(XP_NEIGHBORS_TO_PATTERN[255]); // 0 - surrounded on all sides is the interior
|
|
585
|
+
* ```
|
|
586
|
+
*/
|
|
587
|
+
export const XP_AUTOTILE_PATTERNS = [
|
|
588
|
+
[26, 27, 32, 33],
|
|
589
|
+
[4, 27, 32, 33],
|
|
590
|
+
[26, 5, 32, 33],
|
|
591
|
+
[4, 5, 32, 33],
|
|
592
|
+
[26, 27, 32, 11],
|
|
593
|
+
[4, 27, 32, 11],
|
|
594
|
+
[26, 5, 32, 11],
|
|
595
|
+
[4, 5, 32, 11],
|
|
596
|
+
[26, 27, 10, 33],
|
|
597
|
+
[4, 27, 10, 33],
|
|
598
|
+
[26, 5, 10, 33],
|
|
599
|
+
[4, 5, 10, 33],
|
|
600
|
+
[26, 27, 10, 11],
|
|
601
|
+
[4, 27, 10, 11],
|
|
602
|
+
[26, 5, 10, 11],
|
|
603
|
+
[4, 5, 10, 11],
|
|
604
|
+
[24, 25, 30, 31],
|
|
605
|
+
[24, 5, 30, 31],
|
|
606
|
+
[24, 25, 30, 11],
|
|
607
|
+
[24, 5, 30, 11],
|
|
608
|
+
[14, 15, 20, 21],
|
|
609
|
+
[14, 15, 20, 11],
|
|
610
|
+
[14, 15, 10, 21],
|
|
611
|
+
[14, 15, 10, 11],
|
|
612
|
+
[28, 29, 34, 35],
|
|
613
|
+
[28, 29, 10, 35],
|
|
614
|
+
[4, 29, 34, 35],
|
|
615
|
+
[4, 29, 10, 35],
|
|
616
|
+
[38, 39, 44, 45],
|
|
617
|
+
[4, 39, 44, 45],
|
|
618
|
+
[38, 5, 44, 45],
|
|
619
|
+
[4, 5, 44, 45],
|
|
620
|
+
[24, 29, 30, 35],
|
|
621
|
+
[14, 15, 44, 45],
|
|
622
|
+
[12, 13, 18, 19],
|
|
623
|
+
[12, 13, 18, 11],
|
|
624
|
+
[16, 17, 22, 23],
|
|
625
|
+
[16, 17, 10, 23],
|
|
626
|
+
[40, 41, 46, 47],
|
|
627
|
+
[4, 41, 46, 47],
|
|
628
|
+
[36, 37, 42, 43],
|
|
629
|
+
[36, 5, 42, 43],
|
|
630
|
+
[12, 17, 18, 23],
|
|
631
|
+
[12, 13, 42, 43],
|
|
632
|
+
[36, 41, 42, 47],
|
|
633
|
+
[16, 17, 46, 47],
|
|
634
|
+
[12, 17, 42, 47],
|
|
635
|
+
[0, 1, 6, 7],
|
|
636
|
+
];
|
|
637
|
+
/**
|
|
638
|
+
* Which XP pattern an 8-neighbourhood of same-autotile cells bakes to. Index
|
|
639
|
+
* with a bit mask - north `0x01`, northeast `0x02`, east `0x04`, southeast
|
|
640
|
+
* `0x08`, south `0x10`, southwest `0x20`, west `0x40`, northwest `0x80` - for
|
|
641
|
+
* games computing patterns procedurally instead of reading baked map data.
|
|
642
|
+
*/
|
|
643
|
+
export const XP_NEIGHBORS_TO_PATTERN = [
|
|
644
|
+
46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40, 42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34,
|
|
645
|
+
17, 34, 16, 46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40, 42, 32, 42, 32, 35, 19, 35, 18, 42, 32,
|
|
646
|
+
42, 32, 34, 17, 34, 16, 45, 39, 45, 39, 33, 31, 33, 29, 45, 39, 45, 39, 33, 31, 33, 29, 37, 27, 37, 27, 23, 15, 23,
|
|
647
|
+
13, 37, 27, 37, 27, 22, 11, 22, 9, 45, 39, 45, 39, 33, 31, 33, 29, 45, 39, 45, 39, 33, 31, 33, 29, 36, 26, 36, 26,
|
|
648
|
+
21, 7, 21, 5, 36, 26, 36, 26, 20, 3, 20, 1, 46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43, 40, 42, 32,
|
|
649
|
+
42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16, 46, 44, 46, 44, 43, 41, 43, 40, 46, 44, 46, 44, 43, 41, 43,
|
|
650
|
+
40, 42, 32, 42, 32, 35, 19, 35, 18, 42, 32, 42, 32, 34, 17, 34, 16, 45, 38, 45, 38, 33, 30, 33, 28, 45, 38, 45, 38,
|
|
651
|
+
33, 30, 33, 28, 37, 25, 37, 25, 23, 14, 23, 12, 37, 25, 37, 25, 22, 10, 22, 8, 45, 38, 45, 38, 33, 30, 33, 28, 45,
|
|
652
|
+
38, 45, 38, 33, 30, 33, 28, 36, 24, 36, 24, 21, 6, 21, 4, 36, 24, 36, 24, 20, 2, 20, 0,
|
|
653
|
+
];
|
|
654
|
+
/**
|
|
655
|
+
* Decodes a raw XP map cell into its autotile image and pattern, or null
|
|
656
|
+
* when the cell holds no autotile reference: `EMPTY`, a static tileset tile
|
|
657
|
+
* (384 and up), or anything outside the 1-383 autotile range.
|
|
658
|
+
*
|
|
659
|
+
* @example
|
|
660
|
+
* ```ts
|
|
661
|
+
* import { xpAutotileRef } from '@datamoc/mw_games/two-d/render';
|
|
662
|
+
*
|
|
663
|
+
* console.log(xpAutotileRef(97)); // { index: 2, pattern: 1 } - second image, second pattern
|
|
664
|
+
* console.log(xpAutotileRef(0)); // null - EMPTY is blank, never an autotile
|
|
665
|
+
* console.log(xpAutotileRef(384)); // null - the first static tileset tile
|
|
666
|
+
* ```
|
|
667
|
+
*/
|
|
668
|
+
export function xpAutotileRef(tile) {
|
|
669
|
+
if (!Number.isInteger(tile) || tile <= 0 || tile >= 384)
|
|
670
|
+
return null;
|
|
671
|
+
return { index: Math.floor(tile / 48), pattern: tile % 48 };
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Which XP pattern a cell's 8-neighbourhood bakes to, for maps computed
|
|
675
|
+
* procedurally rather than read from baked data. `sameTerrain` is asked once
|
|
676
|
+
* per direction, with `(dx, dy)` offsets (`(0, -1)` is north); off the map is
|
|
677
|
+
* the caller's to answer (false reads as a border, the edge cell's own value
|
|
678
|
+
* clamps like the editor).
|
|
679
|
+
*
|
|
680
|
+
* @example
|
|
681
|
+
* ```ts
|
|
682
|
+
* import { xpAutotilePattern } from '@datamoc/mw_games/two-d/render';
|
|
683
|
+
*
|
|
684
|
+
* const filled = new Set(['0,0', '1,0', '0,1', '1,1', '-1,0', '0,-1', '2,1', '1,2']);
|
|
685
|
+
* console.log(xpAutotilePattern((dx, dy) => filled.has(`${dx},${dy}`))); // 0 - the interior
|
|
686
|
+
* console.log(xpAutotilePattern(() => false)); // 46 - isolated on all sides
|
|
687
|
+
* ```
|
|
688
|
+
*/
|
|
689
|
+
export function xpAutotilePattern(sameTerrain) {
|
|
690
|
+
let mask = 0;
|
|
691
|
+
if (sameTerrain(0, -1))
|
|
692
|
+
mask |= 0x01;
|
|
693
|
+
if (sameTerrain(1, -1))
|
|
694
|
+
mask |= 0x02;
|
|
695
|
+
if (sameTerrain(1, 0))
|
|
696
|
+
mask |= 0x04;
|
|
697
|
+
if (sameTerrain(1, 1))
|
|
698
|
+
mask |= 0x08;
|
|
699
|
+
if (sameTerrain(0, 1))
|
|
700
|
+
mask |= 0x10;
|
|
701
|
+
if (sameTerrain(-1, 1))
|
|
702
|
+
mask |= 0x20;
|
|
703
|
+
if (sameTerrain(-1, 0))
|
|
704
|
+
mask |= 0x40;
|
|
705
|
+
if (sameTerrain(-1, -1))
|
|
706
|
+
mask |= 0x80;
|
|
707
|
+
return XP_NEIGHBORS_TO_PATTERN[mask];
|
|
708
|
+
}
|
|
709
|
+
/** the atlas kinds each MV family holds, for validating animation cycles */
|
|
710
|
+
const RPGM_AUTOTILE_KIND_COUNTS = [16, 32, 32, 48];
|
|
711
|
+
/**
|
|
712
|
+
* Checks a resolved autotile layout once, up front. Throws naming the first
|
|
713
|
+
* problem: a bad slot, an empty shape table, an empty animation cycle, a
|
|
714
|
+
* cycle kind outside its slot's kinds, a bad XP index, or a frame count
|
|
715
|
+
* below one.
|
|
716
|
+
*
|
|
717
|
+
* @example
|
|
718
|
+
* ```ts
|
|
719
|
+
* import {
|
|
720
|
+
* assertAutotileLayout,
|
|
721
|
+
* RPGM_FLOOR_AUTOTILE_TABLE,
|
|
722
|
+
* } from '@datamoc/mw_games/two-d/render';
|
|
723
|
+
*
|
|
724
|
+
* assertAutotileLayout({ format: 'rpgm-mv', slot: 0, table: RPGM_FLOOR_AUTOTILE_TABLE, cycles: [[0, 1, 2]] });
|
|
725
|
+
* assertAutotileLayout({ format: 'rpgm-xp', index: 2, frames: 1, single: false });
|
|
726
|
+
* ```
|
|
727
|
+
*/
|
|
728
|
+
export function assertAutotileLayout(layout) {
|
|
729
|
+
if (layout.format === 'rpgm-mv') {
|
|
730
|
+
assertSlot(layout.slot);
|
|
731
|
+
validateShapeTable(layout.table);
|
|
732
|
+
const kinds = RPGM_AUTOTILE_KIND_COUNTS[layout.slot];
|
|
733
|
+
const firstKind = SLOT_BASE_KINDS[layout.slot];
|
|
734
|
+
for (const cycle of layout.cycles) {
|
|
735
|
+
if (cycle.length === 0)
|
|
736
|
+
throw new Error('an autotile animation cycle needs at least one kind');
|
|
737
|
+
for (const kind of cycle) {
|
|
738
|
+
if (!Number.isInteger(kind) || kind < firstKind || kind >= firstKind + kinds) {
|
|
739
|
+
throw new Error(`animation cycle kind ${kind} is outside slot ${layout.slot}'s kinds ${firstKind}-${firstKind + kinds - 1}`);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
if (!Number.isInteger(layout.index) || layout.index < 0 || layout.index > 7) {
|
|
746
|
+
throw new Error(`an XP autotile index must be 0-7, got ${layout.index}`);
|
|
747
|
+
}
|
|
748
|
+
if (!Number.isInteger(layout.frames) || layout.frames < 1) {
|
|
749
|
+
throw new Error(`an XP autotile frame count must be at least 1, got ${layout.frames}`);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
/** source pixels of one MV quadrant piece: the format's fixed 24px halves */
|
|
753
|
+
const RPGM_QUADRANT_SIZE = 24;
|
|
754
|
+
/** source pixels of one XP quadrant piece: the format's fixed 16px halves */
|
|
755
|
+
const XP_QUADRANT_SIZE = 16;
|
|
756
|
+
/** columns of 16px mini-blocks in an XP template image */
|
|
757
|
+
const XP_TEMPLATE_COLUMNS = 6;
|
|
758
|
+
/** width of one XP animation stripe, in source pixels */
|
|
759
|
+
const XP_FRAME_WIDTH = 96;
|
|
760
|
+
/** size of one XP single-tile frame, in source pixels */
|
|
761
|
+
const XP_SINGLE_TILE_SIZE = 32;
|
|
762
|
+
/**
|
|
763
|
+
* Resolves one autotile cell to its drawn pieces: four quadrant halves for a
|
|
764
|
+
* template cell, one whole-tile piece for an XP single-tile strip, or null
|
|
765
|
+
* for a blank cell (`tile <= 0` reads as blank; `EMPTY` is -1).
|
|
766
|
+
*
|
|
767
|
+
* The layout is assumed valid (`assertAutotileLayout`); only the cell and
|
|
768
|
+
* frame are checked here. `tile` must be an integer the layout claims - an
|
|
769
|
+
* MV id in the layout's slot range, an XP id in `index * 48` to
|
|
770
|
+
* `index * 48 + 47` - and `frame` an integer at or above zero, wrapping
|
|
771
|
+
* around the animation cycles (MV) or frame stripes (XP).
|
|
772
|
+
*
|
|
773
|
+
* @example
|
|
774
|
+
* ```ts
|
|
775
|
+
* import {
|
|
776
|
+
* autotileCellParts,
|
|
777
|
+
* RPGM_FLOOR_AUTOTILE_TABLE,
|
|
778
|
+
* } from '@datamoc/mw_games/two-d/render';
|
|
779
|
+
*
|
|
780
|
+
* const parts = autotileCellParts(
|
|
781
|
+
* { format: 'rpgm-mv', slot: 0, table: RPGM_FLOOR_AUTOTILE_TABLE, cycles: [] },
|
|
782
|
+
* 2048, 0,
|
|
783
|
+
* );
|
|
784
|
+
* console.log(parts?.length); // 4 - one piece per quadrant
|
|
785
|
+
* console.log(parts?.[0].sourceWidth); // 24 - MV quadrant halves
|
|
786
|
+
* console.log(autotileCellParts(
|
|
787
|
+
* { format: 'rpgm-xp', index: 2, frames: 1, single: false },
|
|
788
|
+
* 97, 0,
|
|
789
|
+
* )?.[0].sourceWidth); // 16 - XP quadrant halves
|
|
790
|
+
* ```
|
|
791
|
+
*/
|
|
792
|
+
export function autotileCellParts(layout, tile, frame) {
|
|
793
|
+
if (tile <= 0)
|
|
794
|
+
return null;
|
|
795
|
+
if (!Number.isInteger(frame) || frame < 0) {
|
|
796
|
+
throw new Error(`an autotile animation frame must be an integer at or above zero, got ${frame}`);
|
|
797
|
+
}
|
|
798
|
+
if (layout.format === 'rpgm-mv')
|
|
799
|
+
return rpgmCellParts(layout, tile, frame);
|
|
800
|
+
return xpCellParts(layout, tile, frame);
|
|
801
|
+
}
|
|
802
|
+
function rpgmCellParts(layout, tile, frame) {
|
|
803
|
+
const base = RPGM_AUTOTILE_SLOT_BASES[layout.slot];
|
|
804
|
+
const count = RPGM_AUTOTILE_SLOT_COUNTS[layout.slot];
|
|
805
|
+
if (!Number.isInteger(tile) || tile < base || tile >= base + count) {
|
|
806
|
+
throw new Error(`tile ${tile} is outside slot ${layout.slot}'s ids ${base}-${base + count - 1}`);
|
|
807
|
+
}
|
|
808
|
+
const offset = tile - base;
|
|
809
|
+
//shorter tables cycle the same way the player's own indexing does
|
|
810
|
+
//(`table[shape % table.length]` over `shape = offset % 48`)
|
|
811
|
+
const shape = (offset % 48) % layout.table.length;
|
|
812
|
+
let kind = SLOT_BASE_KINDS[layout.slot] + Math.floor(offset / 48);
|
|
813
|
+
for (const cycle of layout.cycles) {
|
|
814
|
+
const at = cycle.indexOf(kind);
|
|
815
|
+
if (at >= 0) {
|
|
816
|
+
kind = cycle[(at + frame) % cycle.length];
|
|
817
|
+
break;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
//rpgmAutotileFrame's tileId is the base-relative offset, so a remapped
|
|
821
|
+
//kind keeps the cell's shape and only swaps the kind block
|
|
822
|
+
const described = rpgmAutotileFrame((kind - SLOT_BASE_KINDS[layout.slot]) * 48 + (offset % 48), layout.slot, shape, layout.table);
|
|
823
|
+
return described.quadrants.map((quadrant, index) => ({
|
|
824
|
+
sourceX: quadrant.sourceX,
|
|
825
|
+
sourceY: quadrant.sourceY,
|
|
826
|
+
sourceWidth: RPGM_QUADRANT_SIZE,
|
|
827
|
+
sourceHeight: RPGM_QUADRANT_SIZE,
|
|
828
|
+
destX: (index % 2) / 2,
|
|
829
|
+
destY: Math.floor(index / 2) / 2,
|
|
830
|
+
destWidth: 1 / 2,
|
|
831
|
+
destHeight: 1 / 2,
|
|
832
|
+
}));
|
|
833
|
+
}
|
|
834
|
+
function xpCellParts(layout, tile, frame) {
|
|
835
|
+
if (!Number.isInteger(tile) || tile < layout.index * 48 || tile >= layout.index * 48 + 48 || tile <= 0) {
|
|
836
|
+
throw new Error(`tile ${tile} is outside XP autotile ${layout.index}'s ids ${layout.index * 48}-${layout.index * 48 + 47}`);
|
|
837
|
+
}
|
|
838
|
+
if (layout.single) {
|
|
839
|
+
const stripe = (frame % layout.frames) * XP_SINGLE_TILE_SIZE;
|
|
840
|
+
return [
|
|
841
|
+
{
|
|
842
|
+
sourceX: stripe,
|
|
843
|
+
sourceY: 0,
|
|
844
|
+
sourceWidth: XP_SINGLE_TILE_SIZE,
|
|
845
|
+
sourceHeight: XP_SINGLE_TILE_SIZE,
|
|
846
|
+
destX: 0,
|
|
847
|
+
destY: 0,
|
|
848
|
+
destWidth: 1,
|
|
849
|
+
destHeight: 1,
|
|
850
|
+
},
|
|
851
|
+
];
|
|
852
|
+
}
|
|
853
|
+
const pattern = XP_AUTOTILE_PATTERNS[tile % 48];
|
|
854
|
+
const stripe = (frame % layout.frames) * XP_FRAME_WIDTH;
|
|
855
|
+
return pattern.map((block, index) => ({
|
|
856
|
+
sourceX: (block % XP_TEMPLATE_COLUMNS) * XP_QUADRANT_SIZE + stripe,
|
|
857
|
+
sourceY: Math.floor(block / XP_TEMPLATE_COLUMNS) * XP_QUADRANT_SIZE,
|
|
858
|
+
sourceWidth: XP_QUADRANT_SIZE,
|
|
859
|
+
sourceHeight: XP_QUADRANT_SIZE,
|
|
860
|
+
destX: (index % 2) / 2,
|
|
861
|
+
destY: Math.floor(index / 2) / 2,
|
|
862
|
+
destWidth: 1 / 2,
|
|
863
|
+
destHeight: 1 / 2,
|
|
864
|
+
}));
|
|
865
|
+
}
|
|
110
866
|
//# sourceMappingURL=RpgmAutotile.js.map
|