@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,237 @@
1
+ import { BACKBL, BLEN, CHARBL, MONBL, type Block } from '../formats/blocks.js';
2
+ import type { Character } from '../formats/character.js';
3
+ import { INF_REPEAT, MAXINV, MAXSEQ } from '../formats/character.js';
4
+ import { LASTMON, type Monster } from '../formats/monster.js';
5
+ import { LASTMM, MLEN, MWID, type GameMap } from '../formats/map.js';
6
+ import { LASTSND } from '../formats/sound.js';
7
+ export { BLEN, BACKBL, MONBL, CHARBL, LASTMM, LASTMON, MLEN, MWID, MAXSEQ, MAXINV, INF_REPEAT, LASTSND };
8
+ export declare const SIZEX = 320;
9
+ export declare const SIZEY = 200;
10
+ export declare const MAXKEYS = 20;
11
+ export declare const MAXGRAV = 11;
12
+ export declare const SCRNBLEN = 16;
13
+ export declare const SCRNBWID = 10;
14
+ export declare const GRAVSPEED = 1;
15
+ export declare const MONMOVESPEED = 1;
16
+ export declare const JSTICKKEY = 1;
17
+ export declare const ATTACKX = 8;
18
+ export declare const ATTACKY = 5;
19
+ export declare const OFFSCRN = -100;
20
+ export declare const SCRSPDX = 40;
21
+ export declare const SCRSPDY = 40;
22
+ export declare const SCROLLPERMOVE = 6;
23
+ export declare const MAXMONSSHOWN = 50;
24
+ export declare const CHARPOWER = 100;
25
+ export declare const NEVER = 4294967295;
26
+ /** The gameplay constants a DOS player patch can change (playerLook.ts playTuning); World.tune. */
27
+ export interface PlayTuning {
28
+ /** MAXGRAV: the character's most pixels a move, either way. */
29
+ maxSpeed: number;
30
+ /** MAXGRAV*4: the most momentum gravity blocks build. */
31
+ gravityCap: number;
32
+ /** GRAVSPEED: ticks between gravity pulls. */
33
+ gravityTicks: number;
34
+ /** ATTACKX, ATTACKY: blocks within which a monster starts its attack path. */
35
+ attackX: number;
36
+ attackY: number;
37
+ /** SCRSPDX, SCRSPDY: the scroll speed at the screen edge. */
38
+ scrollSpeedX: number;
39
+ scrollSpeedY: number;
40
+ /** SCROLLPERMOVE: timer ticks one scroll move is spread over. */
41
+ scrollSteps: number;
42
+ /** FadeTo's and FadeAllTo's step count. */
43
+ fadeSteps: number;
44
+ }
45
+ export declare const STOCK_TUNING: Readonly<PlayTuning>;
46
+ export interface Coord {
47
+ x: number;
48
+ y: number;
49
+ }
50
+ /** cinfo: the player's state that persists across scenes. */
51
+ export interface CharInfo {
52
+ score: number;
53
+ update: boolean;
54
+ topthere: boolean;
55
+ bottomthere: boolean;
56
+ curtop: number;
57
+ curbottom: number;
58
+ /** Where the character will be on screen next; scrx/scry where it is drawn; oldx/oldy where it is erased. */
59
+ nextx: number;
60
+ nexty: number;
61
+ scrx: number;
62
+ scry: number;
63
+ oldx: number;
64
+ oldy: number;
65
+ /** Delta of the character's last 2 moves. */
66
+ netx: number;
67
+ nety: number;
68
+ /** Current velocity due to gravity. */
69
+ gravx: number;
70
+ gravy: number;
71
+ hitpts: number;
72
+ /** Lives left; -1 before the first scene sets it from the character's meter. */
73
+ lives: number;
74
+ /** Game clock tick at which the character next moves. */
75
+ nextAni: number;
76
+ /** Inventory block numbers (BACKBL+1 in inv[0] = not filled in yet). */
77
+ inv: number[];
78
+ /** Repetition counters, MAXSEQ + 10 of them; meter[0] is hit points, meter[1] lives. */
79
+ meter: number[];
80
+ seqon: boolean[];
81
+ }
82
+ /** minfo: one live monster. */
83
+ export interface MonInfo {
84
+ /** Born from the character, so it can't hurt the character. */
85
+ fromchar: number;
86
+ /** Bresenham's algorithm: dx = (curpos - dest). */
87
+ delta: Coord;
88
+ /** [0] map block, [1] pixel position within the block. */
89
+ curx: [number, number];
90
+ cury: [number, number];
91
+ /** Where the monster is going when on a path. */
92
+ target: Coord;
93
+ /** xy ratios in Bresenham's line algorithm. */
94
+ offl: number;
95
+ offs: number;
96
+ /** 0 normal, 1 attack pattern. */
97
+ curMarch: number;
98
+ /** Index into mon[].pic. */
99
+ curPic: number;
100
+ /** How to flip and rotate the picture. */
101
+ orient: number;
102
+ picDrawn: boolean;
103
+ scrPos: Coord;
104
+ oldPos: Coord;
105
+ /** Index of the next position in the monster's path. */
106
+ dest: number;
107
+ /** Game clock ticks of the next animation frame, next move, and when it was born. */
108
+ nextAni: number;
109
+ nextMove: number;
110
+ birthTime: number;
111
+ }
112
+ /** mm[]: monster number per slot (LASTMON = empty). */
113
+ interface MonSlot {
114
+ monnum: number;
115
+ curx: number;
116
+ cury: number;
117
+ }
118
+ interface KeyStackEntry {
119
+ key: number;
120
+ seq: number;
121
+ frame: number;
122
+ }
123
+ export interface BresScroll {
124
+ dscroll: number;
125
+ ctr: number;
126
+ iters: number;
127
+ }
128
+ interface ScrollState {
129
+ /** Pixel offset of the screen edge within the edge block (mx, my). */
130
+ nx: number;
131
+ ny: number;
132
+ /** How far to move the screen this game tick; negative is up or left. */
133
+ totalx: number;
134
+ totaly: number;
135
+ /** Character's offset from the screen center (pixels; the C comment says blocks). */
136
+ distx: number;
137
+ disty: number;
138
+ /** SOLLEF/SOLRIG/SOLTOP/SOLBOT flags of the directions currently scrolling. */
139
+ inMotion: number;
140
+ maxX: number;
141
+ maxY: number;
142
+ minX: number;
143
+ minY: number;
144
+ leftStop: number;
145
+ rightStop: number;
146
+ upStop: number;
147
+ downStop: number;
148
+ /** Pixels waiting to be scrolled; whole 4 pixel steps are taken, 0..3 remain as the pan. */
149
+ movx: number;
150
+ movy: number;
151
+ /** 0..3 pixel hardware pan (an absolute position, not a delta). */
152
+ littleShiftx: number;
153
+ littleShifty: number;
154
+ /** 0xff where the scene allows scrolling that way (mirrored from the .gam file). */
155
+ up: number;
156
+ down: number;
157
+ left: number;
158
+ right: number;
159
+ bx: BresScroll;
160
+ by: BresScroll;
161
+ }
162
+ export interface TouchBlocks {
163
+ blks: [number, number][];
164
+ blknum: number[];
165
+ }
166
+ interface SoundHooks {
167
+ /** DoSound: returns true if a sound was started. */
168
+ play(n: number): boolean;
169
+ }
170
+ export interface World {
171
+ palette: Uint8Array;
172
+ map: Uint8Array;
173
+ mapMon: Uint8Array;
174
+ bg: Block[];
175
+ mblk: Block[];
176
+ cblk: Block[];
177
+ mon: Monster[];
178
+ chr: Character;
179
+ noMons: boolean;
180
+ ci: CharInfo;
181
+ mi: MonInfo[];
182
+ mm: MonSlot[];
183
+ firstEmptyMM: number;
184
+ monsolid: number;
185
+ mmSolid: number;
186
+ blkMon: {
187
+ blnum: number;
188
+ nexttime: number;
189
+ }[];
190
+ /** Per-block "birth this tick" flag (bit 0x4000 of Birthtime in the original). */
191
+ birthFlag: Uint8Array;
192
+ nxtchg: number[];
193
+ blkmap: Uint8Array;
194
+ mx: number;
195
+ my: number;
196
+ scroll: ScrollState;
197
+ clock: number;
198
+ keydn: Uint8Array;
199
+ keystack: KeyStackEntry[];
200
+ keystkptr: number;
201
+ curkey: number;
202
+ gclk: number;
203
+ joyOldTime: number;
204
+ joyOldBut: number;
205
+ sound: SoundHooks;
206
+ rand: () => number;
207
+ /** GetJoyPos: position 0 (center) or 1..8 clockwise from up, buttons bit 0/1. */
208
+ joystick?: () => {
209
+ pos: number;
210
+ buttons: number;
211
+ } | null;
212
+ jstickOn: boolean;
213
+ /**
214
+ * Not PLAYGAME's: told when the character's touch did something to map cell (x, y), shown as
215
+ * block `bnum` (it changed into its touch block, or was picked up). The web's tin heart
216
+ * tracking listens here; nothing in play reads it.
217
+ */
218
+ onTouched?: (x: number, y: number, bnum: number) => void;
219
+ /** The gameplay constants, STOCK_TUNING unless the player's patches change them (playerLook.ts playTuning). */
220
+ tune: PlayTuning;
221
+ }
222
+ export declare function newCharInfo(): CharInfo;
223
+ /** Pads a block list with empty blocks so out-of-range numbers are harmless. */
224
+ export declare function padBlocks(list: Block[] | undefined, count: number): Block[];
225
+ export declare function mapBlock(w: World, x: number, y: number): number;
226
+ export declare function mapMonAt(w: World, x: number, y: number): number;
227
+ export declare function setMapMon(w: World, x: number, y: number, v: number): void;
228
+ /** blks[0][blkmap[n]]: the currently displayed variant of background block n. */
229
+ export declare function shownBlock(w: World, n: number): Block;
230
+ export declare function bgBlock(w: World, n: number): Block;
231
+ export declare function createWorld(map: GameMap, sound: SoundHooks, rand?: () => number): World;
232
+ export declare const random: (w: World, n: number) => number;
233
+ export declare const sign: (v: number) => 0 | 1 | -1;
234
+ /** C int (16-bit) wrap. */
235
+ export declare const i16: (v: number) => number;
236
+ /** C unsigned int (16-bit). */
237
+ export declare const u16: (v: number) => number;
@@ -0,0 +1,44 @@
1
+ export declare class Reader {
2
+ readonly bytes: Uint8Array;
3
+ offset: number;
4
+ constructor(bytes: Uint8Array, offset?: number);
5
+ get length(): number;
6
+ get eof(): boolean;
7
+ skip(n: number): this;
8
+ u8(): number;
9
+ i8(): number;
10
+ u16(): number;
11
+ i16(): number;
12
+ u32(): number;
13
+ i32(): number;
14
+ /** Copies n bytes (zero padded when the source is short). */
15
+ bytesOf(n: number): Uint8Array;
16
+ /** Reads a fixed size, NUL terminated string field. */
17
+ cstr(n: number): string;
18
+ }
19
+ export declare class Writer {
20
+ private buf;
21
+ offset: number;
22
+ constructor(initial?: number);
23
+ private ensure;
24
+ u8(v: number): this;
25
+ i8(v: number): this;
26
+ u16(v: number): this;
27
+ i16(v: number): this;
28
+ u32(v: number): this;
29
+ i32(v: number): this;
30
+ bytes(b: ArrayLike<number>, length?: number): this;
31
+ /** Writes a string into a fixed size NUL padded field (truncated to leave room for the NUL). */
32
+ cstr(s: string, length: number): this;
33
+ /**
34
+ * Writes a fixed size string field. When the text is unchanged the original raw
35
+ * bytes (including any garbage after the NUL) are kept so files round-trip exactly.
36
+ */
37
+ cstrOver(s: string, original: Uint8Array | undefined, length: number): this;
38
+ toBytes(): Uint8Array;
39
+ }
40
+ /** Decodes a NUL terminated string; the whole array when there is no NUL. */
41
+ export declare function cString(bytes: Uint8Array): string;
42
+ export declare function latin1Text(bytes: Uint8Array): string;
43
+ /** One byte per character (low 8 bits of each UTF-16 code unit). */
44
+ export declare function textBytes(text: string): Uint8Array;
@@ -0,0 +1,52 @@
1
+ export declare const BLEN = 20;
2
+ export declare const BLOCK_SIZE = 420;
3
+ export declare const BACKBL = 150;
4
+ export declare const MONBL = 100;
5
+ export declare const CHARBL = 50;
6
+ export declare const TRANSPARENT = 255;
7
+ export declare const SOLTOP = 1;
8
+ export declare const SOLRIG = 2;
9
+ export declare const SOLBOT = 4;
10
+ export declare const SOLLEF = 8;
11
+ export type BlockKind = 'bbl' | 'mbl' | 'cbl';
12
+ export declare const BLOCK_COUNTS: Record<BlockKind, number>;
13
+ export interface Block {
14
+ /** 20x20 palette indices, row major (y * 20 + x). 255 is transparent for sprites. */
15
+ pixels: Uint8Array;
16
+ /** Monster number to give birth to (background blocks). */
17
+ birthMon: number;
18
+ /** Clock ticks between monster births; 0 = never. */
19
+ birthTime: number;
20
+ xtra: Uint8Array;
21
+ /** Solid sides: SOLTOP | SOLRIG | SOLBOT | SOLLEF. */
22
+ solid: number;
23
+ /** Sides that hurt (unused by playgame, kept for fidelity). */
24
+ hitpt: number;
25
+ /** Score points when touched. */
26
+ scorePts: number;
27
+ /** Hit points added (negative hurts) when touched. */
28
+ chHitPt: number;
29
+ /** Block this one animates into after ntime ticks (== self means never). */
30
+ nextBl: number;
31
+ ntime: number;
32
+ /** Block this one becomes when touched (== self means unchanged). */
33
+ touchBl: number;
34
+ /** Gravity direction bits: 1 up, 2 right, 4 down, 8 left. */
35
+ grav: number;
36
+ /** Non-zero if the character can pick this block up. */
37
+ obj: number;
38
+ /** Which counter is affected: 1 lives, 3 money, 5..19 sequence counters, 20..29 extra counters. */
39
+ effect: number;
40
+ /** Amount the effect counter changes. */
41
+ eamt: number;
42
+ }
43
+ export declare function emptyBlock(index: number, transparent?: boolean): Block;
44
+ export declare function parseBlocks(bytes: Uint8Array, count: number): Block[];
45
+ export declare function serializeBlocks(blocks: Block[]): Uint8Array;
46
+ export declare function newBlockSet(kind: BlockKind): Block[];
47
+ /**
48
+ * Pixel lookup for a block drawn with one of the 8 orientations used by playgame
49
+ * (rotations/mirrors; see Sdrawspbloc in PLAYGAME.C). Returns the source index for
50
+ * destination (x, y).
51
+ */
52
+ export declare function orientIndex(orient: number, x: number, y: number): number;
@@ -0,0 +1,65 @@
1
+ export declare const MAXSEQ = 20;
2
+ export declare const MAXFRAME = 10;
3
+ export declare const MAXINV = 10;
4
+ export declare const METERS: number;
5
+ export declare const INF_REPEAT = 32767;
6
+ export declare const CHR_RECORD_SIZE = 3784;
7
+ export declare const IDLESEQ = 0;
8
+ export declare const DIESEQ = 1;
9
+ export declare const HURTSEQ = 2;
10
+ export declare const PICKUPSEQ = 3;
11
+ export declare const DROPSEQ = 4;
12
+ export declare const SEQUENCE_NAMES: string[];
13
+ export interface Frame {
14
+ /** Pixel offset from the previous frame. */
15
+ x: number;
16
+ y: number;
17
+ /** Low nibble: orientation of top block. High nibble: orientation of bottom block. */
18
+ orient: number;
19
+ /** Top block number (CHARBL = none). When pic2 == MONBL, pic1 is the monster to give birth to. */
20
+ pic1: number;
21
+ /** Bottom block number. CHARBL+1 marks the end of the sequence. */
22
+ pic2: number;
23
+ /** Clock ticks (1/18.2 s) to wait before the next frame. */
24
+ pause: number;
25
+ extra: Uint8Array;
26
+ }
27
+ export interface Sequence {
28
+ frames: Frame[];
29
+ /** Activation key: high byte = PC scan code, low byte = ASCII. */
30
+ key: number;
31
+ /** Sound effect number (>= 30 means none). */
32
+ sound: number;
33
+ on: number;
34
+ /** Background block required in inventory to use this sequence (150 = none). */
35
+ bloc: number;
36
+ /** Non-zero: sequence cannot be interrupted. */
37
+ ground: number;
38
+ /** Joystick button (0 any, 1/2 button, 4 none). */
39
+ jstkBut: number;
40
+ /** Joystick direction (0 none, 1-8 directions, 9 any). */
41
+ jstkMov: number;
42
+ /** Non-zero: one run per key press. */
43
+ norepeat: number;
44
+ /** Non-zero: motion adds to momentum instead of moving directly. */
45
+ momentum: number;
46
+ xtra: Uint8Array;
47
+ }
48
+ export interface Character {
49
+ sequences: Sequence[];
50
+ x: number[];
51
+ y: number[];
52
+ cframe: number;
53
+ cseq: number;
54
+ inv: Uint8Array;
55
+ /** Repetition counters: 0 hit points, 1 lives, 3 money, 5..19 sequence counters, 20..29 extra. */
56
+ meter: number[];
57
+ /** Raw bytes of the unused second player record. */
58
+ rest: Uint8Array;
59
+ }
60
+ export declare function parseCharacter(bytes: Uint8Array): Character;
61
+ export declare function serializeCharacter(c: Character): Uint8Array;
62
+ export declare function emptyFrame(end?: boolean): Frame;
63
+ export declare function newCharacter(): Character;
64
+ /** Number of frames before the end marker. */
65
+ export declare function frameCount(s: Sequence): number;
@@ -0,0 +1,33 @@
1
+ export declare const CMF_GAMEMAKER_CLOCK = 146;
2
+ interface CmfFile {
3
+ version: number;
4
+ ticksPerBeat: number;
5
+ /** Ticks per second the song was converted for. */
6
+ clockTicks: number;
7
+ channelUsed: Uint8Array;
8
+ /** 16 byte SBI instrument records. */
9
+ instruments: Uint8Array[];
10
+ basicTempo: number;
11
+ /** The event stream (music block to end of file). */
12
+ music: Uint8Array;
13
+ }
14
+ export declare function isCmf(bytes: Uint8Array): boolean;
15
+ export declare function parseCmf(bytes: Uint8Array): CmfFile;
16
+ /** One event of a song: when (in ticks from the start) and its MIDI bytes. */
17
+ export interface CmfEvent {
18
+ tick: number;
19
+ data: number[];
20
+ }
21
+ interface CmfSong {
22
+ /** 16-byte SBI FM instruments; instrument n starts on MIDI channel n. */
23
+ instruments: Uint8Array[];
24
+ events: CmfEvent[];
25
+ ticksPerBeat?: number;
26
+ basicTempo?: number;
27
+ }
28
+ /**
29
+ * Writes a Creative Music File at Game-Maker's 146 ticks a second (PLAYGAME refuses any
30
+ * other clock). Events are sorted by tick; the song ends with an end-of-track marker.
31
+ */
32
+ export declare function encodeCmf(song: CmfSong): Uint8Array;
33
+ export {};
@@ -0,0 +1,53 @@
1
+ import { type Ev, type Note, type CmfSong } from './cmfSong.js';
2
+ /** Notes on one channel, by start. */
3
+ export declare function channelNotes(song: CmfSong, ch: number): Note[];
4
+ export declare function addNote(song: CmfSong, ch: number, key: number, start: number, len: number, vel?: number): Note;
5
+ export declare const DEFAULT_VELOCITY = 100;
6
+ /** Clamps a velocity to what a note-on can carry (0 would turn the note off). */
7
+ export declare function clampVelocity(v: number): number;
8
+ /** Sets how loud notes play (1..127). Unchanged notes keep their bytes. */
9
+ export declare function setVelocity(notes: Iterable<Note>, v: number): void;
10
+ /** Scales velocities by a factor (and/or adds an offset), clamped to 1..127. */
11
+ export declare function scaleVelocities(notes: Iterable<Note>, factor: number, add?: number): number;
12
+ /**
13
+ * The carrier's total level (TL, 0 loudest .. 63 silent) SBFMDRV plays a note at, for the
14
+ * instrument's own TL: 63 - floor((velocity + 128) * (63 - TL) / 256). Velocity 127 keeps
15
+ * the level nearly as written; velocity 1 is about half as loud in TL steps.
16
+ */
17
+ export declare function velocityLevel(velocity: number, tl: number): number;
18
+ /** Moves and/or resizes a note (start, length in ticks, note number). */
19
+ export declare function setNote(song: CmfSong, n: Note, start: number, len: number, key: number): void;
20
+ export declare function deleteNotes(song: CmfSong, notes: Iterable<Note>): void;
21
+ /** The song end never comes before the last event. */
22
+ export declare function extendEnd(song: CmfSong): void;
23
+ export declare function lastEventTick(song: CmfSong): number;
24
+ /** Moves where the song repeats (never before the last event). */
25
+ export declare function setEnd(song: CmfSong, tick: number): void;
26
+ /** Mode in effect at the start (before any note). */
27
+ export declare function startMode(song: CmfSong): boolean;
28
+ export declare function modeChanges(song: CmfSong): Ev[];
29
+ /** Sets melody (false) or rhythm (true) mode from the start of the song. */
30
+ export declare function setStartMode(song: CmfSong, rhythm: boolean): void;
31
+ /** Instrument changes on a channel, by time. */
32
+ export declare function programChanges(song: CmfSong, ch: number): Ev[];
33
+ /** The instrument a channel starts with (its first note's instrument). */
34
+ export declare function startProgram(song: CmfSong, ch: number): number;
35
+ /** Picks the instrument a channel starts with. */
36
+ export declare function setStartProgram(song: CmfSong, ch: number, program: number): void;
37
+ /** Adds (or changes) an instrument change on a channel at a time. */
38
+ export declare function setProgramAt(song: CmfSong, ch: number, tick: number, program: number): Ev;
39
+ export declare function removeEvent(song: CmfSong, ev: Ev): void;
40
+ /** Channels that have notes or instrument changes. */
41
+ export declare function usedChannels(song: CmfSong): number[];
42
+ /** Removes a channel's notes and events (mode switches stay: they affect the whole song). */
43
+ export declare function removeChannel(song: CmfSong, ch: number): void;
44
+ /** Changes the speed: every time is multiplied by factor (the beat length too). */
45
+ export declare function scaleTime(song: CmfSong, factor: number): void;
46
+ /** Removes events PlayIt ignores (pitch bend, other controllers, stray note-offs...). */
47
+ export declare function stripIgnored(song: CmfSong): number;
48
+ export declare function ignoredCount(song: CmfSong): number;
49
+ /**
50
+ * Which FM voice a channel sounds on, given the mode: melody mode has voices 0..8 on
51
+ * channels 0..8; rhythm mode has 0..5 and drums on 11..15. Other channels are silent.
52
+ */
53
+ export declare function channelSounds(ch: number, rhythm: boolean): boolean;
@@ -0,0 +1,19 @@
1
+ import { type CmfSong } from './cmfSong.js';
2
+ export interface Preview {
3
+ bytes: Uint8Array;
4
+ /** Length of one pass of the preview in ticks. */
5
+ length: number;
6
+ /** Song tick (or -1 in a gap) for a tick since the preview started. */
7
+ songTick: (t: number) => number;
8
+ }
9
+ /**
10
+ * A copy of the song to listen to: some channels muted, starting from a point, or looping a
11
+ * region. Built from the same events, so it plays through the same PlayIt code.
12
+ */
13
+ export declare function buildPreview(song: CmfSong, opts?: {
14
+ muted?: Set<number>;
15
+ from?: number;
16
+ loop?: [number, number];
17
+ }): Preview;
18
+ /** A tiny song that plays one note with an instrument (for "try it"). */
19
+ export declare function auditionSong(song: CmfSong, ch: number, program: number, key: number, ticks?: number, vel?: number): Uint8Array;
@@ -0,0 +1,74 @@
1
+ type EvType = 'on' | 'off' | 'program' | 'mode' | 'raw';
2
+ /** One event of the stream. */
3
+ export interface Ev {
4
+ type: EvType;
5
+ tick: number;
6
+ /** Order among events at the same tick (original stream order; new events go around them). */
7
+ seq: number;
8
+ /** MIDI channel 0..15. */
9
+ ch: number;
10
+ /** on/off: note number; program: instrument number; mode: 0 = melody, otherwise rhythm. */
11
+ a: number;
12
+ /** on: velocity 1..127 (how loud; 0 would be a note off); off: the release byte (kept as read). */
13
+ b: number;
14
+ /** off: written as 0x8n (8) or as 0x9n with velocity 0 (9). */
15
+ fn?: 8 | 9;
16
+ /** notes: whether the original wrote a status byte (undefined for new events). */
17
+ status?: boolean;
18
+ /** A stray 0x8n/0x9n status byte written just before a non-note event. */
19
+ prefix?: number;
20
+ /** raw: the whole event. */
21
+ bytes?: number[];
22
+ /** The original encoding of the delta time before this event. */
23
+ delta?: number[];
24
+ }
25
+ export interface Note {
26
+ on: Ev;
27
+ /** No off event: the note sounds until it is cut or the song repeats. */
28
+ off?: Ev;
29
+ }
30
+ export interface CmfSong {
31
+ /** Everything before the instruments (header, title strings); fields are rewritten on save. */
32
+ header: Uint8Array;
33
+ ticksPerBeat: number;
34
+ clockTicks: number;
35
+ channelUsed: Uint8Array;
36
+ /** Which channels had events when read (to keep channelUsed as it was). */
37
+ hadEvents: boolean[];
38
+ /** 16-byte SBI records; instrument n starts on channel n. */
39
+ instruments: Uint8Array[];
40
+ /** Bytes between the instruments and the music (normally none). */
41
+ gap: Uint8Array;
42
+ /** Silence before the song starts again when it repeats (the first delta). */
43
+ leadIn: number;
44
+ leadInBytes?: number[];
45
+ notes: Note[];
46
+ /** program, mode, raw and stray off events. */
47
+ events: Ev[];
48
+ /** Where the song repeats. */
49
+ end: {
50
+ tick: number;
51
+ delta?: number[];
52
+ bytes: number[];
53
+ };
54
+ /** Counter for ordering new events. */
55
+ counter: number;
56
+ }
57
+ export declare const RHYTHM_CHANNELS: number[];
58
+ export declare const DRUM_NAMES: Record<number, string>;
59
+ export declare function noteEnd(song: CmfSong, n: Note): number;
60
+ /** Reads a CMF the way PlayIt() does. */
61
+ export declare function readSong(bytes: Uint8Array): CmfSong;
62
+ /** All events in stream order. */
63
+ export declare function streamEvents(song: CmfSong): Ev[];
64
+ /** Writes the song back to a CMF file. */
65
+ export declare function writeSong(song: CmfSong): Uint8Array;
66
+ /**
67
+ * The driver calls PlayIt() makes over `ticks` timer ticks, as "tick:call" strings
68
+ * (on/off/program/mode/restart). With `velocity`, note-ons end in "@velocity" (how loud
69
+ * SBFMDRV plays them). Two songs that give the same trace with velocities sound the same.
70
+ */
71
+ export declare function traceMusic(music: Uint8Array, ticks: number, velocity?: boolean): string[];
72
+ /** The music block of a CMF file. */
73
+ export declare function musicOf(bytes: Uint8Array): Uint8Array;
74
+ export {};
@@ -0,0 +1,56 @@
1
+ interface FliAnimation {
2
+ width: number;
3
+ height: number;
4
+ frameCount: number;
5
+ /** Delay per frame in 1/70 s (FLI) — FLC files are converted from milliseconds. */
6
+ speed: number;
7
+ /** Byte offsets of each frame record. */
8
+ frames: number[];
9
+ bytes: Uint8Array;
10
+ }
11
+ interface FliCanvas {
12
+ pixels: Uint8Array;
13
+ /** 6-bit palette, 768 bytes. */
14
+ palette: Uint8Array;
15
+ }
16
+ /** A picture bigger than this (4096 x 4096) is a lie in the header, not an animation: refused before any canvas is made. */
17
+ export declare const FLI_MAX_PIXELS: number;
18
+ export declare function isFli(bytes: Uint8Array): boolean;
19
+ export declare function parseFli(bytes: Uint8Array): FliAnimation;
20
+ export declare function newFliCanvas(anim: FliAnimation): FliCanvas;
21
+ /** Applies frame n to the canvas. Returns true if the palette changed. */
22
+ export declare function applyFliFrame(anim: FliAnimation, n: number, c: FliCanvas): boolean;
23
+ /**
24
+ * The most bytes a chunk (with its 6-byte header) may take. PLAYGAME reads an .FLI through
25
+ * FileRead (code/DRV/FILECLSS.CPP): one buffer of up to 0xFFF0 bytes, 2 bytes smaller each
26
+ * time `new` fails, and FrameHeader::View (code/Image/FLI/FLI.CPP) hands each chunk to its
27
+ * decoder only when the whole chunk fits in that buffer (FileRead::Peek). With a game loaded
28
+ * through XFERPLAY there is less memory, and a 63K chunk drew garbage where a 32.7K one
29
+ * played. 16,000 bytes is under half of that 32.7K, so it fits with a quarter of the 64K
30
+ * buffer PLAYGAME asks for; splitting a full 64,000-pixel frame into bands this size costs a
31
+ * few dozen bytes of headers.
32
+ */
33
+ export declare const FLI_CHUNK_MAX = 16000;
34
+ /**
35
+ * Writes an Autodesk Animator .FLI (Game-Maker shows 320x200): each frame run-length coded
36
+ * or as the lines that changed, the 6-bit palette in the first frame, and a closing "ring"
37
+ * frame that leads back to the start. No chunk is bigger than FLI_CHUNK_MAX: a bigger frame
38
+ * is split into bands of lines. `speed` is the delay after each frame in 1/70 s.
39
+ * `noLoopFrame` leaves the ring frame out: PLAYGAME's FLI::View (code/Image/FLI/FLI.CPP)
40
+ * plays only the header's frame count, so the ring frame is never shown there.
41
+ */
42
+ export declare function encodeFli(frames: Uint8Array[], palette: Uint8Array, opts?: {
43
+ width?: number;
44
+ height?: number;
45
+ speed?: number;
46
+ /** A palette per frame (fades, flashes); changes are stored where they happen. */ palettes?: Uint8Array[];
47
+ /** Code runs of a color inside changed spans as run packets too (smaller deltas for drawn art). */ runs?: boolean;
48
+ /** Leave out the closing ring frame (nothing that plays the file shows it). */ noLoopFrame?: boolean;
49
+ /**
50
+ * After the first frame, send a palette change only for the colors the frame draws (a fade
51
+ * of a picture that uses 90 colors sends 90, not 256); a color the player still holds
52
+ * stale goes out in the first frame that draws it. What shows is the same.
53
+ */
54
+ sparsePalettes?: boolean;
55
+ }): Uint8Array;
56
+ export {};
@@ -0,0 +1,18 @@
1
+ export interface FliFrame {
2
+ pixels: Uint8Array;
3
+ /** 6-bit palette, 768 bytes. */
4
+ palette: Uint8Array;
5
+ }
6
+ export interface FliFrames {
7
+ width: number;
8
+ height: number;
9
+ /** Delay after each frame in 1/70 s. */
10
+ speed: number;
11
+ frames: FliFrame[];
12
+ }
13
+ /** Plays the animation through, keeping a copy of every frame (not the closing ring frame). */
14
+ export declare function decodeFliFrames(bytes: Uint8Array): FliFrames;
15
+ /** Writes the frames as an .FLI; palette changes are stored on the frames where they happen. */
16
+ export declare function encodeFliFrames(a: FliFrames): Uint8Array;
17
+ /** Places a picture on a width x height frame: centered, cropped or padded with color 0. */
18
+ export declare function fitPicture(pixels: Uint8Array, pw: number, ph: number, width: number, height: number): Uint8Array;
@@ -0,0 +1,13 @@
1
+ type FliFaultKind = 'big' | 'packets' | 'black' | 'type';
2
+ interface FliFault {
3
+ kind: FliFaultKind;
4
+ /** The frame it is in (0 the first; the last is the ring frame back to the start). */
5
+ frame: number;
6
+ /** The chunk's size with its header ('big'), the packet count ('packets') or the chunk type ('type'). */
7
+ value: number;
8
+ }
9
+ /** Every fault in an .FLI, the first of each kind per frame. A file that isn't an FLI has none. */
10
+ export declare function fliFaults(bytes: Uint8Array): FliFault[];
11
+ /** A fault in words, for a finding or a health issue. */
12
+ export declare function describeFliFault(f: FliFault): string;
13
+ export {};