@lewismoten/gamemaker-sandbox-engine 0.0.0-stage → 3.3.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 (129) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +24 -0
  3. package/NOTICE.md +58 -0
  4. package/README.md +149 -2
  5. package/dist/assets/music.worklet-aD2x7RRM.js +466 -0
  6. package/dist/audio/cmfLoad.js +10 -0
  7. package/dist/audio/cmfPlayer.js +201 -0
  8. package/dist/audio/context.js +75 -0
  9. package/dist/audio/engine.js +173 -0
  10. package/dist/audio/mix.js +40 -0
  11. package/dist/audio/opl.js +245 -0
  12. package/dist/audio/output.js +40 -0
  13. package/dist/core/gameFiles.js +89 -0
  14. package/dist/engine/character.js +187 -0
  15. package/dist/engine/funcKeys.js +164 -0
  16. package/dist/engine/game.js +133 -0
  17. package/dist/engine/keys.js +68 -0
  18. package/dist/engine/machine.js +192 -0
  19. package/dist/engine/menus.js +135 -0
  20. package/dist/engine/monsters.js +259 -0
  21. package/dist/engine/playGain.js +10 -0
  22. package/dist/engine/playerLook.js +48 -0
  23. package/dist/engine/recorder.js +127 -0
  24. package/dist/engine/render.js +45 -0
  25. package/dist/engine/scene.js +324 -0
  26. package/dist/engine/scroll.js +79 -0
  27. package/dist/engine/showGraphic.js +107 -0
  28. package/dist/engine/slowPc.js +98 -0
  29. package/dist/engine/slowPcMusic.js +46 -0
  30. package/dist/engine/touch.js +61 -0
  31. package/dist/engine/world.js +205 -0
  32. package/dist/formats/binary.js +120 -0
  33. package/dist/formats/blocks.js +103 -0
  34. package/dist/formats/character.js +83 -0
  35. package/dist/formats/cmf.js +37 -0
  36. package/dist/formats/cmfEdit.js +154 -0
  37. package/dist/formats/cmfPreview.js +89 -0
  38. package/dist/formats/cmfSong.js +190 -0
  39. package/dist/formats/fli.js +340 -0
  40. package/dist/formats/fliFrames.js +34 -0
  41. package/dist/formats/fliLimits.js +54 -0
  42. package/dist/formats/game.js +198 -0
  43. package/dist/formats/gif.js +125 -0
  44. package/dist/formats/gifProgressive.js +99 -0
  45. package/dist/formats/graphicScripts.js +44 -0
  46. package/dist/formats/highscore.js +30 -0
  47. package/dist/formats/jpeg.js +359 -0
  48. package/dist/formats/map.js +38 -0
  49. package/dist/formats/monster.js +69 -0
  50. package/dist/formats/palette.js +58 -0
  51. package/dist/formats/recording.js +17 -0
  52. package/dist/formats/sound.js +44 -0
  53. package/dist/formats/voc.js +303 -0
  54. package/dist/gfx/colorVision.js +45 -0
  55. package/dist/gfx/cp437Glyphs.js +337 -0
  56. package/dist/gfx/font8x8.js +10 -0
  57. package/dist/gfx/screen.js +151 -0
  58. package/dist/index.js +15 -0
  59. package/dist/input/chords.js +46 -0
  60. package/dist/input/deskMouse.js +24 -0
  61. package/dist/input/keyboard.js +82 -0
  62. package/dist/input/scancodes.js +143 -0
  63. package/dist/player/fileExtensions.js +118 -0
  64. package/dist/player/patchRules.js +129 -0
  65. package/dist/player/patchTable.js +1753 -0
  66. package/dist/text/cp437.js +44 -0
  67. package/dist/types/audio/cmfLoad.d.ts +7 -0
  68. package/dist/types/audio/cmfPlayer.d.ts +69 -0
  69. package/dist/types/audio/context.d.ts +12 -0
  70. package/dist/types/audio/engine.d.ts +60 -0
  71. package/dist/types/audio/mix.d.ts +14 -0
  72. package/dist/types/audio/music.worklet.d.ts +22 -0
  73. package/dist/types/audio/opl.d.ts +37 -0
  74. package/dist/types/audio/output.d.ts +13 -0
  75. package/dist/types/core/gameFiles.d.ts +49 -0
  76. package/dist/types/engine/character.d.ts +30 -0
  77. package/dist/types/engine/funcKeys.d.ts +35 -0
  78. package/dist/types/engine/game.d.ts +57 -0
  79. package/dist/types/engine/keys.d.ts +17 -0
  80. package/dist/types/engine/machine.d.ts +103 -0
  81. package/dist/types/engine/menus.d.ts +46 -0
  82. package/dist/types/engine/monsters.d.ts +19 -0
  83. package/dist/types/engine/playGain.d.ts +11 -0
  84. package/dist/types/engine/playerLook.d.ts +44 -0
  85. package/dist/types/engine/recorder.d.ts +67 -0
  86. package/dist/types/engine/render.d.ts +8 -0
  87. package/dist/types/engine/scene.d.ts +188 -0
  88. package/dist/types/engine/scroll.d.ts +24 -0
  89. package/dist/types/engine/showGraphic.d.ts +39 -0
  90. package/dist/types/engine/slowPc.d.ts +124 -0
  91. package/dist/types/engine/slowPcMusic.d.ts +18 -0
  92. package/dist/types/engine/touch.d.ts +33 -0
  93. package/dist/types/engine/world.d.ts +237 -0
  94. package/dist/types/formats/binary.d.ts +44 -0
  95. package/dist/types/formats/blocks.d.ts +52 -0
  96. package/dist/types/formats/character.d.ts +65 -0
  97. package/dist/types/formats/cmf.d.ts +33 -0
  98. package/dist/types/formats/cmfEdit.d.ts +53 -0
  99. package/dist/types/formats/cmfPreview.d.ts +19 -0
  100. package/dist/types/formats/cmfSong.d.ts +74 -0
  101. package/dist/types/formats/fli.d.ts +56 -0
  102. package/dist/types/formats/fliFrames.d.ts +18 -0
  103. package/dist/types/formats/fliLimits.d.ts +13 -0
  104. package/dist/types/formats/game.d.ts +79 -0
  105. package/dist/types/formats/gif.d.ts +15 -0
  106. package/dist/types/formats/gifProgressive.d.ts +46 -0
  107. package/dist/types/formats/graphicScripts.d.ts +18 -0
  108. package/dist/types/formats/highscore.d.ts +10 -0
  109. package/dist/types/formats/jpeg.d.ts +20 -0
  110. package/dist/types/formats/map.d.ts +24 -0
  111. package/dist/types/formats/monster.d.ts +48 -0
  112. package/dist/types/formats/palette.d.ts +15 -0
  113. package/dist/types/formats/recording.d.ts +7 -0
  114. package/dist/types/formats/sound.d.ts +13 -0
  115. package/dist/types/formats/voc.d.ts +13 -0
  116. package/dist/types/gfx/colorVision.d.ts +26 -0
  117. package/dist/types/gfx/cp437Glyphs.d.ts +2 -0
  118. package/dist/types/gfx/font8x8.d.ts +2 -0
  119. package/dist/types/gfx/screen.d.ts +50 -0
  120. package/dist/types/index.d.ts +4 -0
  121. package/dist/types/input/chords.d.ts +22 -0
  122. package/dist/types/input/deskMouse.d.ts +14 -0
  123. package/dist/types/input/keyboard.d.ts +39 -0
  124. package/dist/types/input/scancodes.d.ts +3 -0
  125. package/dist/types/player/fileExtensions.d.ts +44 -0
  126. package/dist/types/player/patchRules.d.ts +24 -0
  127. package/dist/types/player/patchTable.d.ts +83 -0
  128. package/dist/types/text/cp437.d.ts +6 -0
  129. package/package.json +339 -4
@@ -0,0 +1,127 @@
1
+ import { parseRecording as a, RECLEN as n, serializeRecording as d } from "../formats/recording.js";
2
+ const r = 1, e = 2;
3
+ class u {
4
+ mode = 0;
5
+ keys = [];
6
+ index = 0;
7
+ timer = 0;
8
+ lastKeyPress = 0;
9
+ paused = !1;
10
+ initRecord() {
11
+ this.mode = r, this.keys = [], this.restart();
12
+ }
13
+ /**
14
+ * Whether waits for a key count toward playback time. PLAYGAME's GetKey called
15
+ * DoPlayBack on every poll, so while a "hit any key" screen waited the timer raced
16
+ * ahead (thousands of polls a second), and a demo recorded in DOS stores those polls
17
+ * as one huge DeltaTime before the key that dismissed the screen (Nebula's 26058).
18
+ * Demos recorded here count game ticks only, so for them waits must not count.
19
+ */
20
+ countsWaits = !1;
21
+ initPlayback(s) {
22
+ return s ? (this.keys = a(s), this.countsWaits = this.keys.some((t) => t.delta > 4096), this.mode = e, this.restart(), !0) : !1;
23
+ }
24
+ stop() {
25
+ this.mode = 0, this.restart();
26
+ }
27
+ restart() {
28
+ this.lastKeyPress = 0, this.index = 0, this.timer = 0, this.paused = !1;
29
+ }
30
+ pause() {
31
+ this.paused = !0;
32
+ }
33
+ unpause() {
34
+ this.paused = !1;
35
+ }
36
+ /** Game ticks counted since the recording or playback (re)started; the playback position. */
37
+ get tick() {
38
+ return this.timer;
39
+ }
40
+ get playing() {
41
+ return this.mode === e;
42
+ }
43
+ /** Paused: play has left the levels (the won/lost pictures and score table follow). */
44
+ get halted() {
45
+ return this.paused;
46
+ }
47
+ /** DoPlayBack: advance one tick; returns the keys that become pending now. */
48
+ doPlayback() {
49
+ const s = [];
50
+ if (this.paused || (this.timer++, this.mode !== e)) return s;
51
+ for (; this.index < this.keys.length && this.lastKeyPress + this.keys[this.index].delta <= this.timer; )
52
+ s.push(this.keys[this.index].key), this.lastKeyPress += this.keys[this.index].delta, this.index++;
53
+ return s;
54
+ }
55
+ /**
56
+ * GetKey polls while a screen waits for a key: `polls` calls to DoPlayBack at once.
57
+ * Returns the recorded keys that become pending (only for recordings made in DOS).
58
+ */
59
+ advanceWait(s) {
60
+ const t = [];
61
+ if (this.paused || this.mode !== e || !this.countsWaits) return t;
62
+ for (this.timer += s; this.index < this.keys.length && this.lastKeyPress + this.keys[this.index].delta <= this.timer; )
63
+ t.push(this.keys[this.index].key), this.lastKeyPress += this.keys[this.index].delta, this.index++;
64
+ return t;
65
+ }
66
+ /**
67
+ * One GetKey poll (DoPlayBack) by a key screen in a tick-counted recording, where waits
68
+ * otherwise don't count (advanceWait): the keys a demo gave that screen one tick after
69
+ * its opening key (DropBloc's Enter) become pending. Recordings made in DOS count their waits.
70
+ */
71
+ pollOnce() {
72
+ return this.paused || this.mode !== e || this.countsWaits ? [] : this.advanceByTick();
73
+ }
74
+ advanceByTick() {
75
+ const s = [];
76
+ for (this.timer++; this.index < this.keys.length && this.lastKeyPress + this.keys[this.index].delta <= this.timer; )
77
+ s.push(this.keys[this.index].key), this.lastKeyPress += this.keys[this.index].delta, this.index++;
78
+ return s;
79
+ }
80
+ /**
81
+ * A screen that read keys has finished. In DOS the next key may have come during it
82
+ * (the recording shows a gap of many thousands of polls), however fast that PC polled;
83
+ * catch up to it, and to keys a poll or two behind it (taken by the keyboard flush that
84
+ * follows every screen), so gameplay resumes in step. Only for DOS recordings.
85
+ */
86
+ finishWait() {
87
+ const s = [];
88
+ if (this.paused || this.mode !== e || !this.countsWaits) return s;
89
+ const t = this.keys[this.index];
90
+ if (!t || t.delta <= 1e3) return s;
91
+ for (this.timer = Math.max(this.timer, this.lastKeyPress + t.delta); this.index < this.keys.length; ) {
92
+ const i = this.keys[this.index], h = this.lastKeyPress + i.delta <= this.timer;
93
+ if (!h && i.delta > 2) break;
94
+ h || (this.timer = this.lastKeyPress + i.delta), s.push(i.key), this.lastKeyPress += i.delta, this.index++;
95
+ }
96
+ return s;
97
+ }
98
+ /**
99
+ * DoRecord: called when a key is actually applied to the character (keys held back
100
+ * while a sequence can't be interrupted are recorded on the tick they take effect).
101
+ * DeltaTime is a 16-bit uint in the C, and at most RECLEN keys are kept.
102
+ */
103
+ doRecord(s) {
104
+ this.paused || this.mode !== r || this.index >= n || (this.keys[this.index] = { key: s, delta: this.timer - this.lastKeyPress & 65535 }, this.lastKeyPress = this.timer, this.index++);
105
+ }
106
+ /** The recording so far, in .rec format. */
107
+ save() {
108
+ return d(this.keys.slice(0, this.index));
109
+ }
110
+ /** For save games (the C wrote the Recording object and its keys into the .sav). */
111
+ snapshot() {
112
+ return {
113
+ mode: this.mode,
114
+ keys: this.keys.slice(0, Math.max(this.index, this.keys.length)),
115
+ index: this.index,
116
+ timer: this.timer,
117
+ lastKeyPress: this.lastKeyPress
118
+ };
119
+ }
120
+ restore(s) {
121
+ Object.assign(this, { mode: s.mode, keys: s.keys, index: s.index, timer: s.timer, lastKeyPress: s.lastKeyPress, paused: !1 });
122
+ }
123
+ }
124
+ export {
125
+ r as RECORD,
126
+ u as Recorder
127
+ };
@@ -0,0 +1,45 @@
1
+ import { currentFrame as S } from "./character.js";
2
+ import { monPicNum as a } from "./monsters.js";
3
+ import { inScreenBounds as d } from "./touch.js";
4
+ import { SCRNBWID as y, SCRNBLEN as b, shownBlock as B, mapBlock as L, MAXMONSSHOWN as N, OFFSCRN as f } from "./world.js";
5
+ import { LASTMON as M, LASTSL as P } from "../formats/monster.js";
6
+ import { MLEN as h, MWID as k, LASTMM as I } from "../formats/map.js";
7
+ import { BLEN as p, MONBL as A, CHARBL as e } from "../formats/blocks.js";
8
+ const C = 312, D = 196;
9
+ function V(s) {
10
+ const { ci: o } = s;
11
+ o.update = !1, o.scrx > f && (o.oldx = o.scrx, o.oldy = o.scry, o.topthere = o.curtop < e, o.bottomthere = o.curbottom < e);
12
+ }
13
+ function _(s, o) {
14
+ const l = o.scroll.littleShiftx, n = o.scroll.littleShifty, x = o.scroll.nx + l, u = o.scroll.ny + n;
15
+ for (let t = 0; t <= y; t++)
16
+ for (let c = 0; c <= b; c++) {
17
+ const r = (o.mx + c) % h, m = (o.my + t) % k;
18
+ s.drawBlock(c * p - x, t * p - u, B(o, L(o, r, m)).pixels);
19
+ }
20
+ if (!o.noMons) {
21
+ let t = 0;
22
+ for (let c = 0; c < I && t < N; c++) {
23
+ const r = o.mi[c];
24
+ if (o.mm[c].monnum >= M || r.curPic < 0 || r.curPic >= P) continue;
25
+ const m = a(o, c);
26
+ if (!d(r.scrPos) || m >= A) {
27
+ r.picDrawn = !1;
28
+ continue;
29
+ }
30
+ t++, r.picDrawn = !0, r.oldPos = { ...r.scrPos }, s.drawSprite(r.scrPos.x - l, r.scrPos.y - n, r.orient, o.mblk[m].pixels);
31
+ }
32
+ }
33
+ const { ci: i } = o;
34
+ if (i.scrx > f) {
35
+ const t = S(o).orient;
36
+ i.curtop < e && s.drawSprite(i.scrx - l, i.scry - p - n, t & 15, o.cblk[i.curtop].pixels), i.curbottom < e && s.drawSprite(i.scrx - l, i.scry - n, t >> 4, o.cblk[i.curbottom].pixels);
37
+ }
38
+ s.boxFill(C, 0, 319, 199, 0), s.boxFill(0, D, 319, 199, 0);
39
+ }
40
+ export {
41
+ D as VISIBLE_H,
42
+ C as VISIBLE_W,
43
+ _ as renderWorld,
44
+ V as updateCharDrawState
45
+ };
@@ -0,0 +1,324 @@
1
+ import { aboutScreen as ge, statusScreen as he, helpScreen as be, drawLoadHeading as ve, pickSaveSlot as $, drawSaveHeading as xe, pickDropSlot as Se } from "./funcKeys.js";
2
+ import { moveCharGrav as X, handleJoystick as Q, updateCharScreenPos as Me, moveChars as Ce } from "./character.js";
3
+ import { resetKeys as z, simKeyPress as Le } from "./keys.js";
4
+ import { resetMonInfo as Ae, birthMon as we, blockBirthMonsters as Oe, moveAllMonsters as Te } from "./monsters.js";
5
+ import { renderWorld as V, updateCharDrawState as Pe } from "./render.js";
6
+ import { initScroll as Y, changeScroll as Ee, drawScroll as Ne } from "./scroll.js";
7
+ import { showGraphic as Z } from "./showGraphic.js";
8
+ import { playTuning as Ke, STOCK_LOOK as K } from "./playerLook.js";
9
+ import { getTouchBlocks as Be } from "./touch.js";
10
+ import { bgBlock as H, createWorld as qe, padBlocks as I, OFFSCRN as A, SCRNBLEN as ee, SCRNBWID as oe, NEVER as Re, mapBlock as De } from "./world.js";
11
+ import { BACKBL as C, parseBlocks as j, MONBL as F, CHARBL as N } from "../formats/blocks.js";
12
+ import { parseCharacter as Ie, MAXINV as _, MAXSEQ as E } from "../formats/character.js";
13
+ import { parseMonsters as je, LASTMON as Fe } from "../formats/monster.js";
14
+ import { parseMap as Ge, MLEN as te, MWID as ne, LASTMM as U } from "../formats/map.js";
15
+ import { parsePalette as Ue } from "../formats/palette.js";
16
+ import { parseSoundSet as ce, LASTSND as We } from "../formats/sound.js";
17
+ import { MAXSCENELINKS as M, NOSCENE as Ve } from "../formats/game.js";
18
+ import { TICK_RATE as He } from "../audio/cmfPlayer.js";
19
+ import { SlowCpu as _e, tickCost as J, sceneLoadMs as Je, vocStallMs as $e, vocWontFit as Xe, musicHoldMs as Qe, scrollCost as ze } from "./slowPc.js";
20
+ import { songIsrMs as Ye, songLoad as Ze } from "./slowPcMusic.js";
21
+ import { newPlayGain as re, gainAtLoad as eo } from "./playGain.js";
22
+ const G = 2;
23
+ function B(e, r, t) {
24
+ return e.scenes[r]?.files[t] || void 0;
25
+ }
26
+ function se(e, r, t) {
27
+ const { m: c, game: o } = e, s = (y) => B(o, r, y), i = [], a = (y) => {
28
+ const b = s(y);
29
+ if (!b) return;
30
+ const T = c.files.get(b);
31
+ return T || i.push(b), T;
32
+ }, d = a(0), v = a(1), g = a(2), n = a(3), x = a(4), S = a(5), L = a(6);
33
+ if (i.length) return i;
34
+ const u = qe(Ge(v ?? new Uint8Array(0)), { play: () => !1 }, e.rand?.());
35
+ u.tune = Ke(e.look ?? K), d ? u.palette = Ue(d) : t && (u.palette = t.palette), u.bg = I(g ? j(g, C) : t?.bg.slice(0, C), C), u.mblk = I(x ? j(x, F) : t?.mblk.slice(0, F), F), u.cblk = I(L ? j(L, N) : t?.cblk.slice(0, N), N), u.mon = n ? je(n) : t?.mon ?? [], u.noMons = !s(3) || !s(4);
36
+ const h = e.onTouched;
37
+ if (h && (u.onTouched = (y, b, T) => h(r, y, b, T)), u.chr = S ? Ie(S) : t.chr, !u.chr) return [s(5) ?? "character"];
38
+ const P = s(7), w = P ? c.files.get(P) : void 0, O = s(8);
39
+ return { world: u, sounds: w ? ce(w) : void 0, song: O ? c.files.get(O) : void 0 };
40
+ }
41
+ const ie = [0, 1, 2, 3, 4, 5, 6, 7], oo = [0, 2, 3, 4, 6, 7];
42
+ function to(e, r, t, c = ie) {
43
+ const o = [];
44
+ for (const s of t ? [...c, 8] : c) {
45
+ const i = B(e.game, r, s);
46
+ i && o.push(e.m.files.get(i)?.length ?? 0);
47
+ }
48
+ return o;
49
+ }
50
+ async function ae(e, r, t) {
51
+ const c = e.speed.slowPc;
52
+ if (!c || c.vocOpenMs === void 0 || !c.vocBytesPerMs) {
53
+ e.sceneLoad && (e.sceneLoad = void 0);
54
+ return;
55
+ }
56
+ const o = to(e, r, e.m.audio.musicEnabled, t), s = Je(c, o);
57
+ e.sceneLoad = { files: o.length, bytes: o.reduce((i, a) => i + a, 0), ms: s }, s > 0 && (me(e, s), await e.m.sleep(s));
58
+ }
59
+ async function le(e, r) {
60
+ const { m: t, game: c } = e, o = c.scenes[r]?.files ?? [];
61
+ await t.need(...o.slice(0, 9));
62
+ const s = o[7] ? t.files.get(o[7]) : void 0;
63
+ let i = [];
64
+ try {
65
+ i = s ? ce(s).digital.filter((d) => d && d[0] !== " ").map((d) => `${d}.voc`) : [];
66
+ } catch {
67
+ }
68
+ await t.need(...i);
69
+ const a = (c.scenes[r]?.links ?? []).flatMap((d) => c.scenes[d.toScene]?.files.slice(0, 10) ?? []);
70
+ t.want(o[10], ...a);
71
+ }
72
+ function no(e, r) {
73
+ e.vocStall = (e.vocStall ?? 0) + r, me(e, r);
74
+ }
75
+ function me(e, r) {
76
+ e.m.audio.holdMusic(Qe(e.speed.slowPc, r));
77
+ }
78
+ function fe(e, r, t) {
79
+ r.sound = {
80
+ play: (c) => {
81
+ if (!t || !e.soundOn || c < 0 || c >= We) return !1;
82
+ const o = t.digital[c];
83
+ if (!e.speakerOnly && e.m.audio.soundCardEnabled !== !1 && o && o[0] !== " ") {
84
+ const s = e.m.files.get(`${o}.voc`), i = e.speed.slowPc, a = s ? $e(i, s.length) : 0;
85
+ !s || !i || !a ? e.m.audio.playVoc(s) : (e.m.audio.stopVoc(), no(e, a), Xe(i, s.length) ? e.vocLate = void 0 : e.vocLate = { bytes: s, wait: (e.vocLate?.wait ?? 0) + a });
86
+ } else e.m.audio.playSpeaker(t.freqs[c]);
87
+ return !0;
88
+ }
89
+ }, r.joystick = e.joystick;
90
+ }
91
+ function qo(e) {
92
+ e.timerCounter = 1, e.sndClock = 1;
93
+ const r = e.ci;
94
+ r.hitpts = -1, r.lives = -1, r.score = 0, e.gain = re(), r.inv.fill(C + 1), r.meter.fill(-1);
95
+ }
96
+ function co(e, r) {
97
+ const { ci: t, chr: c } = e;
98
+ if (t.inv[0] === C + 1) for (let o = 0; o < _; o++) t.inv[o] = c.inv[o];
99
+ for (let o = 0; o < E; o++)
100
+ t.seqon[o] = c.sequences[o].bloc === C, t.meter[o] === -2e4 && (t.meter[o] = c.meter[o]);
101
+ for (let o = 0; o < _; o++) for (let s = 0; s < E; s++) c.sequences[s].bloc === t.inv[o] && (t.seqon[s] = !0);
102
+ if (t.meter[0] === -1) {
103
+ for (let o = 0; o < 5; o++) t.meter[o] = c.meter[o];
104
+ for (let o = 5; o < E; o++) t.meter[o] = c.sequences[o].key > 0 ? c.meter[o] : -2e4;
105
+ for (let o = E; o < E + 10; o++) t.meter[o] = c.meter[o];
106
+ }
107
+ c.x[0] = r.x, c.y[0] = r.y, c.x[1] = 0, c.y[1] = 0, c.cseq = 0, c.cframe = -1, t.hitpts === -1 && (t.hitpts = t.meter[0]), t.lives === -1 && (t.lives = t.meter[1]), t.netx = 5, t.nety = 0, t.gravx = 0, t.gravy = 0, t.scrx = t.oldx = t.nextx = A, t.scry = t.oldy = t.nexty = A, t.topthere = !1, t.bottomthere = !1, t.curtop = N, t.curbottom = N, t.nextAni = e.clock, e.mx = r.x - ee / 2, e.my = r.y - oe / 2, e.mx < 0 && (e.mx += te), e.my < 0 && (e.my += ne);
108
+ for (let o = 0; o < U; o++)
109
+ Ae(e.mi[o]), we(e, o, e.mm[o].monnum, e.mm[o].curx, e.mm[o].cury), e.mi[o].fromchar = 0;
110
+ for (let o = 0; o < C; o++)
111
+ e.blkmap[o] = o, e.nxtchg[o] = e.bg[o].ntime > 0 ? e.clock + e.bg[o].ntime : Re;
112
+ if (e.blkMon = [], !e.noMons)
113
+ for (let o = 0; o < C; o++) e.bg[o].birthTime > 0 && e.blkMon.push({ blnum: o, nexttime: e.clock + e.bg[o].birthTime });
114
+ z(e), ro(e.keydn, c.sequences[c.cseq].key);
115
+ }
116
+ function ro(e, r) {
117
+ r >= 0 && r < 128 && (e[r] = 1);
118
+ }
119
+ function so(e) {
120
+ for (let r = 0; r < C; r++) {
121
+ const t = e.blkmap[r], c = H(e, t);
122
+ e.nxtchg[r] <= e.clock && c.nextBl !== t && (e.blkmap[r] = c.nextBl, e.nxtchg[r] = c.ntime <= 0 ? 0 : e.nxtchg[r] + H(e, e.blkmap[r]).ntime);
123
+ }
124
+ }
125
+ function io(e, r, t) {
126
+ const c = Be(r), o = e.game.scenes[t].links;
127
+ for (let s = 0; s < M; s++) {
128
+ const i = o[s];
129
+ if (!(!i || i.toScene === Ve)) {
130
+ for (let a = 0; a < 6; a++)
131
+ if (i.from.x === c.blks[a][0] && i.from.y === c.blks[a][1])
132
+ return r.chr.x[0] = i.to.x, r.chr.y[0] = i.to.y, s;
133
+ }
134
+ }
135
+ return M;
136
+ }
137
+ async function ao(e, r) {
138
+ const { m: t } = e, c = e.look ?? K;
139
+ t.screen.setPalette(new Uint8Array(768));
140
+ for (let o = 1; o <= 4; o++) t.screen.setColor(o, ...c.rgb(`color.missing.${o}`));
141
+ t.screen.clear(), t.screen.box(...c.frame("border.missing.outer"), 4), t.screen.box(...c.frame("border.missing.inner"), 4), t.screen.write(40, 20, 1, c.text("str.missing.title")), r.forEach((o, s) => t.screen.write(32, (9 + s) * 8, 2, o)), t.screen.write(120, 168, 3, c.text("str.missing.anyKey")), await t.pauseTimeKey(c.seconds("timing.missingFiles"));
142
+ }
143
+ async function Ro(e, r, t, c) {
144
+ const { m: o, game: s } = e, i = e.look ?? K;
145
+ let a = r, d = t, v = c;
146
+ o.screen.setPaletteTo(0, 0, 0), await le(e, a);
147
+ const g = se(e, a, e.lastWorld);
148
+ if (Array.isArray(g))
149
+ return await ao(e, g), { ok: !1, link: M + 1 };
150
+ await ae(e, a, ie);
151
+ let n = g.world;
152
+ e.lastWorld = n, n.ci = e.ci, n.clock = e.timerCounter, fe(e, n, g.sounds);
153
+ let x = g.song;
154
+ e.musicOn && o.audio.playSong(x), co(n, s.scenes[d]?.links[v]?.to ?? { x: 0, y: 0 }), X(n, !0), Q(n, !0), Y(n, s.scenes[a].scroll), e.colors = n.palette, o.screen.dosCropped = !0, o.screen.sceneNumber = a, V(o.screen, n), await o.fadeTo(n.palette, n.tune.fadeSteps), o.keyboard.attach();
155
+ const L = new Set(n.chr.sequences.map((l) => l.key >> 8).filter((l) => l));
156
+ o.keyboard.chordable = (l) => L.has(l), o.flushKeys();
157
+ let u = 0, h = M, P = !1, w = e.timerCounter;
158
+ const O = 1e3 / He, y = new _e(O);
159
+ let b;
160
+ const T = (l) => ((!b || b.song !== l) && (b = { song: l, load: Ze(l) }), b.load), ue = () => {
161
+ let l = 0;
162
+ for (let p = 0; p < U && l < 50; p++) n.mm[p].monnum < Fe && n.mi[p].scrPos.x !== A && l++;
163
+ return l;
164
+ }, R = new Uint8Array(n.blkmap.length), pe = () => {
165
+ let l = 0;
166
+ for (let p = 0; p < oe; p++)
167
+ for (let m = 0; m < ee; m++) {
168
+ const k = De(n, (n.mx + m) % te, (n.my + p) % ne);
169
+ k < R.length && n.blkmap[k] !== R[k] && l++;
170
+ }
171
+ return l;
172
+ };
173
+ let D = o.now(), q = 0;
174
+ const W = () => {
175
+ D = o.now(), q = 0;
176
+ }, ke = async () => {
177
+ n.clock = w = e.timerCounter, n.noMons || (Oe(n), Te(n)), o.keyboard.typed.length = 0;
178
+ const l = o.keyboard.events.splice(0);
179
+ for (const m of e.rec.doPlayback()) l.push(m);
180
+ if (l.length && (!n.chr.sequences[n.chr.cseq].ground || n.chr.cframe === 0)) {
181
+ for (const m of l)
182
+ e.rec.doRecord(m), Le(n, m);
183
+ for (const m of l) (m === 1 || m >= 59 && m <= 68) && (n.keydn[m] = 1);
184
+ } else l.length && o.keyboard.events.unshift(...l);
185
+ let p = 0;
186
+ do
187
+ await Ce(n, async () => {
188
+ const m = await Se(o, n, i);
189
+ return o.flushKeys(), n.keydn.fill(0), W(), m;
190
+ }) && (u = G);
191
+ while (n.chr.cframe === -1 && u !== G && p++ < 50);
192
+ so(n), Pe(n), P = Ee(n) !== 0, n.monsolid = 0, n.mmSolid = U, h = io(e, n, a);
193
+ }, ye = async (l) => {
194
+ const p = e.sndClock;
195
+ o.audio.stopSpeaker(), o.screen.dosCropped = !1, o.screen.clear(), n.keydn.fill(0), o.flushKeys();
196
+ const m = n.palette;
197
+ switch (o.screen.setPalette(m), i.fkeyOn(l) ? l : 0) {
198
+ case 1:
199
+ await be(o, n, B(s, 0, 6), e.gmHelp, i);
200
+ break;
201
+ case 2:
202
+ await he(o, n, i);
203
+ break;
204
+ case 5:
205
+ await mo(e, n, { prevscene: d, doscene: a, linkin: v });
206
+ break;
207
+ case 6: {
208
+ const f = await uo(e, n);
209
+ f && ({ w: n, prevscene: d, doscene: a, linkin: v, song: x } = { ...f, song: f.song });
210
+ break;
211
+ }
212
+ case 9:
213
+ o.screen.write(40, 80, i.color(m, "color.select.joyText"), "Joysticks are configured by"), o.screen.write(40, 88, i.color(m, "color.select.joyText"), "your browser (Gamepad API)."), await o.pauseTimeKey(5);
214
+ break;
215
+ case 10:
216
+ await ge(o, n, i);
217
+ break;
218
+ }
219
+ const k = e.sndClock >> 3;
220
+ for (const f of n.mi)
221
+ f.nextAni = k, f.nextMove = k, f.scrPos = { x: A, y: A }, f.oldPos = { x: A, y: A }, f.picDrawn = !1;
222
+ n.scroll.nx = n.scroll.ny = 0, n.scroll.movx = n.scroll.movy = 0, z(n), n.chr.cseq = 0, n.chr.cframe = 0, n.ci.topthere = n.ci.bottomthere = !1, Me(n), n.ci.scrx = n.ci.nextx, n.ci.scry = n.ci.nexty, o.screen.setPalette(n.palette), e.colors = n.palette, l !== 6 && (e.sndClock = p), e.timerCounter = n.clock = e.sndClock >> 3, w = e.timerCounter, o.flushKeys(), W();
223
+ };
224
+ for (; !u && h === M; ) {
225
+ await o.frame();
226
+ const l = o.now();
227
+ q += l - D, D = l;
228
+ let p = Math.floor(q / O);
229
+ q -= p * O, p > 40 && (p = 40);
230
+ for (let m = 0; m < p && !u && h === M; m++) {
231
+ (e.sndClock & 7) === 0 && e.timerCounter++, e.sndClock++;
232
+ const k = e.speed.slowPc;
233
+ if (!k) y.reset();
234
+ else if (y.spend(Ye(k, e.musicOn && o.audio.musicEnabled ? T(x) : void 0)), y.busy()) continue;
235
+ if (P) {
236
+ const f = Ne(n);
237
+ k && y.spend(ze(k, f));
238
+ }
239
+ if (n.keydn[1]) {
240
+ u = 1;
241
+ break;
242
+ }
243
+ for (let f = 1; f <= 10; f++)
244
+ n.keydn[58 + f] && (n.keydn[58 + f] = 0, f === 3 ? o.audio.musicEnabled && (e.musicOn = !e.musicOn, e.musicOn ? o.audio.playSong(x) : o.audio.stopSong()) : f === 4 ? e.soundOn = !e.soundOn : f === 8 ? n.jstickOn = !n.jstickOn : f !== 7 && await ye(f));
245
+ w < e.timerCounter && (k && (y.spend(J(k, ue())), R.set(n.blkmap)), e.vocStall = 0, await ke(), k && k.cellMs && y.spend(J({ ...k, tickMs: 0, monsterMs: 0 }, 0, pe())), k && e.vocStall && y.spend(e.vocStall), e.vocStall = 0);
246
+ }
247
+ e.vocLate && (e.vocLate.due ??= l + e.vocLate.wait, l >= e.vocLate.due && (e.m.audio.playVoc(e.vocLate.bytes), e.vocLate = void 0)), o.screen.dosCropped = !0, o.screen.sceneNumber = a, V(o.screen, n), e.onFrame?.(n);
248
+ }
249
+ return e.vocLate = void 0, o.audio.stopSong(), o.audio.stopSpeaker(), await o.fadeAllTo(0, 0, 0, n.tune.fadeSteps), o.screen.dosCropped = !1, o.keyboard.detach(), o.keyboard.chordable = void 0, o.keyboard.attach(), n.keydn[1] && (h = M + 1), u === G && (e.rec.playing || e.onLifeLost?.(), e.ci.lives > 0 ? (e.ci.lives--, e.ci.hitpts = -1, h = M) : h = M + 2), { ok: !0, link: h, doscene: a, prevscene: d };
250
+ }
251
+ const de = (e) => `game${e}.sav`;
252
+ function lo(e, r, t, c) {
253
+ return {
254
+ version: 1,
255
+ ...r,
256
+ sndClock: t,
257
+ world: {
258
+ nxtchg: e.nxtchg,
259
+ ci: e.ci,
260
+ mx: e.mx,
261
+ my: e.my,
262
+ mi: e.mi,
263
+ mm: e.mm,
264
+ noMons: e.noMons,
265
+ blkMon: e.blkMon,
266
+ blkmap: [...e.blkmap],
267
+ map: [...e.map],
268
+ mapMon: [...e.mapMon],
269
+ chr: { x: e.chr.x, y: e.chr.y, cframe: e.chr.cframe, cseq: e.chr.cseq }
270
+ },
271
+ rec: c.snapshot()
272
+ };
273
+ }
274
+ async function mo(e, r, t) {
275
+ const { m: c, game: o } = e, s = e.look ?? K;
276
+ e.rec.pause();
277
+ const i = B(o, 0, 10), a = new Uint8Array(768);
278
+ i ? await Z(c, i, { cols: a, pause: 0, gamePalette: r.palette, look: s }) : (a.set(r.palette), xe(c.screen, s, a));
279
+ const d = await $(c, a, !0, s);
280
+ d >= 0 && (c.files.set(de(d), new TextEncoder().encode(JSON.stringify(lo(r, t, e.sndClock, e.rec)))), c.screen.write(112, 185, s.color(a, i ? "color.select.saveTextPic" : "color.select.saveText"), s.text("str.save.done")), await c.pauseTimeKey(s.seconds("timing.saveMessage"))), e.rec.unpause();
281
+ }
282
+ function fo(e, r, t) {
283
+ const c = se(e, t.doscene, r);
284
+ if (Array.isArray(c)) return;
285
+ const o = c.world, s = t.world;
286
+ return Object.assign(o, { nxtchg: s.nxtchg, mx: s.mx, my: s.my, mi: s.mi, mm: s.mm, noMons: s.noMons, blkMon: s.blkMon }), o.blkmap = Uint8Array.from(s.blkmap), o.map = Uint8Array.from(s.map), o.mapMon = Uint8Array.from(s.mapMon), Object.assign(e.ci, s.ci), o.ci = e.ci, Object.assign(o.chr, s.chr), Y(o, e.game.scenes[t.doscene].scroll), e.rec.restore(t.rec), e.sndClock = t.sndClock, o.clock = e.sndClock >> 3, X(o, !0), Q(o, !0), c;
287
+ }
288
+ async function uo(e, r) {
289
+ const { m: t, game: c } = e, o = e.look ?? K, s = B(c, 0, 9), i = new Uint8Array(768);
290
+ s ? await Z(t, s, { cols: i, pause: 0, gamePalette: r.palette, look: o }) : (i.set(r.palette), ve(t.screen, o, i));
291
+ const a = await $(t, i, !1, o);
292
+ if (a < 0) return;
293
+ const d = t.files.get(de(a)), v = o.color(i, s ? "color.select.loadTextPic" : "color.select.loadText"), g = o.seconds("timing.loadMessage");
294
+ if (!d) {
295
+ t.screen.write(40, 185, v, o.text("str.load.empty")), await t.pauseTimeKey(g);
296
+ return;
297
+ }
298
+ let n;
299
+ try {
300
+ n = JSON.parse(new TextDecoder().decode(d));
301
+ } catch {
302
+ t.screen.write(40, 185, v, "This saved game is damaged!"), await t.pauseTimeKey(g);
303
+ return;
304
+ }
305
+ await le(e, n.doscene);
306
+ const x = e.ci.score, S = fo(e, r, n);
307
+ if (!S) return;
308
+ eo(e.gain ??= re(), x, e.ci.score);
309
+ const L = S.world;
310
+ return fe(e, L, S.sounds), t.screen.write(88, 185, v, o.text("str.load.done")), await ae(e, n.doscene, oo), await t.pauseTimeKey(g), e.musicOn && t.audio.playSong(S.song), { w: L, prevscene: n.prevscene, doscene: n.doscene, linkin: n.linkin, song: S.song };
311
+ }
312
+ export {
313
+ oo as LOADGAME_SLOTS,
314
+ so as changeBlocks,
315
+ se as loadScene,
316
+ Ro as playScene,
317
+ fo as restoreSaved,
318
+ lo as savedState,
319
+ B as sceneFile,
320
+ to as sceneReads,
321
+ ro as setStartKey,
322
+ qo as startGameInits,
323
+ co as startSceneInits
324
+ };
@@ -0,0 +1,79 @@
1
+ import { updateCharDrawState as v } from "./render.js";
2
+ import { inScreenBounds as g } from "./touch.js";
3
+ import { SIZEX as m, SIZEY as M, i16 as s, sign as c, OFFSCRN as r } from "./world.js";
4
+ import { BLEN as x, SOLLEF as a, SOLRIG as f, SOLTOP as S, SOLBOT as d } from "../formats/blocks.js";
5
+ import { MLEN as p, MWID as u, LASTMM as L } from "../formats/map.js";
6
+ import { LASTMON as O } from "../formats/monster.js";
7
+ function T(i, t) {
8
+ const o = i.scroll;
9
+ Object.assign(o, {
10
+ nx: 0,
11
+ ny: 0,
12
+ totalx: 0,
13
+ totaly: 0,
14
+ distx: 0,
15
+ disty: 0,
16
+ inMotion: 0,
17
+ movx: 0,
18
+ movy: 0,
19
+ littleShiftx: 0,
20
+ littleShifty: 0,
21
+ bx: { dscroll: 0, ctr: 0, iters: 0 },
22
+ by: { dscroll: 0, ctr: 0, iters: 0 }
23
+ }), o.up = t.down, o.down = t.up, o.left = t.right, o.right = t.left, o.maxX = m / 3, o.minX = -m / 3, o.maxY = 60, o.minY = -60, o.upStop = Math.trunc(-M / 6), o.downStop = Math.trunc(M / 6), o.leftStop = -m / 4, o.rightStop = m / 4;
24
+ }
25
+ function y(i, t, o, n = !1) {
26
+ let l = s(s(i) * t);
27
+ return n && (l = s(-l)), s(Math.trunc(l / s(o)));
28
+ }
29
+ function B(i) {
30
+ const t = i.scroll;
31
+ t.totalx = t.totaly = 0;
32
+ const o = i.ci.nextx + x / 2 - m / 2, n = i.ci.nexty + x / 2 - M / 2;
33
+ return t.distx = o, t.disty = n, t.left === 255 && o > t.maxX && (t.inMotion |= a), t.right === 255 && o < t.minX && (t.inMotion |= f), t.up === 255 && n > t.maxY && (t.inMotion |= S), t.down === 255 && n < t.minY && (t.inMotion |= d), t.inMotion & a && (o < t.leftStop ? t.inMotion &= ~a : t.totalx = y(o - t.leftStop, i.tune.scrollSpeedX, t.maxX - t.leftStop)), t.inMotion & f && (o > t.rightStop ? t.inMotion &= ~f : t.totalx = y(-o + t.rightStop, i.tune.scrollSpeedX, t.rightStop - t.minX, !0)), t.inMotion & S && (n < t.upStop ? t.inMotion &= ~S : t.totaly = y(n - t.upStop, i.tune.scrollSpeedY, t.maxY - t.upStop)), t.inMotion & d && (n > t.downStop ? t.inMotion &= ~d : t.totaly = y(-n + t.downStop, i.tune.scrollSpeedY, t.downStop - t.minY, !0)), t.totalx = Math.max(-28, Math.min(28, t.totalx)), t.totaly = Math.max(-28, Math.min(28, t.totaly)), t.bx = { dscroll: t.totalx, ctr: 0, iters: i.tune.scrollSteps }, t.by = { dscroll: t.totaly, ctr: 0, iters: i.tune.scrollSteps }, t.inMotion;
34
+ }
35
+ function h(i) {
36
+ let t = 0;
37
+ const o = Math.abs(i.dscroll);
38
+ if (o > i.iters) {
39
+ for (; i.ctr < o; )
40
+ t += c(i.dscroll), i.ctr += i.iters;
41
+ i.ctr -= o;
42
+ } else
43
+ i.ctr += o, i.ctr >= i.iters && (i.ctr -= i.iters, t += c(i.dscroll));
44
+ return t;
45
+ }
46
+ function P(i, t) {
47
+ for (let l = 0; l < L; l++) {
48
+ if (i.mm[l].monnum >= O) continue;
49
+ const e = i.mi[l];
50
+ e.scrPos.x !== r && (e.scrPos.x += t.x, e.scrPos.y += t.y), e.oldPos.x !== r && (e.oldPos.x += t.x, e.oldPos.y += t.y, g(e.oldPos) || (e.oldPos = { x: r, y: r }));
51
+ }
52
+ const o = i.ci;
53
+ let n = !1;
54
+ return o.nexty - o.oldy === 0 || c(t.y) === c(o.nexty - o.oldy) ? o.scry !== r && (o.scry += t.y) : (n = !0, Math.abs(o.nexty - o.oldy) < 4 && (o.scry += o.nexty - o.oldy + t.y)), o.nextx - o.oldx === 0 || c(t.x) === c(o.nextx - o.oldx) ? o.scrx !== r && (o.scrx += t.x) : (n = !0, Math.abs(o.nextx - o.oldx) < 4 && (o.scrx += o.nextx - o.oldx + t.x)), o.nextx !== r && (o.nextx += t.x, o.nexty += t.y), o.oldx !== r && (o.oldx += t.x, o.oldy += t.y), n;
55
+ }
56
+ function F(i) {
57
+ const t = i.scroll;
58
+ t.movx += h(t.bx), t.movy += h(t.by);
59
+ const o = { x: 0, y: 0 };
60
+ if (t.movx < 0)
61
+ for (; t.movx < 0; )
62
+ o.x += 4, t.movx += 4, t.nx -= 4;
63
+ else if (t.movx > 0)
64
+ for (; t.movx > 3; )
65
+ o.x -= 4, t.movx -= 4, t.nx += 4;
66
+ if (t.movy < 0)
67
+ for (; t.movy < 0; )
68
+ o.y += 4, t.movy += 4, t.ny -= 4;
69
+ else if (t.movy > 0)
70
+ for (; t.movy > 3; )
71
+ o.y -= 4, t.movy -= 4, t.ny += 4;
72
+ return t.littleShiftx = t.movx & 3, t.littleShifty = t.movy & 3, t.nx >= x && (t.nx -= x, i.mx = (i.mx + 1) % p), t.ny >= x && (t.ny -= x, i.my = (i.my + 1) % u), t.nx < 0 && (t.nx += x, i.mx = (i.mx - 1 + p) % p), t.ny < 0 && (t.ny += x, i.my = (i.my - 1 + u) % u), ((o.x || o.y) && P(i, o) || t.littleShiftx || t.littleShifty) && v(i), (Math.abs(o.x) + Math.abs(o.y)) / 4;
73
+ }
74
+ export {
75
+ B as changeScroll,
76
+ y as dosSpeed,
77
+ F as drawScroll,
78
+ T as initScroll
79
+ };
@@ -0,0 +1,107 @@
1
+ import { isGif as d, decodeGif as h } from "../formats/gif.js";
2
+ import { isFli as x, parseFli as y, newFliCanvas as k, applyFliFrame as G } from "../formats/fli.js";
3
+ import { textLines as b, parseBackdrop as p, parseSlideList as T } from "../formats/graphicScripts.js";
4
+ import { matchColor as P, PALETTE_SIZE as F } from "../formats/palette.js";
5
+ import { STOCK_LOOK as u } from "./playerLook.js";
6
+ const S = [63, 10, 10], A = [10, 10, 63], U = [63, 63, 0], D = [50, 10, 50], N = (e, t) => P(e, t[0], t[1], t[2]), w = (e) => (/\.[^.]*$/.exec(e)?.[0] ?? "").toLowerCase();
7
+ async function L(e, t, a) {
8
+ if (await e.need(t), w(t) === ".bkd") {
9
+ const s = e.files.get(t);
10
+ s && await e.need(p(s).gif);
11
+ }
12
+ return e.waiting(() => E(e, t, a));
13
+ }
14
+ async function E(e, t, a) {
15
+ e.audio.stopVoc();
16
+ const s = w(t);
17
+ let i = a.pause ?? -1;
18
+ const o = a.look ?? u, n = a.cols ?? new Uint8Array(F);
19
+ let c;
20
+ if (e.onItem?.(s === ".fli" ? "cartoon" : s === ".txt" ? "text" : s === ".lst" ? "slides" : "picture", t), s === ".gif" || s === ".bkd")
21
+ i === -1 && (i = o.seconds(s === ".gif" ? "timing.showGraphic.gif" : "timing.showGraphic.bkd")), e.screen.setPaletteTo(0, 0, 0), K(e, t, n, s === ".bkd") ? (await e.fadeTo(n, o.num("play.fadeSteps")), c = (await e.pauseTimeKey(i))?.ascii) : e.screen.clear();
22
+ else if (s === ".fli")
23
+ i === -1 && (i = o.seconds("timing.showGraphic.fli")), await C(e, t) && (n.set(e.screen.palette), c = (await e.pauseTimeKey(i))?.ascii);
24
+ else if (s === ".txt") {
25
+ i === -1 && (i = o.seconds("timing.showGraphic.txt"));
26
+ const r = a.cols ?? a.gamePalette;
27
+ return R(e, t, o.color(r, "color.select.textPages"), i, a.gamePalette, e.files.get(t), o);
28
+ } else if (s === ".lst") {
29
+ const r = e.files.get(t);
30
+ if (!r) return !0;
31
+ for (const l of T(r))
32
+ if (!await L(e, l.name, { cols: n, pause: l.pause ?? 65535, gamePalette: a.gamePalette, look: o })) return !1;
33
+ }
34
+ return c !== 27;
35
+ }
36
+ function K(e, t, a, s = !1) {
37
+ let i = 0, o = 0, n = t;
38
+ if (s) {
39
+ const r = e.files.get(t);
40
+ if (!r) return !1;
41
+ const l = p(r);
42
+ i = l.x, o = l.y, n = l.gif;
43
+ }
44
+ const c = e.files.get(n);
45
+ if (!c || !d(c)) return !1;
46
+ try {
47
+ const r = h(c);
48
+ return e.screen.drawImage(r.pixels, r.width, r.height, i, o), a.set(r.palette), !0;
49
+ } catch {
50
+ return !1;
51
+ }
52
+ }
53
+ function B() {
54
+ return new Promise((e) => {
55
+ const t = new MessageChannel();
56
+ t.port1.onmessage = () => e(), t.port2.postMessage(0);
57
+ });
58
+ }
59
+ async function C(e, t) {
60
+ const a = e.files.get(t);
61
+ if (!a || !x(a)) return !1;
62
+ const s = y(a), i = k(s);
63
+ i.palette.set(e.screen.palette), i.pixels.set(e.screen.pixels.subarray(0, Math.min(i.pixels.length, e.screen.pixels.length)));
64
+ let o = e.now();
65
+ for (let n = 0; n < s.frameCount; n++) {
66
+ if (G(s, n, i) && e.screen.setPalette(i.palette), e.screen.drawImage(i.pixels, s.width, s.height), s.speed === 0) {
67
+ await B(), e.checkAbort();
68
+ continue;
69
+ }
70
+ o += s.speed * 1e3 / 70;
71
+ do
72
+ await e.frame();
73
+ while (e.now() < o);
74
+ }
75
+ return !0;
76
+ }
77
+ async function R(e, t, a, s, i, o = e.files.get(t), n = u) {
78
+ const c = e.screen.snapshot(), r = n.color(i, "color.select.textMissing");
79
+ e.flushKeys();
80
+ let l = !1;
81
+ if (!o)
82
+ e.screen.write(40, 80, r, n.text("str.text.missingTitle")), e.screen.write(40, 96, r, n.format("str.text.missingFile", t)), e.screen.write(40, 104, r, n.text("str.text.missingTail"));
83
+ else {
84
+ let f = 5;
85
+ for (const g of b(o)) {
86
+ if (f > 20) {
87
+ if (e.screen.write(224, 168, r, n.text("str.text.more")), (await e.pauseTimeKey(s))?.ascii === 27) {
88
+ l = !0;
89
+ break;
90
+ }
91
+ f = 5, e.screen.restore(c);
92
+ }
93
+ e.screen.write(40, f * 8, a, g), f++;
94
+ }
95
+ }
96
+ return l || await e.pauseTimeKey(s), e.screen.restore(c), !l;
97
+ }
98
+ export {
99
+ A as RGB_BLUE,
100
+ D as RGB_PURPLE,
101
+ S as RGB_RED,
102
+ U as RGB_YELLOW,
103
+ R as displayFile,
104
+ N as match,
105
+ C as playFli,
106
+ L as showGraphic
107
+ };