@datamoc/mw_games 0.12.0 → 0.14.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 (75) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/README.md +5 -1
  3. package/dist/board/Classics.d.ts.map +1 -1
  4. package/dist/board/Classics.js +3 -2
  5. package/dist/board/Classics.js.map +1 -1
  6. package/dist/board/FogOfWar.d.ts.map +1 -1
  7. package/dist/board/FogOfWar.js +5 -2
  8. package/dist/board/FogOfWar.js.map +1 -1
  9. package/dist/board/HexSkirmish.d.ts.map +1 -1
  10. package/dist/board/HexSkirmish.js +2 -1
  11. package/dist/board/HexSkirmish.js.map +1 -1
  12. package/dist/core/DialogueText.d.ts +47 -0
  13. package/dist/core/DialogueText.d.ts.map +1 -0
  14. package/dist/core/DialogueText.js +43 -0
  15. package/dist/core/DialogueText.js.map +1 -0
  16. package/dist/core/Grid.d.ts +64 -0
  17. package/dist/core/Grid.d.ts.map +1 -0
  18. package/dist/core/Grid.js +76 -0
  19. package/dist/core/Grid.js.map +1 -0
  20. package/dist/core/Twee.d.ts +67 -0
  21. package/dist/core/Twee.d.ts.map +1 -0
  22. package/dist/core/Twee.js +140 -0
  23. package/dist/core/Twee.js.map +1 -0
  24. package/dist/core/index.d.ts +5 -0
  25. package/dist/core/index.d.ts.map +1 -1
  26. package/dist/core/index.js +3 -0
  27. package/dist/core/index.js.map +1 -1
  28. package/dist/mw_games.global.js +108 -107
  29. package/dist/roguelike/Level.d.ts.map +1 -1
  30. package/dist/roguelike/Level.js +5 -4
  31. package/dist/roguelike/Level.js.map +1 -1
  32. package/dist/rpg/EventRunner.d.ts +20 -0
  33. package/dist/rpg/EventRunner.d.ts.map +1 -1
  34. package/dist/rpg/EventRunner.js +52 -11
  35. package/dist/rpg/EventRunner.js.map +1 -1
  36. package/dist/rpg/dialogue-text.d.ts +81 -0
  37. package/dist/rpg/dialogue-text.d.ts.map +1 -0
  38. package/dist/rpg/dialogue-text.js +88 -0
  39. package/dist/rpg/dialogue-text.js.map +1 -0
  40. package/dist/rpg/index.d.ts +4 -1
  41. package/dist/rpg/index.d.ts.map +1 -1
  42. package/dist/rpg/index.js +2 -0
  43. package/dist/rpg/index.js.map +1 -1
  44. package/dist/rpg/twee-events.d.ts +48 -0
  45. package/dist/rpg/twee-events.d.ts.map +1 -0
  46. package/dist/rpg/twee-events.js +35 -0
  47. package/dist/rpg/twee-events.js.map +1 -0
  48. package/dist/two-d/Game.d.ts +24 -0
  49. package/dist/two-d/Game.d.ts.map +1 -1
  50. package/dist/two-d/Game.js +42 -1
  51. package/dist/two-d/Game.js.map +1 -1
  52. package/dist/two-d/ResolutionFit.d.ts +28 -0
  53. package/dist/two-d/ResolutionFit.d.ts.map +1 -0
  54. package/dist/two-d/ResolutionFit.js +39 -0
  55. package/dist/two-d/ResolutionFit.js.map +1 -0
  56. package/dist/two-d/stage/dialogue-text.d.ts +81 -0
  57. package/dist/two-d/stage/dialogue-text.d.ts.map +1 -0
  58. package/dist/two-d/stage/dialogue-text.js +95 -0
  59. package/dist/two-d/stage/dialogue-text.js.map +1 -0
  60. package/dist/two-d/stage/index.d.ts +1 -0
  61. package/dist/two-d/stage/index.d.ts.map +1 -1
  62. package/dist/two-d/stage/index.js +1 -0
  63. package/dist/two-d/stage/index.js.map +1 -1
  64. package/dist/two-d/stage/twee.d.ts +7 -25
  65. package/dist/two-d/stage/twee.d.ts.map +1 -1
  66. package/dist/two-d/stage/twee.js +10 -162
  67. package/dist/two-d/stage/twee.js.map +1 -1
  68. package/dist/version.d.ts +1 -1
  69. package/dist/version.js +1 -1
  70. package/package.json +4 -1
  71. package/tools/classic-html.mjs +1 -1
  72. package/tools/compress-dist.d.mts +18 -0
  73. package/tools/compress-dist.mjs +5 -0
  74. package/tools/single-file.d.mts +16 -0
  75. package/tools/single-file.mjs +8 -1
@@ -1,8 +1,11 @@
1
1
  import { Application, TextureSource } from 'pixi.js';
2
2
  import { SceneStack } from '../core/SceneStack.js';
3
3
  import { Signal } from '../core/Signal.js';
4
+ import { Logger } from '../core/Log.js';
5
+ import { fitResolution } from './ResolutionFit.js';
4
6
  import * as Input from '../core/Input.js';
5
7
  const PIXEL_ART_CLASS = 'mwg-pixel-art';
8
+ const log = new Logger('renderer');
6
9
  /**
7
10
  * A class beats an inline `canvas.style.imageRendering` because Pixi's own `autoDensity`/
8
11
  * `resizeTo` rewrite the canvas's `style` attribute wholesale (see `start()`); this rule
@@ -42,6 +45,13 @@ function watchDevicePixelRatio(onChange) {
42
45
  * The application: owns the renderer, the loop, and the current scene.
43
46
  *
44
47
  * Construct it, `await start(FirstScene)`, and the rest is scenes.
48
+ *
49
+ * The canvas is drawn at the display's `devicePixelRatio`, up to what the device can actually
50
+ * make: a backing store of `viewport * devicePixelRatio` pixels is refused past the GPU's
51
+ * `MAX_TEXTURE_SIZE` (WebGL clamps it rather than failing, with nothing reported), so the
52
+ * resolution is reduced to the largest whole number that fits and a warning says so. A game
53
+ * therefore keeps rendering on a device with a small limit, softer than the display asked for
54
+ * rather than wrong; nothing changes on a device that can afford what it asked for.
45
55
  */
46
56
  export class Game {
47
57
  static { this.instance = null; }
@@ -134,7 +144,11 @@ export class Game {
134
144
  //them the backing size would push everything they centre off the screen.
135
145
  this.app.renderer.on('resize', () => {
136
146
  this.stack.resize(this.width, this.height);
147
+ //a rotation or a window resize changes how much of a backing store this device
148
+ //can afford, so re-fit rather than keeping whatever was chosen at startup
149
+ this.fitResolutionToDevice();
137
150
  });
151
+ this.fitResolutionToDevice();
138
152
  //the resolution passed to app.init() above is a one-time snapshot of
139
153
  //devicePixelRatio; a later browser zoom (or dragging the window to a display with a
140
154
  //different scale factor) changes that ratio without Pixi noticing on its own. Left
@@ -143,7 +157,7 @@ export class Game {
143
157
  //non-integer ratio duplicates pixel columns inconsistently - the seams a pixel-art
144
158
  //tilemap shows between tiles that were perfectly adjacent in the buffer itself.
145
159
  this.stopWatchingDpr = watchDevicePixelRatio(() => {
146
- this.app.renderer.resize(this.width, this.height, window.devicePixelRatio || 1);
160
+ this.fitResolutionToDevice();
147
161
  });
148
162
  this.expose();
149
163
  this.switchNow(first);
@@ -221,6 +235,33 @@ export class Game {
221
235
  target.__PIXI_APP__ = this.app;
222
236
  target.__MWG__ = this;
223
237
  }
238
+ /**
239
+ * Resizes the renderer to a resolution this device can actually afford.
240
+ *
241
+ * A full-window canvas at device resolution can ask for a backing store larger than the
242
+ * GPU's `MAX_TEXTURE_SIZE`, and WebGL clamps that silently instead of failing: the canvas
243
+ * keeps its size, the scene keeps being rendered into a surface that is not the one asked
244
+ * for, and nothing anywhere says so. A 1080-wide phone at `devicePixelRatio` 2.625 asks for
245
+ * 2121x4709 against the 4096 limit one emulator reported, and got a 2121x4096 drawing
246
+ * buffer; see `fitResolution` for the arithmetic and for what that investigation did and
247
+ * did not establish about the black screen that process showed.
248
+ *
249
+ * Called after `init`, whenever the renderer is resized (a rotation changes which one fits),
250
+ * and when `devicePixelRatio` itself changes. It returns immediately when the device can
251
+ * afford what was asked for, which is every ordinary case, so nothing about a normal
252
+ * startup changes.
253
+ */
254
+ fitResolutionToDevice() {
255
+ const gl = this.app.renderer.gl;
256
+ const limit = gl ? gl.getParameter(gl.MAX_TEXTURE_SIZE) : Number.POSITIVE_INFINITY;
257
+ const wanted = window.devicePixelRatio || 1;
258
+ const fitted = fitResolution(this.width, this.height, wanted, limit);
259
+ if (fitted === this.app.renderer.resolution)
260
+ return;
261
+ log.warn(`this device cannot render a ${this.width}x${this.height} canvas at ${wanted}x ` +
262
+ `(its limit is ${limit}); using ${fitted}x instead, which is softer than the display`);
263
+ this.app.renderer.resize(this.width, this.height, fitted);
264
+ }
224
265
  frame(deltaSeconds) {
225
266
  //queued scene changes run first, in order, so a frame never updates a
226
267
  //scene that was already asked to leave
@@ -1 +1 @@
1
- {"version":3,"file":"Game.js","sourceRoot":"","sources":["../../src/two-d/Game.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Game.js","sourceRoot":"","sources":["../../src/two-d/Game.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGrD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAE1C,MAAM,eAAe,GAAG,eAAe,CAAC;AAExC,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC;AAQnC;;;;;GAKG;AACH,SAAS,wBAAwB;IAChC,IAAI,QAAQ,CAAC,cAAc,CAAC,eAAe,CAAC;QAAE,OAAO;IAErD,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,GAAG,eAAe,CAAC;IAC3B,KAAK,CAAC,WAAW,GAAG,IAAI,eAAe,kCAAkC,CAAC;IAC1E,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AAClC,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,qBAAqB,CAAC,QAAoB;IAClD,IAAI,KAAK,GAA0B,IAAI,CAAC;IAExC,MAAM,KAAK,GAAG,GAAS,EAAE;QACxB,KAAK,GAAG,UAAU,CAAC,gBAAgB,MAAM,CAAC,gBAAgB,OAAO,CAAC,CAAC;QACnE,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,GAAS,EAAE;QACvB,QAAQ,EAAE,CAAC;QACX,KAAK,EAAE,CAAC;IACT,CAAC,CAAC;IAEF,KAAK,EAAE,CAAC;IACR,OAAO,GAAG,EAAE,CAAC,KAAK,EAAE,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AACzD,CAAC;AAuDD;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,IAAI;aACD,aAAQ,GAAgB,IAAI,AAApB,CAAqB;IAyB5C,YAAY,OAAO,GAAgB,EAAE;QAvB5B,QAAG,GAAG,IAAI,WAAW,EAAE,CAAC;QAEjC,mEAAmE;QACnE,YAAO,GAAG,CAAC,CAAC;QAEZ,wDAAwD;QACxD,cAAS,GAAG,CAAC,CAAC;QAEd,+EAA+E;QAC/E,cAAS,GAAG,CAAC,CAAC;QAEd,6EAA6E;QACpE,YAAO,GAAG,IAAI,MAAM,EAAU,CAAC;QAEhC,qBAAgB,GAAG,CAAC,CAAC;QACrB,iBAAY,GAAG,CAAC,CAAC;QAEjB,UAAK,GAAG,IAAI,UAAU,EAAW,CAAC;QAClC,YAAO,GAAmB,EAAE,CAAC;QAE7B,YAAO,GAAG,KAAK,CAAC;QAChB,oBAAe,GAAwB,IAAI,CAAC;QAGnD,IAAI,CAAC,OAAO,GAAG;YACd,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;YAC1D,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,QAAQ;YAC1C,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,IAAI;YAClC,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,IAAI;YAClC,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,MAAM;YACpC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE;SACpC,CAAC;QAEF,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YAC3B,6EAA6E;YAC7E,6EAA6E;YAC7E,8EAA8E;YAC9E,2EAA2E;YAC3E,0EAA0E;YAC1E,+EAA+E;YAC/E,oEAAoE;YACpE,8EAA8E;YAC9E,yEAAyE;YACzE,aAAa,CAAC,cAAc,CAAC,SAAS,GAAG,SAAS,CAAC;QACpD,CAAC;QAED,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,6EAA6E;IAC7E,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;IACvC,CAAC;IAED,IAAI,MAAM;QACT,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IACxC,CAAC;IAED,wEAAwE;IACxE,MAAM,KAAK,OAAO;QACjB,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAA0B;QACrC,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QAEpB,6EAA6E;QAC7E,oFAAoF;QACpF,iCAAiC;QACjC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU;YAAE,QAAQ,EAAE,CAAC;QAC3D,KAAK,CAAC,MAAM,EAAE,CAAC;QAEf,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YACnB,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;YAC3B,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU;YACnC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ;YAC/B,SAAS,EAAE,KAAK;YAChB,8EAA8E;YAC9E,qBAAqB,EAAE,KAAK;YAC5B,6EAA6E;YAC7E,UAAU,EAAE,MAAM,CAAC,gBAAgB,IAAI,CAAC;YACxC,WAAW,EAAE,IAAI;SACjB,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YACtC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAChD,CAAC;QAED,qFAAqF;QACrF,iFAAiF;QACjF,gFAAgF;QAChF,oFAAoF;QACpF,6EAA6E;QAC7E,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YAC3B,wBAAwB,EAAE,CAAC;YAC3B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QACpD,CAAC;QAED,oFAAoF;QACpF,iFAAiF;QACjF,yEAAyE;QACzE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YACnC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAC3C,+EAA+E;YAC/E,0EAA0E;YAC1E,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAE7B,qEAAqE;QACrE,oFAAoF;QACpF,mFAAmF;QACnF,mFAAmF;QACnF,8EAA8E;QAC9E,mFAAmF;QACnF,gFAAgF;QAChF,IAAI,CAAC,eAAe,GAAG,qBAAqB,CAAC,GAAG,EAAE;YACjD,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC9B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAEtB,8EAA8E;QAC9E,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC;IACpE,CAAC;IAED;;;;;OAKG;IACH,WAAW,CAAC,IAAyB;QACpC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED;;;;;;OAMG;IACH,SAAS,CAAC,IAAyB;QAClC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED;;;;OAIG;IACH,QAAQ,CAAC,MAAgB;QACxB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,yDAAyD;IACzD,IAAI,YAAY;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;IAC3B,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,QAAgB,EAAE,KAAK,GAAG,CAAC;QAClC,IAAI,CAAC,gBAAgB,GAAG,QAAQ,CAAC;QACjC,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;IAC3B,CAAC;IAED;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAU;QACd,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACf,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;;;;;;OAUG;IACK,MAAM;QACb,MAAM,MAAM,GAAG,UAAgD,CAAC;QAChE,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC;QAC/B,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IACvB,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACK,qBAAqB;QAC5B,MAAM,EAAE,GAAI,IAAI,CAAC,GAAG,CAAC,QAA4C,CAAC,EAAE,CAAC;QACrE,MAAM,KAAK,GAAG,EAAE,CAAC,CAAC,CAAE,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,gBAAgB,CAAY,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC;QAC/F,MAAM,MAAM,GAAG,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QACrE,IAAI,MAAM,KAAK,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU;YAAE,OAAO;QAEpD,GAAG,CAAC,IAAI,CACP,+BAA+B,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,cAAc,MAAM,IAAI;YAC/E,iBAAiB,KAAK,YAAY,MAAM,6CAA6C,CACtF,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3D,CAAC;IAEO,KAAK,CAAC,YAAoB;QACjC,sEAAsE;QACtE,uCAAuC;QACvC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACpC,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ;gBAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;iBACzD,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM;gBAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;;gBAC1D,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAExB,IAAI,IAAI,CAAC,gBAAgB,GAAG,CAAC,EAAE,CAAC;YAC/B,8EAA8E;YAC9E,IAAI,CAAC,gBAAgB,IAAI,YAAY,CAAC;YACtC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;QAC9E,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC;QAE/B,kFAAkF;QAClF,4EAA4E;QAC5E,KAAK,CAAC,YAAY,EAAE,CAAC;QAErB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAEpC,yEAAyE;QACzE,KAAK,CAAC,QAAQ,EAAE,CAAC;IAClB,CAAC;IAEO,SAAS,CAAC,IAAyB;QAC1C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED,0EAA0E;IAClE,WAAW,CAAC,IAAyB;QAC5C,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;QAChC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAErC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QAEnB,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,+EAA+E;IACvE,SAAS,CAAC,IAAyB;QAC1C,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAErC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QAEnB,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,kEAAkE;IAC1D,QAAQ,CAAC,MAAe;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACvB,IAAI,GAAG;YAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;IAED,OAAO;QACN,KAAK,CAAC,MAAM,EAAE,CAAC;QACf,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACrB,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QACzB,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI;YAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IAClD,CAAC;CACD"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * A renderer's backing store is `width * resolution` by `height * resolution` pixels, and a
3
+ * device's GPU has a `MAX_TEXTURE_SIZE` it will not go past. `Game` used to ask for the
4
+ * display's full `devicePixelRatio` whatever the canvas size, which on a large enough canvas is
5
+ * a request the device cannot honour: WebGL answers that by clamping the drawing buffer rather
6
+ * than failing, so the game carries on rendering into a surface that is not the one it asked
7
+ * for, with nothing reported anywhere.
8
+ *
9
+ * Measured, not assumed: a full-window canvas of 816x1812 css pixels at `devicePixelRatio`
10
+ * 2.625 asks for 2121x4709, and a device reporting a 4096 limit produced a drawing buffer
11
+ * clamped to 2121x4096. That same process painted an entirely black screen, but that is *not*
12
+ * attributed here: the failure did not reproduce (the emulator reported 8192 on every later
13
+ * start) and a deliberately clamped 1050x10500 request rendered correctly on the next process,
14
+ * so the black screen's cause was never established. What stands on its own is the clamped
15
+ * request, which is a size the game never asked for and cannot see.
16
+ *
17
+ * So the request is kept inside what the device says it can make. Whole numbers, because whole
18
+ * device pixels are the point: a fractional ratio duplicates pixel columns unevenly, the same
19
+ * reason `Game` watches `devicePixelRatio` in the first place.
20
+ *
21
+ * @param width logical width in css pixels (`renderer.screen.width`)
22
+ * @param height logical height in css pixels
23
+ * @param devicePixelRatio what the display asks for; never exceeded
24
+ * @param maxTextureSize the GPU's own limit, or any non-finite/non-positive value for "no cap"
25
+ * @returns the resolution to resize with, never above `devicePixelRatio`, never below 1
26
+ */
27
+ export declare function fitResolution(width: number, height: number, devicePixelRatio: number, maxTextureSize: number): number;
28
+ //# sourceMappingURL=ResolutionFit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResolutionFit.d.ts","sourceRoot":"","sources":["../../src/two-d/ResolutionFit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CASrH"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * A renderer's backing store is `width * resolution` by `height * resolution` pixels, and a
3
+ * device's GPU has a `MAX_TEXTURE_SIZE` it will not go past. `Game` used to ask for the
4
+ * display's full `devicePixelRatio` whatever the canvas size, which on a large enough canvas is
5
+ * a request the device cannot honour: WebGL answers that by clamping the drawing buffer rather
6
+ * than failing, so the game carries on rendering into a surface that is not the one it asked
7
+ * for, with nothing reported anywhere.
8
+ *
9
+ * Measured, not assumed: a full-window canvas of 816x1812 css pixels at `devicePixelRatio`
10
+ * 2.625 asks for 2121x4709, and a device reporting a 4096 limit produced a drawing buffer
11
+ * clamped to 2121x4096. That same process painted an entirely black screen, but that is *not*
12
+ * attributed here: the failure did not reproduce (the emulator reported 8192 on every later
13
+ * start) and a deliberately clamped 1050x10500 request rendered correctly on the next process,
14
+ * so the black screen's cause was never established. What stands on its own is the clamped
15
+ * request, which is a size the game never asked for and cannot see.
16
+ *
17
+ * So the request is kept inside what the device says it can make. Whole numbers, because whole
18
+ * device pixels are the point: a fractional ratio duplicates pixel columns unevenly, the same
19
+ * reason `Game` watches `devicePixelRatio` in the first place.
20
+ *
21
+ * @param width logical width in css pixels (`renderer.screen.width`)
22
+ * @param height logical height in css pixels
23
+ * @param devicePixelRatio what the display asks for; never exceeded
24
+ * @param maxTextureSize the GPU's own limit, or any non-finite/non-positive value for "no cap"
25
+ * @returns the resolution to resize with, never above `devicePixelRatio`, never below 1
26
+ */
27
+ export function fitResolution(width, height, devicePixelRatio, maxTextureSize) {
28
+ const longest = Math.max(width, height);
29
+ if (!Number.isFinite(maxTextureSize) || maxTextureSize <= 0)
30
+ return devicePixelRatio;
31
+ if (!Number.isFinite(longest) || longest <= 0)
32
+ return devicePixelRatio;
33
+ if (longest * devicePixelRatio <= maxTextureSize)
34
+ return devicePixelRatio;
35
+ //a canvas longer than the limit even at 1x is left at 1x: nothing smaller can be offered,
36
+ //and scaling the scene down instead would move every coordinate a game depends on
37
+ return Math.max(1, Math.floor(maxTextureSize / longest));
38
+ }
39
+ //# sourceMappingURL=ResolutionFit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResolutionFit.js","sourceRoot":"","sources":["../../src/two-d/ResolutionFit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,MAAc,EAAE,gBAAwB,EAAE,cAAsB;IAC5G,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,cAAc,IAAI,CAAC;QAAE,OAAO,gBAAgB,CAAC;IACrF,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,gBAAgB,CAAC;IACvE,IAAI,OAAO,GAAG,gBAAgB,IAAI,cAAc;QAAE,OAAO,gBAAgB,CAAC;IAE1E,0FAA0F;IAC1F,kFAAkF;IAClF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,81 @@
1
+ import type { Catalog, Direction } from '../../i18n/index.ts';
2
+ import type { StageCommand, StoryScript } from './script.ts';
3
+ /**
4
+ * A terse, line-based text format for straight (non-branching) dialogue - the
5
+ * counterpart to `twee.ts`'s passage graphs, for the common case of a scene
6
+ * that is just a sequence of lines. `rpg` has its own wrapper around the same
7
+ * parsing engine (`core.parseDialogueLines`) for a text-only RPG's map events
8
+ * (`rpg.parseDialogueText`, targeting `EventCommand`) - declared separately
9
+ * here for the same reason `EventChoice` is declared separately from this
10
+ * module's own `Choice`: a text-only RPG built on `core` and `rpg` alone
11
+ * should not have to depend on `two-d` (and its Pixi peer dependency) just to
12
+ * parse dialogue text, and a Pixi-based visual novel that never touches map
13
+ * events should not have to pull in `rpg` either. The actual `@id`/`-`
14
+ * parsing logic lives once in `core.parseDialogueLines`, not copied between
15
+ * the two - only the final command shape (`as` here, `speaker` in `rpg`)
16
+ * differs. Three kinds of line:
17
+ *
18
+ * - `@id text` names who is speaking and says `text`; `@id` alone (no text)
19
+ * just registers the speaker, without saying anything yet.
20
+ * - `- text` continues the two-speaker exchange the first two `@id` lines
21
+ * opened, alternating speaker on every line: the first `-` after the two
22
+ * openers goes to whichever of them did not speak last, and so on.
23
+ * - any other non-blank line narrates, with no speaker.
24
+ *
25
+ * ```
26
+ * @alice Hello.
27
+ * @bob Hi!
28
+ * - How are you?
29
+ * - Fine, and you?
30
+ * ```
31
+ *
32
+ * The `-` shorthand is deliberately capped at two speakers: it exists for the
33
+ * two-character back-and-forth, not as a guess at which of three or more
34
+ * people talks next. A third distinct `@id` anywhere in the source is a
35
+ * parse error rather than a silent guess; a scene with more than two
36
+ * speakers writes `@id` on every line instead, same as it does today.
37
+ *
38
+ * Like `twee.ts`, lines reach `StageCommand.say` as plain, untranslated
39
+ * text - a game's own translation step decides how that text reaches a
40
+ * player, the same seam MWL's own `_("...")`-marked strings use (the source
41
+ * text doubles as the catalog key). `extractDialogueCatalog` builds that
42
+ * catalog the same way MWL's `extractCatalog` does, for a game that wants a
43
+ * translator-ready file to start from.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * import { parseDialogueText, StageScript } from '@datamoc/mw_games/two-d';
48
+ *
49
+ * declare const script: StageScript;
50
+ *
51
+ * const commands = parseDialogueText(`
52
+ * @alice Hello.
53
+ * @bob Hi!
54
+ * - How are you?
55
+ * - Fine, and you?
56
+ * `);
57
+ * await script.run(commands);
58
+ * ```
59
+ */
60
+ export declare function parseDialogueText(source: string): StageCommand[];
61
+ /**
62
+ * Collects every `say`/`ask` line's text into an identity catalog - each key
63
+ * mapping to itself, the same shape MWL's own `extractCatalog` builds from
64
+ * `_("...")`-marked strings - so a translator has real entries to work from
65
+ * instead of a wall of untranslated dialogue. Accepts either a flat command
66
+ * list (`parseDialogueText`'s own output) or a `StoryScript` graph
67
+ * (`importTwee`'s), so the same extraction step covers both dialogue paths.
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * import { parseDialogueText, extractDialogueCatalog } from '@datamoc/mw_games/two-d';
72
+ *
73
+ * const commands = parseDialogueText('@alice Hello.\n');
74
+ * console.log(extractDialogueCatalog(commands).messages); // { 'Hello.': 'Hello.' }
75
+ * ```
76
+ */
77
+ export declare function extractDialogueCatalog(commands: readonly StageCommand[] | StoryScript, options?: {
78
+ locale?: string;
79
+ direction?: Direction;
80
+ }): Catalog;
81
+ //# sourceMappingURL=dialogue-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialogue-text.d.ts","sourceRoot":"","sources":["../../../src/two-d/stage/dialogue-text.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAIhE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CACrC,QAAQ,EAAE,SAAS,YAAY,EAAE,GAAG,WAAW,EAC/C,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,SAAS,CAAA;CAAO,GACtD,OAAO,CAYT"}
@@ -0,0 +1,95 @@
1
+ import { parseDialogueLines } from '../../core/DialogueText.js';
2
+ /**
3
+ * A terse, line-based text format for straight (non-branching) dialogue - the
4
+ * counterpart to `twee.ts`'s passage graphs, for the common case of a scene
5
+ * that is just a sequence of lines. `rpg` has its own wrapper around the same
6
+ * parsing engine (`core.parseDialogueLines`) for a text-only RPG's map events
7
+ * (`rpg.parseDialogueText`, targeting `EventCommand`) - declared separately
8
+ * here for the same reason `EventChoice` is declared separately from this
9
+ * module's own `Choice`: a text-only RPG built on `core` and `rpg` alone
10
+ * should not have to depend on `two-d` (and its Pixi peer dependency) just to
11
+ * parse dialogue text, and a Pixi-based visual novel that never touches map
12
+ * events should not have to pull in `rpg` either. The actual `@id`/`-`
13
+ * parsing logic lives once in `core.parseDialogueLines`, not copied between
14
+ * the two - only the final command shape (`as` here, `speaker` in `rpg`)
15
+ * differs. Three kinds of line:
16
+ *
17
+ * - `@id text` names who is speaking and says `text`; `@id` alone (no text)
18
+ * just registers the speaker, without saying anything yet.
19
+ * - `- text` continues the two-speaker exchange the first two `@id` lines
20
+ * opened, alternating speaker on every line: the first `-` after the two
21
+ * openers goes to whichever of them did not speak last, and so on.
22
+ * - any other non-blank line narrates, with no speaker.
23
+ *
24
+ * ```
25
+ * @alice Hello.
26
+ * @bob Hi!
27
+ * - How are you?
28
+ * - Fine, and you?
29
+ * ```
30
+ *
31
+ * The `-` shorthand is deliberately capped at two speakers: it exists for the
32
+ * two-character back-and-forth, not as a guess at which of three or more
33
+ * people talks next. A third distinct `@id` anywhere in the source is a
34
+ * parse error rather than a silent guess; a scene with more than two
35
+ * speakers writes `@id` on every line instead, same as it does today.
36
+ *
37
+ * Like `twee.ts`, lines reach `StageCommand.say` as plain, untranslated
38
+ * text - a game's own translation step decides how that text reaches a
39
+ * player, the same seam MWL's own `_("...")`-marked strings use (the source
40
+ * text doubles as the catalog key). `extractDialogueCatalog` builds that
41
+ * catalog the same way MWL's `extractCatalog` does, for a game that wants a
42
+ * translator-ready file to start from.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * import { parseDialogueText, StageScript } from '@datamoc/mw_games/two-d';
47
+ *
48
+ * declare const script: StageScript;
49
+ *
50
+ * const commands = parseDialogueText(`
51
+ * @alice Hello.
52
+ * @bob Hi!
53
+ * - How are you?
54
+ * - Fine, and you?
55
+ * `);
56
+ * await script.run(commands);
57
+ * ```
58
+ */
59
+ export function parseDialogueText(source) {
60
+ return parseDialogueLines(source).map((line) => line.speaker === undefined ? { say: line.text } : { say: line.text, as: line.speaker });
61
+ }
62
+ /**
63
+ * Collects every `say`/`ask` line's text into an identity catalog - each key
64
+ * mapping to itself, the same shape MWL's own `extractCatalog` builds from
65
+ * `_("...")`-marked strings - so a translator has real entries to work from
66
+ * instead of a wall of untranslated dialogue. Accepts either a flat command
67
+ * list (`parseDialogueText`'s own output) or a `StoryScript` graph
68
+ * (`importTwee`'s), so the same extraction step covers both dialogue paths.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * import { parseDialogueText, extractDialogueCatalog } from '@datamoc/mw_games/two-d';
73
+ *
74
+ * const commands = parseDialogueText('@alice Hello.\n');
75
+ * console.log(extractDialogueCatalog(commands).messages); // { 'Hello.': 'Hello.' }
76
+ * ```
77
+ */
78
+ export function extractDialogueCatalog(commands, options = {}) {
79
+ const messages = {};
80
+ const collect = (list) => {
81
+ for (const command of list) {
82
+ if ('say' in command)
83
+ messages[command.say] = command.say;
84
+ else if ('ask' in command)
85
+ messages[command.ask] = command.ask;
86
+ }
87
+ };
88
+ if (Array.isArray(commands))
89
+ collect(commands);
90
+ else
91
+ for (const list of Object.values(commands))
92
+ collect(list);
93
+ return { locale: options.locale ?? 'en', direction: options.direction ?? 'ltr', messages };
94
+ }
95
+ //# sourceMappingURL=dialogue-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialogue-text.js","sourceRoot":"","sources":["../../../src/two-d/stage/dialogue-text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAIhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC/C,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAC9C,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,CACtF,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,sBAAsB,CACrC,QAA+C,EAC/C,OAAO,GAA+C,EAAE;IAExD,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,MAAM,OAAO,GAAG,CAAC,IAA6B,EAAQ,EAAE;QACvD,KAAK,MAAM,OAAO,IAAI,IAAI,EAAE,CAAC;YAC5B,IAAI,KAAK,IAAI,OAAO;gBAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;iBACrD,IAAI,KAAK,IAAI,OAAO;gBAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;QAChE,CAAC;IACF,CAAC,CAAC;IACF,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;QAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;;QAC1C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/D,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,KAAK,EAAE,QAAQ,EAAE,CAAC;AAC5F,CAAC"}
@@ -4,6 +4,7 @@ export { StageScript } from './script.ts';
4
4
  export type { StageCommand, StageChoice, StoryScript, ScriptOptions, ScriptState, HistoryEntry } from './script.ts';
5
5
  export { importTwee } from './twee.ts';
6
6
  export type { TwineStory } from './twee.ts';
7
+ export { parseDialogueText, extractDialogueCatalog } from './dialogue-text.ts';
7
8
  export { StoryScreen, StorySequence } from './StoryScreen.ts';
8
9
  export type { StoryBeat, StoryScreenOptions } from './StoryScreen.ts';
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/two-d/stage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAErF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACpH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC9D,YAAY,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/two-d/stage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAErF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACpH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE/E,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC9D,YAAY,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -1,5 +1,6 @@
1
1
  export { DialogueStage } from './DialogueStage.js';
2
2
  export { StageScript } from './script.js';
3
3
  export { importTwee } from './twee.js';
4
+ export { parseDialogueText, extractDialogueCatalog } from './dialogue-text.js';
4
5
  export { StoryScreen, StorySequence } from './StoryScreen.js';
5
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/two-d/stage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAGvC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/two-d/stage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE/E,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
@@ -12,31 +12,13 @@ export interface TwineStory {
12
12
  /**
13
13
  * Reads a `.twee` file into a `StoryScript`.
14
14
  *
15
- * Twee was chosen over Twine's `<tw-passagedata>` HTML export on purpose: it is
16
- * plain text, so this stays a pure string parser with no DOM - testable under
17
- * `node --test` and loadable through `mwg/assets` like any other text asset.
18
- *
19
- * Only structure is imported, and that answers the format question the roadmap
20
- * left open: each passage's text lines become `say` commands and its
21
- * `[[links]]` become one closing `ask` whose choices jump (`[[text]]`,
22
- * `[[text->target]]` and `[[target<-text]]`) - the last text line doubles as
23
- * the question, since a choice box needs a prompt and repeating it works.
24
- * No story-format macro language
25
- * (Harlowe, SugarCube, Chapbook) is interpreted - body text reaches the stage
26
- * untouched, and a link carrying a setter throws instead of silently dropping
27
- * the behaviour the setter described.
28
- *
29
- * ```twee
30
- * :: Start
31
- * You stand at a crossroads.
32
- *
33
- * [[Take the left path->Left]]
34
- * [[Take the right path->Right]]
35
- *
36
- * :: Left
37
- * The path ends at a wall.
38
- * [[Go back->Start]]
39
- * ```
15
+ * The actual parsing (passages, `[[links]]`, `StoryData`/`StoryTitle`) lives once in
16
+ * `core.parseTwee` - `rpg.importTwee` is the same wrapper around the same engine, targeting
17
+ * `EventStoryScript` instead, declared separately for the same reason `EventChoice` already
18
+ * duplicates `two-d/ui`'s `Choice`: a text-only RPG should not have to depend on `two-d` just
19
+ * to import a branching Twee story, and a Pixi-based visual novel that never touches map
20
+ * events should not have to depend on `rpg` either. `core.parseTwee`'s own doc comment covers
21
+ * the notation itself (passages, links, what a macro-carrying link does).
40
22
  *
41
23
  * @example
42
24
  * ```ts
@@ -1 +1 @@
1
- {"version":3,"file":"twee.d.ts","sourceRoot":"","sources":["../../../src/two-d/stage/twee.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,aAAa,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,WAAW,CAAC;IACnB,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CA0CrD"}
1
+ {"version":3,"file":"twee.d.ts","sourceRoot":"","sources":["../../../src/two-d/stage/twee.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,WAAW,CAAC;IACnB,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAGrD"}
@@ -1,31 +1,14 @@
1
+ import { parseTwee } from '../../core/Twee.js';
1
2
  /**
2
3
  * Reads a `.twee` file into a `StoryScript`.
3
4
  *
4
- * Twee was chosen over Twine's `<tw-passagedata>` HTML export on purpose: it is
5
- * plain text, so this stays a pure string parser with no DOM - testable under
6
- * `node --test` and loadable through `mwg/assets` like any other text asset.
7
- *
8
- * Only structure is imported, and that answers the format question the roadmap
9
- * left open: each passage's text lines become `say` commands and its
10
- * `[[links]]` become one closing `ask` whose choices jump (`[[text]]`,
11
- * `[[text->target]]` and `[[target<-text]]`) - the last text line doubles as
12
- * the question, since a choice box needs a prompt and repeating it works.
13
- * No story-format macro language
14
- * (Harlowe, SugarCube, Chapbook) is interpreted - body text reaches the stage
15
- * untouched, and a link carrying a setter throws instead of silently dropping
16
- * the behaviour the setter described.
17
- *
18
- * ```twee
19
- * :: Start
20
- * You stand at a crossroads.
21
- *
22
- * [[Take the left path->Left]]
23
- * [[Take the right path->Right]]
24
- *
25
- * :: Left
26
- * The path ends at a wall.
27
- * [[Go back->Start]]
28
- * ```
5
+ * The actual parsing (passages, `[[links]]`, `StoryData`/`StoryTitle`) lives once in
6
+ * `core.parseTwee` - `rpg.importTwee` is the same wrapper around the same engine, targeting
7
+ * `EventStoryScript` instead, declared separately for the same reason `EventChoice` already
8
+ * duplicates `two-d/ui`'s `Choice`: a text-only RPG should not have to depend on `two-d` just
9
+ * to import a branching Twee story, and a Pixi-based visual novel that never touches map
10
+ * events should not have to depend on `rpg` either. `core.parseTwee`'s own doc comment covers
11
+ * the notation itself (passages, links, what a macro-carrying link does).
29
12
  *
30
13
  * @example
31
14
  * ```ts
@@ -39,142 +22,7 @@
39
22
  * ```
40
23
  */
41
24
  export function importTwee(source) {
42
- const passages = splitPassages(source);
43
- if (passages.length === 0)
44
- throw new Error('this twee source has no passages - passages start with ":: Name"');
45
- const story = {};
46
- let title;
47
- let start;
48
- for (const passage of passages) {
49
- if (passage.name === 'StoryTitle') {
50
- title = passage.body.trim() || undefined;
51
- continue;
52
- }
53
- if (passage.name === 'StoryData') {
54
- start = readStart(passage.body);
55
- continue;
56
- }
57
- if (Object.prototype.hasOwnProperty.call(story, passage.name)) {
58
- throw new Error(`this twee source defines "${passage.name}" twice`);
59
- }
60
- story[passage.name] = passageCommands(passage.name, passage.body);
61
- }
62
- const names = Object.keys(story);
63
- if (names.length === 0)
64
- throw new Error('this twee source has no story passages, only StoryTitle/StoryData');
65
- if (start !== undefined && !Object.prototype.hasOwnProperty.call(story, start)) {
66
- throw new Error(`StoryData starts at "${start}", which is not a passage in this file`);
67
- }
68
- for (const [name, commands] of Object.entries(story)) {
69
- for (const command of commands) {
70
- if ('ask' in command) {
71
- for (const choice of command.choices) {
72
- if (choice.goto !== undefined && !Object.prototype.hasOwnProperty.call(story, choice.goto)) {
73
- throw new Error(`passage "${name}" links to "${choice.goto}", which is not a passage in this file`);
74
- }
75
- }
76
- }
77
- }
78
- }
79
- return { story, start: start ?? names[0], title };
80
- }
81
- /** cuts the source at every line starting with `::`, parsing headers into names */
82
- function splitPassages(source) {
83
- const out = [];
84
- let name = null;
85
- let body = [];
86
- const flush = () => {
87
- if (name !== null)
88
- out.push({ name, body: body.join('\n') });
89
- };
90
- for (const line of source.split('\n')) {
91
- if (line.startsWith('::')) {
92
- flush();
93
- name = parseHeader(line);
94
- body = [];
95
- }
96
- else if (name !== null) {
97
- body.push(line);
98
- }
99
- }
100
- flush();
101
- return out;
102
- }
103
- /** `:: Name [tags] {"meta": true}` - only the name survives; tags and position are editor concerns */
104
- function parseHeader(line) {
105
- const rest = line.slice(2).trim();
106
- const tagAt = rest.search(/[[{]/);
107
- const name = (tagAt === -1 ? rest : rest.slice(0, tagAt)).trim();
108
- if (!name)
109
- throw new Error(`a twee passage header needs a name, got "${line}"`);
110
- return name;
111
- }
112
- /** StoryData is JSON; only `start` matters to the runner, the rest is player furniture */
113
- function readStart(body) {
114
- let data;
115
- try {
116
- data = JSON.parse(body.trim());
117
- }
118
- catch {
119
- throw new Error('StoryData must be JSON - check the braces');
120
- }
121
- if (typeof data !== 'object' || data === null || Array.isArray(data)) {
122
- throw new Error('StoryData must be a JSON object');
123
- }
124
- const start = data.start;
125
- if (start !== undefined && typeof start !== 'string') {
126
- throw new Error('StoryData "start" must be a passage name');
127
- }
128
- return start;
129
- }
130
- /** text lines speak in order; the last one doubles as the prompt when links follow it */
131
- function passageCommands(passage, body) {
132
- const lines = [];
133
- const choices = [];
134
- for (const line of body.split('\n')) {
135
- const text = extractLinks(line, choices, passage).replace(/\s+/g, ' ').trim();
136
- if (text !== '')
137
- lines.push(text);
138
- }
139
- if (choices.length === 0)
140
- return lines.map((say) => ({ say }));
141
- const prompt = lines.pop() ?? '';
142
- return [...lines.map((say) => ({ say })), { ask: prompt, choices }];
143
- }
144
- /**
145
- * Pulls `[[links]]` out of a line, leaving the surrounding text behind.
146
- * Returns the line with the links removed.
147
- */
148
- function extractLinks(line, choices, passage) {
149
- let out = '';
150
- let rest = line;
151
- for (;;) {
152
- const open = rest.indexOf('[[');
153
- if (open === -1)
154
- return out + rest;
155
- const close = rest.indexOf(']]', open);
156
- if (close === -1) {
157
- throw new Error(`passage "${passage}" has a "[[" with no closing "]]" in "${line.trim()}"`);
158
- }
159
- out += rest.slice(0, open);
160
- choices.push(parseLink(rest.slice(open + 2, close), passage));
161
- rest = rest.slice(close + 2);
162
- }
163
- }
164
- function parseLink(inner, passage) {
165
- if (inner.includes('[') || inner.includes(']')) {
166
- throw new Error(`passage "${passage}" links with a setter ("${inner.trim()}") - ` +
167
- 'story-format macros are not imported, so the link is refused rather than half-read');
168
- }
169
- const forward = inner.indexOf('->');
170
- if (forward !== -1) {
171
- return { text: inner.slice(0, forward).trim(), goto: inner.slice(forward + 2).trim() };
172
- }
173
- const backward = inner.indexOf('<-');
174
- if (backward !== -1) {
175
- return { text: inner.slice(backward + 2).trim(), goto: inner.slice(0, backward).trim() };
176
- }
177
- const target = inner.trim();
178
- return { text: target, goto: target };
25
+ const { story, start, title } = parseTwee(source);
26
+ return title === undefined ? { story, start } : { story, start, title };
179
27
  }
180
28
  //# sourceMappingURL=twee.js.map