@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,79 @@
1
+ export declare const NOSCENE = 65535;
2
+ export declare const STARTTYPE = 1;
3
+ export declare const ENDTYPE = 2;
4
+ export declare const ADVTYPE = 10;
5
+ export declare const SCENEDESCLEN = 20;
6
+ export declare const SCENEFILES = 20;
7
+ export declare const MAXSCENELINKS = 20;
8
+ export declare const GAM_VERSION = 300;
9
+ /** Scene 0 (title/menu) file slots. */
10
+ export declare const START_FILES: readonly ["Title graphic", "Title song", "Menu graphic", "Menu song", "Storyline graphic", "Storyline song", "Game instructions", "Beginning credits", "High score backdrop", "Load game background", "Save game background", "Demo recording"];
11
+ /** Scene 1 (game over) file slots. */
12
+ export declare const END_FILES: readonly ["Game won graphic", "Game won song", "Game lost graphic", "Game lost song"];
13
+ /** Adventure (level) scene file slots. */
14
+ export declare const ADV_FILES: readonly ["Palette", "Map", "Background block set", "Monsters", "Monster block set", "Character", "Character block set", "Sound set", "Sound Blaster music", "Level intro graphic", "Level exit graphic"];
15
+ export declare const ADV_EXTS: readonly ["pal", "map", "bbl", "mon", "mbl", "chr", "cbl", "snd", "cmf", "graphic", "graphic"];
16
+ export declare const GRAPHIC_EXTS: string[];
17
+ export interface Point {
18
+ x: number;
19
+ y: number;
20
+ }
21
+ export interface Link {
22
+ /** Scene to go to, NOSCENE = unused. */
23
+ toScene: number;
24
+ /** Map block that triggers the link. */
25
+ from: Point;
26
+ /** Map block where the character starts in the next scene. */
27
+ to: Point;
28
+ }
29
+ interface ScrollInfo {
30
+ /** 0 = no scrolling, 0xFF = scroll when the character nears the edge. */
31
+ up: number;
32
+ down: number;
33
+ left: number;
34
+ right: number;
35
+ style: number;
36
+ xtra: Uint8Array;
37
+ }
38
+ export interface Scene {
39
+ gametype: number;
40
+ /** Position of the scene box in the integrator's world view. */
41
+ pos: Point;
42
+ scroll: ScrollInfo;
43
+ numLinks: number;
44
+ desc: string;
45
+ descRaw?: Uint8Array;
46
+ /** File names by slot ('' = none). */
47
+ files: string[];
48
+ links: Link[];
49
+ }
50
+ export interface Game {
51
+ version: number;
52
+ /** Raw 256 byte header so unknown bytes survive a round trip. */
53
+ header: Uint8Array;
54
+ filesPerScene: number;
55
+ linksPerScene: number;
56
+ scenes: Scene[];
57
+ /** Original string pool, kept to reproduce the file exactly when nothing changed. */
58
+ pool?: Uint8Array;
59
+ poolOffsets?: number[][];
60
+ /** True when the file was converted from the pre-3.00 layout. */
61
+ converted: boolean;
62
+ }
63
+ export declare function emptyLink(): Link;
64
+ export declare function emptyScene(gametype?: number): Scene;
65
+ export declare function defaultHeader(): Uint8Array;
66
+ export declare function newGame(title?: string): Game;
67
+ export declare function parseGame(bytes: Uint8Array): Game;
68
+ export declare function serializeGame(g: Game): Uint8Array;
69
+ /**
70
+ * The game's name for showing outside DOS: the start scene's description, which holds CP437
71
+ * byte codes (the menu draws them with the PC font), as the Unicode a PC showed, without the
72
+ * spaces and frame characters (box lines, blocks) authors put around it to center or box it.
73
+ * Empty when there is none.
74
+ */
75
+ export declare function gameTitle(game: Game): string;
76
+ export declare function sceneKind(s: Scene): 'start' | 'end' | 'adventure' | 'unused';
77
+ export declare function fileSlotsFor(s: Scene): readonly string[];
78
+ export declare function slotExtensions(s: Scene): readonly string[];
79
+ export {};
@@ -0,0 +1,15 @@
1
+ import { type Palette } from './palette.js';
2
+ export interface IndexedImage {
3
+ width: number;
4
+ height: number;
5
+ pixels: Uint8Array;
6
+ palette: Palette;
7
+ }
8
+ export declare function isGif(bytes: Uint8Array): boolean;
9
+ export declare function decodeGif(bytes: Uint8Array): IndexedImage;
10
+ export declare function lzwDecode(data: Uint8Array, minCodeSize: number, pixelCount: number, done?: {
11
+ count: number;
12
+ }): Uint8Array;
13
+ /** Encodes an 8-bit indexed image as GIF87a with a full 256 color table. */
14
+ export declare function encodeGif(img: IndexedImage): Uint8Array;
15
+ export declare function lzwEncode(pixels: Uint8Array, minCodeSize: number): Uint8Array;
@@ -0,0 +1,46 @@
1
+ import { type IndexedImage } from './gif.js';
2
+ import { type Palette } from './palette.js';
3
+ /** A GIF read from as many of its bytes as there are so far. */
4
+ interface PartialGif {
5
+ width: number;
6
+ height: number;
7
+ /** 6-bit VGA values (the DAC), as decodeGif() gives them. */
8
+ palette: Palette;
9
+ /** How many colors the file's color table has. */
10
+ colors: number;
11
+ interlaced: boolean;
12
+ /** Indexes in file order: row by row as stored (interlaced files store their passes in turn). */
13
+ stored: Uint8Array;
14
+ /** How many pixels of `stored` have arrived. */
15
+ received: number;
16
+ /** All the pixels have arrived. */
17
+ complete: boolean;
18
+ /** Pixel width/height ratio from the GIF89a header (1 when not given). */
19
+ aspect: number;
20
+ }
21
+ /** The picture row each stored row is, and how many rows it covers until finer rows arrive. */
22
+ export declare function storedRows(height: number, interlaced: boolean): {
23
+ y: number;
24
+ span: number;
25
+ }[];
26
+ /**
27
+ * Reads the start of a GIF. Undefined until the header, color table and image descriptor
28
+ * have all arrived (a viewer can't draw anything before that).
29
+ */
30
+ export declare function decodePartialGif(bytes: Uint8Array): PartialGif | undefined;
31
+ /**
32
+ * The picture as far as it has arrived, rows in screen order. Rows not yet received are
33
+ * `blank`, or, in an interlaced file, a copy of the coarser row above them.
34
+ */
35
+ export declare function partialPixels(g: PartialGif, blank?: number): Uint8Array;
36
+ /**
37
+ * Encodes an image as GIF89a: interlaced if asked, with a color table just big enough for
38
+ * `colors` and an optional pixel aspect byte ((n + 15) / 64 = pixel width / height; 38 is
39
+ * the tall pixels of 320x200 and 640x400 on a 4:3 screen).
40
+ */
41
+ export declare function encodeGif89(img: IndexedImage, opts?: {
42
+ interlaced?: boolean;
43
+ colors?: number;
44
+ aspect?: number;
45
+ }): Uint8Array;
46
+ export {};
@@ -0,0 +1,18 @@
1
+ interface Backdrop {
2
+ x: number;
3
+ y: number;
4
+ gif: string;
5
+ }
6
+ export declare function parseBackdrop(bytes: Uint8Array): Backdrop;
7
+ export declare function serializeBackdrop(b: Backdrop): Uint8Array;
8
+ export interface SlideEntry {
9
+ name: string;
10
+ /** Seconds to wait; undefined = the caller's default. */
11
+ pause?: number;
12
+ }
13
+ /** Port of FileEntry/FileListClass: "name [pause]" per line, names up to 15 chars. */
14
+ export declare function parseSlideList(bytes: Uint8Array): SlideEntry[];
15
+ export declare function serializeSlideList(entries: SlideEntry[]): Uint8Array;
16
+ /** Splits a .txt file into the 31 character lines Display_File shows (fgets with a 32 byte buffer). */
17
+ export declare function textLines(bytes: Uint8Array): string[];
18
+ export {};
@@ -0,0 +1,10 @@
1
+ export interface HighScore {
2
+ score: number;
3
+ name: string;
4
+ }
5
+ export declare const HIGH_SCORES = 10;
6
+ export declare function parseHighScores(bytes: Uint8Array): HighScore[];
7
+ export declare function serializeHighScores(list: HighScore[]): Uint8Array;
8
+ /** Port of CheckHighScores' ranking: returns the 0-based place, or -1 if not in the top ten. */
9
+ export declare function placeFor(list: HighScore[], score: number): number;
10
+ export declare function insertHighScore(list: HighScore[], place: number, entry: HighScore): HighScore[];
@@ -0,0 +1,20 @@
1
+ /** A JPEG decoded from as much of it as there is. */
2
+ export interface PartialJpeg {
3
+ width: number;
4
+ height: number;
5
+ /** 1 (grayscale) or 3 (RGB). */
6
+ channels: number;
7
+ /** width * height * channels bytes. */
8
+ pixels: Uint8Array;
9
+ /** Per pixel: 1 once that part of the picture has arrived (a progressive file: all of it after its first scan). */
10
+ shown: Uint8Array;
11
+ progressive: boolean;
12
+ /** Scans that have fully arrived. */
13
+ scans: number;
14
+ complete: boolean;
15
+ /** Pixel width / height from the JFIF header (1 when not given). */
16
+ aspect: number;
17
+ }
18
+ export declare function isJpeg(bytes: Uint8Array): boolean;
19
+ /** Decodes as much of a JPEG as there is; undefined until the frame header has arrived. */
20
+ export declare function decodePartialJpeg(data: Uint8Array): PartialJpeg | undefined;
@@ -0,0 +1,24 @@
1
+ export declare const MLEN = 100;
2
+ export declare const MWID = 100;
3
+ export declare const LASTMM = 200;
4
+ export interface PlacedMonster {
5
+ /** Monster number in the .mon file; LASTMON (64) or more = empty slot. */
6
+ monnum: number;
7
+ status: number;
8
+ xtra: number;
9
+ curx: number;
10
+ cury: number;
11
+ extra: number;
12
+ }
13
+ export interface GameMap {
14
+ /** Background block per cell (index = y * 100 + x). */
15
+ blocks: Uint8Array;
16
+ /** Placed monster index per cell (LASTMM = none). */
17
+ mons: Uint8Array;
18
+ monsters: PlacedMonster[];
19
+ }
20
+ export declare function parseMap(bytes: Uint8Array): GameMap;
21
+ export declare function serializeMap(m: GameMap): Uint8Array;
22
+ export declare function newMap(): GameMap;
23
+ /** Rebuilds the per-cell monster index from the placed monster list (as the map editor does). */
24
+ export declare function reindexMonsters(m: GameMap): void;
@@ -0,0 +1,48 @@
1
+ export declare const LASTMON = 64;
2
+ export declare const LASTSL = 20;
3
+ export declare const MAXMARCH = 10;
4
+ export declare const MONSTER_SIZE = 300;
5
+ export declare const NORMALMOVEMENT = 0;
6
+ export declare const ATTACKMOVEMENT = 1;
7
+ export interface March {
8
+ /** Block offset from the previous corner (first corner: from the start). */
9
+ x: number;
10
+ y: number;
11
+ /** Speed (pixels per tick) to move toward this corner; 0 ends the path. */
12
+ pic: number;
13
+ /** Picture orientation (0-7) while moving to this corner. */
14
+ orient: number;
15
+ }
16
+ export interface Monster {
17
+ used: number;
18
+ /** Non-zero: monster is not affected by gravity (unused by playgame). */
19
+ fly: number;
20
+ jump: number;
21
+ stick: number;
22
+ /** Higher power kills lower power; >= 100 (CHARPOWER) can't be killed by touching the character. */
23
+ power: number;
24
+ /** Non-zero: monster stops at solid blocks. */
25
+ thru: number;
26
+ /** Animation: [block number (>= 100 ends), ticks to show] x 21. */
27
+ pic: [number, number][];
28
+ lasttime: number;
29
+ /** Monster this becomes when it dies (64 = none). */
30
+ newmon: number;
31
+ /** Score bonus when killed by the character's weapons. */
32
+ upscore: number;
33
+ xtra: Uint8Array;
34
+ /** 0 no attack path, 1 attack path is absolute, 2 relative to the character. */
35
+ activate: number;
36
+ /** -2 never dies, -1 dies after path, 0 dies when killed, > 0 lifetime in ticks. */
37
+ end: number;
38
+ /** 0 follow path, 1..63 toward the character at this speed (negative: away), >= 64 random (speed = towards >> 6). */
39
+ towards: number;
40
+ close: [number, number];
41
+ /** [normal path, attack path], 10 corners each. */
42
+ march: [March[], March[]];
43
+ cur: March;
44
+ }
45
+ export declare function parseMonsters(bytes: Uint8Array): Monster[];
46
+ export declare function serializeMonsters(mons: Monster[]): Uint8Array;
47
+ export declare function emptyMonster(): Monster;
48
+ export declare function newMonsterSet(): Monster[];
@@ -0,0 +1,15 @@
1
+ export declare const PALETTE_SIZE: number;
2
+ export type Palette = Uint8Array;
3
+ export declare function parsePalette(bytes: Uint8Array): Palette;
4
+ export declare function serializePalette(pal: Palette): Uint8Array;
5
+ /** Expands 6-bit VGA components to packed 0xAABBGGRR values for ImageData/Uint32Array. */
6
+ export declare function paletteToRGBA(pal: Palette): Uint32Array;
7
+ export declare function vga8(v: number): number;
8
+ export declare function paletteCss(pal: Palette, index: number): string;
9
+ /**
10
+ * Port of RGBdata::Match: the palette index whose color is closest to (r,g,b)
11
+ * (6-bit components), by squared distance; first match wins ties.
12
+ */
13
+ export declare function matchColor(pal: Palette, r: number, g: number, b: number): number;
14
+ /** Default palette GameMaker editors start with: a rainbow ramp plus grays (port of RainbowCols-ish). */
15
+ export declare function defaultPalette(): Palette;
@@ -0,0 +1,7 @@
1
+ export declare const RECLEN = 1000;
2
+ export interface RecordedKey {
3
+ delta: number;
4
+ key: number;
5
+ }
6
+ export declare function parseRecording(bytes: Uint8Array): RecordedKey[];
7
+ export declare function serializeRecording(keys: RecordedKey[]): Uint8Array;
@@ -0,0 +1,13 @@
1
+ export declare const LASTSND = 30;
2
+ export declare const NUMFREQ = 36;
3
+ export declare const SOUND_NAMES: string[];
4
+ export interface SoundSet {
5
+ /** freqs[n] has NUMFREQ frequencies in Hz (0 = silence). */
6
+ freqs: Uint16Array[];
7
+ /** Digital .voc file name (without extension) for each effect, '' = use PC speaker. */
8
+ digital: string[];
9
+ digitalRaw: Uint8Array[];
10
+ }
11
+ export declare function parseSoundSet(bytes: Uint8Array): SoundSet;
12
+ export declare function serializeSoundSet(s: SoundSet): Uint8Array;
13
+ export declare function newSoundSet(): SoundSet;
@@ -0,0 +1,13 @@
1
+ interface DecodedVoc {
2
+ sampleRate: number;
3
+ samples: Float32Array;
4
+ }
5
+ export declare function isVoc(bytes: Uint8Array): boolean;
6
+ export declare function decodeVoc(bytes: Uint8Array): DecodedVoc;
7
+ /**
8
+ * Encodes mono samples (-1..1) as an 8-bit unsigned PCM Creative Voice File, the kind a
9
+ * Sound Blaster plays. The rate is stored as a time constant, so it is rounded the way
10
+ * the card did (11025 Hz is stored as 10,989 Hz: time constant 165, 1,000,000 / 91).
11
+ */
12
+ export declare function encodeVoc(samples: Float32Array, sampleRate?: number): Uint8Array;
13
+ export {};
@@ -0,0 +1,26 @@
1
+ export type Rgb = [number, number, number];
2
+ export type Vision = 'protan' | 'deutan' | 'tritan';
3
+ /** Machado et al. 2009, Table 1, severity 1.0 (rows give linear R, G, B out). */
4
+ export declare const MACHADO: {
5
+ readonly protan: readonly [0.152286, 1.052583, -0.204868, 0.114503, 0.786281, 0.099216, -0.003882, -0.048116, 1.051998];
6
+ readonly deutan: readonly [0.367322, 0.860646, -0.227968, 0.280085, 0.672501, 0.047413, -0.01182, 0.04294, 0.968881];
7
+ readonly tritan: readonly [1.255528, -0.076749, -0.178779, -0.078411, 0.930809, 0.147602, 0.004733, 0.691367, 0.3039];
8
+ };
9
+ /** An sRGB value (0..1) as linear light (0..1). */
10
+ export declare const srgbToLinear: (c: number) => number;
11
+ /** Linear light as an sRGB value (0..1), clamped first. */
12
+ export declare function linearToSrgb(l: number): number;
13
+ /** A linear RGB color as the given kind of color vision sees it, each channel clamped to 0..1. */
14
+ export declare function simulateLinear(rgb: Rgb, matrix: readonly number[]): Rgb;
15
+ /** Linear RGB to CIELAB (D65 white). */
16
+ export declare function lab([r, g, b]: Rgb): Rgb;
17
+ /** CIELAB back to linear RGB (unclamped). */
18
+ export declare function unlab([L, a, b]: Rgb): Rgb;
19
+ /** How far apart two CIELAB colors look (CIE76 delta E: about 2.3 is just noticeable side by side). */
20
+ export declare const deltaELab: (a: Rgb, b: Rgb) => number;
21
+ /** A color (0-255 per channel) as the given kind of color vision sees it. */
22
+ export declare function simulateBytes(c: Rgb, v: Vision): Rgb;
23
+ /** How far apart two colors (0-255 per channel) look: CIE76 delta E; about 2 is just noticeable, over 25 plainly different. */
24
+ export declare const deltaEBytes: (a: Rgb, b: Rgb) => number;
25
+ /** A whole VGA palette (768 bytes of 6-bit values) as the given kind of color vision sees it. */
26
+ export declare function simulatePalette(pal: Uint8Array, v: Vision): Uint8Array;
@@ -0,0 +1,2 @@
1
+ /** The whole CP437 8x8 font: FONT8X8's ASCII plus GLYPHS, with NUL blank (256 x 8 rows, LSB = leftmost pixel). */
2
+ export declare const FONT_CP437: Uint8Array;
@@ -0,0 +1,2 @@
1
+ /** 256 glyphs x 8 rows; characters outside printable ASCII are drawn as a box. */
2
+ export declare const FONT8X8: Uint8Array;
@@ -0,0 +1,50 @@
1
+ export declare const SIZEX = 320;
2
+ export declare const SIZEY = 200;
3
+ export declare class Screen {
4
+ /** Observer metadata only: PLAYGAME's CropScreen is active (no effect on rendering). */
5
+ dosCropped: boolean;
6
+ /** Level number for screen captures; retained during function-key screens. */
7
+ sceneNumber: number;
8
+ readonly pixels: Uint8Array<ArrayBuffer>;
9
+ /** Palette currently shown by the "DAC" (6-bit components). */
10
+ readonly palette: Uint8Array<ArrayBuffer>;
11
+ readonly canvas: HTMLCanvasElement;
12
+ private ctx;
13
+ private image;
14
+ private rgba;
15
+ private lut;
16
+ private dirty;
17
+ constructor(canvas: HTMLCanvasElement);
18
+ setPalette(pal: ArrayLike<number>): void;
19
+ /** SetAllPalTo: every entry the same color. */
20
+ setPaletteTo(r: number, g: number, b: number): void;
21
+ setColor(index: number, r: number, g: number, b: number): void;
22
+ private updateLut;
23
+ markDirty(): void;
24
+ present(): void;
25
+ clear(col?: number): void;
26
+ point(x: number, y: number, col: number): void;
27
+ getCol(x: number, y: number): number;
28
+ /** BoxFill: inclusive corners. */
29
+ boxFill(x: number, y: number, x1: number, y1: number, col: number): void;
30
+ /** Box: rectangle outline. */
31
+ box(x: number, y: number, x1: number, y1: number, col: number): void;
32
+ line(x0: number, y0: number, x1: number, y1: number, col: number): void;
33
+ /**
34
+ * GPutChar: transparent background, 8x8 glyph from the BIOS font (GetROMFont). That ROM font
35
+ * holds only characters 0-127, and GPutChar takes a signed char (code/GM/GRAPHC.C), so 128-255
36
+ * read whatever lies before the font: scribbles on a real VGA card. They draw nothing here.
37
+ * (Text read from a file with TextDecoder('latin1') brings 0x80-0x9F as code points above 255.)
38
+ */
39
+ putChar(x: number, y: number, col: number, code: number): void;
40
+ /** GWrite: '\n' moves to the next line at the starting column. */
41
+ write(x: number, y: number, col: number, text: string): void;
42
+ /** drawblk / BufDrawBlk: opaque 20x20 block, clipped. */
43
+ drawBlock(x: number, y: number, pixels: Uint8Array): void;
44
+ /** BufDrawSpBlk: transparent (255) sprite with one of 8 orientations, clipped. */
45
+ drawSprite(x: number, y: number, orient: number, pixels: Uint8Array): void;
46
+ /** Copies an indexed image (e.g. a GIF) with its top-left at (-sx, -sy). */
47
+ drawImage(pixels: Uint8Array, width: number, height: number, sx?: number, sy?: number): void;
48
+ snapshot(): Uint8Array;
49
+ restore(snap: Uint8Array): void;
50
+ }
@@ -0,0 +1,4 @@
1
+ export { Machine, GameAborted } from './engine/machine.js';
2
+ export { runGame, loadGameFile, gameNameOf, type RunOptions } from './engine/game.js';
3
+ export { GameFiles, normalize, cdName, type FileStream } from './core/gameFiles.js';
4
+ export { AudioEngine } from './audio/engine.js';
@@ -0,0 +1,22 @@
1
+ /** The DOM key codes of the four arrow keys (the keypad's own 8 4 6 2 never chord). */
2
+ export declare const ARROW_CODES: Record<string, number>;
3
+ /**
4
+ * Turns the arrow keys physically held into the keys the game should see held.
5
+ * `bound` says whether the game uses a key; chords whose key it doesn't use stay plain arrows.
6
+ */
7
+ export declare function chordKeys(held: ReadonlySet<number>, bound: (scan: number) => boolean): Set<number>;
8
+ /**
9
+ * Tracks the arrows held and the keys the game was told about, and returns the scan code
10
+ * events (bit 7 set = released) that take the game from what it saw to what it should see.
11
+ * Releases come before presses, so the game never sees a chord and its arrows held at once.
12
+ */
13
+ export declare class ArrowChords {
14
+ bound: (scan: number) => boolean;
15
+ private held;
16
+ private shown;
17
+ constructor(bound?: (scan: number) => boolean);
18
+ /** An arrow key went down or up; returns the events for the game. */
19
+ arrow(scan: number, pressed: boolean): number[];
20
+ /** Forgets everything (focus lost: the keyboard lets go of every key). */
21
+ reset(): void;
22
+ }
@@ -0,0 +1,14 @@
1
+ /** dx, dy in 320x200 screen pixels (fractions allowed); buttons: 1 = left, 2 = right. */
2
+ type DeskMouseListener = (dx: number, dy: number, buttons: number) => void;
3
+ /** Listens to the desk mouse; returns the function that stops listening. */
4
+ export declare function listenDeskMouse(f: DeskMouseListener): () => void;
5
+ /** The desk mouse rolled by (dx, dy) screen pixels with these buttons down. */
6
+ export declare function deskMouse(dx: number, dy: number, buttons: number): void;
7
+ /** Moves a pointer by whole pixels, keeping the fractions for next time. */
8
+ export declare class Mickeys {
9
+ private rx;
10
+ private ry;
11
+ /** Whole pixels to move now for a roll of (dx, dy). */
12
+ take(dx: number, dy: number): [number, number];
13
+ }
14
+ export {};
@@ -0,0 +1,39 @@
1
+ import { ArrowChords } from './chords.js';
2
+ export interface TypedKey {
3
+ scan: number;
4
+ /** ASCII code (0 for extended keys such as arrows). */
5
+ ascii: number;
6
+ /** The DOM key, for text entry. */
7
+ key: string;
8
+ }
9
+ export declare class Keyboard {
10
+ /** Scan code events; bit 7 set = released. */
11
+ readonly events: number[];
12
+ readonly typed: TypedKey[];
13
+ readonly down: Set<number>;
14
+ private target?;
15
+ private waiters;
16
+ /** Two arrows held together stand for the keypad key between them when the game binds it. */
17
+ readonly chords: ArrowChords;
18
+ /** Which keys the game binds, for arrow chords (none: arrows stay arrows). */
19
+ set chordable(bound: ((scan: number) => boolean) | undefined);
20
+ private onDown;
21
+ private onUp;
22
+ private onBlur;
23
+ attach(target?: EventTarget): void;
24
+ detach(): void;
25
+ private handle;
26
+ /** One scan code event for the game (an arrow chord's press or release). */
27
+ private apply;
28
+ /** Simulates a key event (touch controls, gamepad, demo playback). */
29
+ inject(scan: number, pressed: boolean): void;
30
+ /** Queues a recorded scan code as-is (demo playback while a screen waits for a key). */
31
+ feed(scan: number): void;
32
+ releaseAll(): void;
33
+ /** bioskey(1)/bioskey(0): peek or take the next typed key. */
34
+ peekKey(): TypedKey | undefined;
35
+ readKey(): TypedKey | undefined;
36
+ clear(): void;
37
+ /** Resolves on the next key press. */
38
+ nextPress(): Promise<void>;
39
+ }
@@ -0,0 +1,3 @@
1
+ export declare const SCAN: Record<string, number>;
2
+ export declare function scanToAscii(scan: number): number;
3
+ export declare function scanName(scan: number): string;
@@ -0,0 +1,44 @@
1
+ interface ExtKind {
2
+ /** Game-Maker's own extension, lower case, no dot. */
3
+ ext: string;
4
+ label: string;
5
+ note: string;
6
+ /**
7
+ * File offsets of each ".ext" in XFERPLAY 3.00, the one it opens files by first; none for the
8
+ * kinds the .gam names in full.
9
+ */
10
+ offsets: number[];
11
+ }
12
+ export declare const EXT_KINDS: ExtKind[];
13
+ /** The patch id for a kind. */
14
+ export declare const extId: (ext: string) => string;
15
+ /** The kind an id names, if it is one. */
16
+ export declare function extKind(id: string): ExtKind | undefined;
17
+ /** Why `value` can't be kind `ext`'s new extension, or undefined when it can. */
18
+ export declare function extValueProblem(ext: string, value: unknown): string | undefined;
19
+ /** The kinds a set of patches renames: Game-Maker's extension -> the new one (both lower case, no dot). */
20
+ export declare function extensionMap(patches: Record<string, unknown> | undefined): Map<string, string>;
21
+ /** Kinds that share a new extension (each problem names both), for the panel and the export. */
22
+ export declare function extensionClashes(patches: Record<string, unknown> | undefined): Map<string, string>;
23
+ /** The patches without any renamed extensions (what the web player and web-page exports carry). */
24
+ export declare function withoutExtensions<T>(patches: Record<string, T>): Record<string, T>;
25
+ /** Writes each renamed kind's extension into every one of its copies in the player. */
26
+ export declare function writeExtensions(exe: Uint8Array, patches: Record<string, unknown>): void;
27
+ /**
28
+ * A player's renamed extensions as patches, for the kinds whose copies all agree and keep the
29
+ * rules; `read` lists the kinds read (so their bytes are explained).
30
+ */
31
+ export declare function readExtensions(exe: Uint8Array): {
32
+ patches: Record<string, string>;
33
+ read: string[];
34
+ };
35
+ /** Writes Game-Maker's own extension back into every copy of the kinds listed. */
36
+ export declare function writeStockExtensions(exe: Uint8Array, kinds: string[]): void;
37
+ /**
38
+ * The CD's extension -> the one this player opens files by instead ('' when blanked), lower
39
+ * case with the dot, for the player's own kinds that differ. (Virtual Mario blanked .gam.)
40
+ */
41
+ export declare function renamedExtensions(exe: Uint8Array): Record<string, string>;
42
+ /** Acord Games' extensions, as NEVER.EXE and its games' files use them (.lst, .voc and .dat kept). */
43
+ export declare const ACORD_EXTENSIONS: Record<string, string>;
44
+ export {};
@@ -0,0 +1,24 @@
1
+ import { type FramePatch, type PatchEntry } from './patchTable.js';
2
+ export type PatchValue = string | number | number[];
3
+ /** A project's DOS player choices: patch id -> value (patchTable.ts says what each takes). */
4
+ export type PlayerPatches = Record<string, PatchValue>;
5
+ export declare function patchEntry(id: string): PatchEntry | undefined;
6
+ /** A printf format's % codes, in order. */
7
+ export declare function formatCodes(text: string): string[];
8
+ /** Why `value` can't be written for `entry`, or undefined when it can. */
9
+ export declare function patchProblem(entry: PatchEntry, value: unknown): string | undefined;
10
+ /** The largest value a frame's left, top, right or bottom (i: 0-3) takes: a push imm8 is sign-extended, so a 1-byte one stops at 127. */
11
+ export declare function frameLimit(entry: FramePatch, i: number): number;
12
+ /** True when `value` is what the CD's player already has (so no patch is needed). */
13
+ export declare function isStock(entry: PatchEntry, value: PatchValue): boolean;
14
+ /** Writes a value already checked with patchProblem. */
15
+ export declare function writePatch(exe: Uint8Array, entry: PatchEntry, value: PatchValue): void;
16
+ /** The entry's value in `exe` (text up to its first 0, trailing spaces dropped), or undefined when it can't be read as one. */
17
+ export declare function readPatch(exe: Uint8Array, entry: PatchEntry): PatchValue | undefined;
18
+ /** Writes the CD's own value back (for every byte the entry covers, the 0s included). */
19
+ export declare function writeStock(exe: Uint8Array, entry: PatchEntry): void;
20
+ /**
21
+ * Only the patches that are known, valid and not the stock value; the rest are left out. Renamed
22
+ * file extensions (fileExtensions.ts) are kept in lower case.
23
+ */
24
+ export declare function cleanPatches(patches: Record<string, unknown> | undefined): PlayerPatches;
@@ -0,0 +1,83 @@
1
+ /** The editor panel's groups. */
2
+ export type PatchGroup = 'words' | 'colors' | 'frames' | 'positions' | 'times' | 'keys' | 'play';
3
+ /** The screen a patch shows on, which the panel previews while it is edited ('gameplay': every scene, no preview). */
4
+ export type PatchScreen = 'menu' | 'hiscores' | 'newHiscore' | 'status' | 'load' | 'save' | 'drop' | 'help' | 'text' | 'missing' | 'about' | 'play' | 'gameplay' | 'all';
5
+ /**
6
+ * The color targets RGBdata::Match looks for, by name, with the DGROUP offset of each object
7
+ * (what a color selector's push imm16 names).
8
+ */
9
+ export declare const COLOR_TARGETS: {
10
+ readonly yellow: 623;
11
+ readonly red: 626;
12
+ readonly blue: 629;
13
+ readonly purple: 632;
14
+ readonly hsRed: 5626;
15
+ readonly hsBlue: 5629;
16
+ readonly hsGreen: 5632;
17
+ };
18
+ export type ColorName = keyof typeof COLOR_TARGETS;
19
+ /** One immediate in the code: its file offset and size (1: imm8, sign-extended; 2: imm16). */
20
+ export interface ImmField {
21
+ offset: number;
22
+ size: number;
23
+ /** It holds the value's negative (the -MAXGRAV of `if (tx < -MAXGRAV) tx = -MAXGRAV`). */
24
+ negate?: true;
25
+ }
26
+ interface Base {
27
+ id: string;
28
+ group: PatchGroup;
29
+ screen: PatchScreen;
30
+ label: string;
31
+ note?: string;
32
+ /** experimental: changes how every scene plays (the `play` group); test it in DOSBox. */
33
+ safety: 'safe' | 'caution' | 'experimental';
34
+ /** The web player shows it too (false: DOS only). */
35
+ web: boolean;
36
+ }
37
+ /** A NUL-ended string: never longer than `length`, characters 0x20-0x7E; a `format` keeps its % codes. */
38
+ export interface TextPatch extends Base {
39
+ kind: 'text' | 'format';
40
+ offset: number;
41
+ length: number;
42
+ stock: string;
43
+ }
44
+ /** A number in one immediate, or the same number in each of several (`fields`, patched together). */
45
+ export interface NumberPatch extends Base {
46
+ kind: 'number';
47
+ fields: ImmField[];
48
+ /** A 1-byte field is a sign-extended push imm8. */
49
+ signed: boolean;
50
+ min: number;
51
+ max: number;
52
+ stock: number;
53
+ }
54
+ /** A color: red, green and blue (0-63), one byte each. */
55
+ interface RgbPatch extends Base {
56
+ kind: 'rgb';
57
+ offsets: [number, number, number];
58
+ stock: [number, number, number];
59
+ }
60
+ /** Which color target a screen matches (the push imm16 before RGBdata::Match). */
61
+ interface SelectPatch extends Base {
62
+ kind: 'select';
63
+ offset: number;
64
+ stock: ColorName;
65
+ }
66
+ /** A Box(x1, y1, x2, y2) frame. */
67
+ export interface FramePatch extends Base {
68
+ kind: 'frame';
69
+ fields: [ImmField, ImmField, ImmField, ImmField];
70
+ stock: [number, number, number, number];
71
+ }
72
+ /** A function key's entry in DoFunKy's jump table: on (as shipped) or 'off'. */
73
+ interface FkeyPatch extends Base {
74
+ kind: 'fkey';
75
+ key: number;
76
+ offset: number;
77
+ stock: number;
78
+ }
79
+ export type PatchEntry = TextPatch | NumberPatch | RgbPatch | SelectPatch | FramePatch | FkeyPatch;
80
+ /** DoFunKy's "does nothing" target: an F-key whose entry jumps here is off. */
81
+ export declare const FKEY_OFF = 10489;
82
+ export declare const PATCHES: PatchEntry[];
83
+ export {};