@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.
- package/CHANGELOG.md +42 -0
- package/LICENSE +24 -0
- package/NOTICE.md +58 -0
- package/README.md +149 -2
- package/dist/assets/music.worklet-aD2x7RRM.js +466 -0
- package/dist/audio/cmfLoad.js +10 -0
- package/dist/audio/cmfPlayer.js +201 -0
- package/dist/audio/context.js +75 -0
- package/dist/audio/engine.js +173 -0
- package/dist/audio/mix.js +40 -0
- package/dist/audio/opl.js +245 -0
- package/dist/audio/output.js +40 -0
- package/dist/core/gameFiles.js +89 -0
- package/dist/engine/character.js +187 -0
- package/dist/engine/funcKeys.js +164 -0
- package/dist/engine/game.js +133 -0
- package/dist/engine/keys.js +68 -0
- package/dist/engine/machine.js +192 -0
- package/dist/engine/menus.js +135 -0
- package/dist/engine/monsters.js +259 -0
- package/dist/engine/playGain.js +10 -0
- package/dist/engine/playerLook.js +48 -0
- package/dist/engine/recorder.js +127 -0
- package/dist/engine/render.js +45 -0
- package/dist/engine/scene.js +324 -0
- package/dist/engine/scroll.js +79 -0
- package/dist/engine/showGraphic.js +107 -0
- package/dist/engine/slowPc.js +98 -0
- package/dist/engine/slowPcMusic.js +46 -0
- package/dist/engine/touch.js +61 -0
- package/dist/engine/world.js +205 -0
- package/dist/formats/binary.js +120 -0
- package/dist/formats/blocks.js +103 -0
- package/dist/formats/character.js +83 -0
- package/dist/formats/cmf.js +37 -0
- package/dist/formats/cmfEdit.js +154 -0
- package/dist/formats/cmfPreview.js +89 -0
- package/dist/formats/cmfSong.js +190 -0
- package/dist/formats/fli.js +340 -0
- package/dist/formats/fliFrames.js +34 -0
- package/dist/formats/fliLimits.js +54 -0
- package/dist/formats/game.js +198 -0
- package/dist/formats/gif.js +125 -0
- package/dist/formats/gifProgressive.js +99 -0
- package/dist/formats/graphicScripts.js +44 -0
- package/dist/formats/highscore.js +30 -0
- package/dist/formats/jpeg.js +359 -0
- package/dist/formats/map.js +38 -0
- package/dist/formats/monster.js +69 -0
- package/dist/formats/palette.js +58 -0
- package/dist/formats/recording.js +17 -0
- package/dist/formats/sound.js +44 -0
- package/dist/formats/voc.js +303 -0
- package/dist/gfx/colorVision.js +45 -0
- package/dist/gfx/cp437Glyphs.js +337 -0
- package/dist/gfx/font8x8.js +10 -0
- package/dist/gfx/screen.js +151 -0
- package/dist/index.js +15 -0
- package/dist/input/chords.js +46 -0
- package/dist/input/deskMouse.js +24 -0
- package/dist/input/keyboard.js +82 -0
- package/dist/input/scancodes.js +143 -0
- package/dist/player/fileExtensions.js +118 -0
- package/dist/player/patchRules.js +129 -0
- package/dist/player/patchTable.js +1753 -0
- package/dist/text/cp437.js +44 -0
- package/dist/types/audio/cmfLoad.d.ts +7 -0
- package/dist/types/audio/cmfPlayer.d.ts +69 -0
- package/dist/types/audio/context.d.ts +12 -0
- package/dist/types/audio/engine.d.ts +60 -0
- package/dist/types/audio/mix.d.ts +14 -0
- package/dist/types/audio/music.worklet.d.ts +22 -0
- package/dist/types/audio/opl.d.ts +37 -0
- package/dist/types/audio/output.d.ts +13 -0
- package/dist/types/core/gameFiles.d.ts +49 -0
- package/dist/types/engine/character.d.ts +30 -0
- package/dist/types/engine/funcKeys.d.ts +35 -0
- package/dist/types/engine/game.d.ts +57 -0
- package/dist/types/engine/keys.d.ts +17 -0
- package/dist/types/engine/machine.d.ts +103 -0
- package/dist/types/engine/menus.d.ts +46 -0
- package/dist/types/engine/monsters.d.ts +19 -0
- package/dist/types/engine/playGain.d.ts +11 -0
- package/dist/types/engine/playerLook.d.ts +44 -0
- package/dist/types/engine/recorder.d.ts +67 -0
- package/dist/types/engine/render.d.ts +8 -0
- package/dist/types/engine/scene.d.ts +188 -0
- package/dist/types/engine/scroll.d.ts +24 -0
- package/dist/types/engine/showGraphic.d.ts +39 -0
- package/dist/types/engine/slowPc.d.ts +124 -0
- package/dist/types/engine/slowPcMusic.d.ts +18 -0
- package/dist/types/engine/touch.d.ts +33 -0
- package/dist/types/engine/world.d.ts +237 -0
- package/dist/types/formats/binary.d.ts +44 -0
- package/dist/types/formats/blocks.d.ts +52 -0
- package/dist/types/formats/character.d.ts +65 -0
- package/dist/types/formats/cmf.d.ts +33 -0
- package/dist/types/formats/cmfEdit.d.ts +53 -0
- package/dist/types/formats/cmfPreview.d.ts +19 -0
- package/dist/types/formats/cmfSong.d.ts +74 -0
- package/dist/types/formats/fli.d.ts +56 -0
- package/dist/types/formats/fliFrames.d.ts +18 -0
- package/dist/types/formats/fliLimits.d.ts +13 -0
- package/dist/types/formats/game.d.ts +79 -0
- package/dist/types/formats/gif.d.ts +15 -0
- package/dist/types/formats/gifProgressive.d.ts +46 -0
- package/dist/types/formats/graphicScripts.d.ts +18 -0
- package/dist/types/formats/highscore.d.ts +10 -0
- package/dist/types/formats/jpeg.d.ts +20 -0
- package/dist/types/formats/map.d.ts +24 -0
- package/dist/types/formats/monster.d.ts +48 -0
- package/dist/types/formats/palette.d.ts +15 -0
- package/dist/types/formats/recording.d.ts +7 -0
- package/dist/types/formats/sound.d.ts +13 -0
- package/dist/types/formats/voc.d.ts +13 -0
- package/dist/types/gfx/colorVision.d.ts +26 -0
- package/dist/types/gfx/cp437Glyphs.d.ts +2 -0
- package/dist/types/gfx/font8x8.d.ts +2 -0
- package/dist/types/gfx/screen.d.ts +50 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/input/chords.d.ts +22 -0
- package/dist/types/input/deskMouse.d.ts +14 -0
- package/dist/types/input/keyboard.d.ts +39 -0
- package/dist/types/input/scancodes.d.ts +3 -0
- package/dist/types/player/fileExtensions.d.ts +44 -0
- package/dist/types/player/patchRules.d.ts +24 -0
- package/dist/types/player/patchTable.d.ts +83 -0
- package/dist/types/text/cp437.d.ts +6 -0
- package/package.json +339 -4
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const r = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ", c = /* @__PURE__ */ new Map();
|
|
2
|
+
for (let t = 1; t < 256; t++) (t < 32 || t > 126) && c.set(r[t], t);
|
|
3
|
+
for (const [t, o] of [
|
|
4
|
+
["β", 225],
|
|
5
|
+
// β beta for ß
|
|
6
|
+
["μ", 230],
|
|
7
|
+
// μ mu for µ
|
|
8
|
+
["Ω", 234],
|
|
9
|
+
// Ω ohm for Ω
|
|
10
|
+
["∑", 228],
|
|
11
|
+
// ∑ sum for Σ
|
|
12
|
+
["ϕ", 237],
|
|
13
|
+
// ϕ for φ
|
|
14
|
+
["∈", 238]
|
|
15
|
+
// ∈ for ε
|
|
16
|
+
])
|
|
17
|
+
c.set(t, o);
|
|
18
|
+
const l = { "–": "-", "—": "--", "‘": "'", "’": "'", "“": '"', "”": '"', "…": "...", "×": "x" };
|
|
19
|
+
function C(t) {
|
|
20
|
+
let o = "";
|
|
21
|
+
for (const e of t) {
|
|
22
|
+
const n = c.get(e);
|
|
23
|
+
o += n !== void 0 ? String.fromCharCode(n) : l[e] ?? e;
|
|
24
|
+
}
|
|
25
|
+
return o;
|
|
26
|
+
}
|
|
27
|
+
const f = /* @__PURE__ */ new Map(), i = new TextDecoder("latin1");
|
|
28
|
+
for (let t = 128; t < 160; t++) f.set(i.decode(Uint8Array.of(t)), t);
|
|
29
|
+
function s(t) {
|
|
30
|
+
let o = "";
|
|
31
|
+
for (let e = 0; e < t.length; e++) {
|
|
32
|
+
const n = f.get(t[e]) ?? t.charCodeAt(e);
|
|
33
|
+
o += n < 256 ? r[n] : t[e];
|
|
34
|
+
}
|
|
35
|
+
return o;
|
|
36
|
+
}
|
|
37
|
+
function a(t) {
|
|
38
|
+
return i.decode(t).replace(/[^\x00-\x7f]/g, (o) => s(o));
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
a as cp437Text,
|
|
42
|
+
s as fromCp437,
|
|
43
|
+
C as toCp437
|
|
44
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
interface LoadedSong {
|
|
2
|
+
music: Uint8Array;
|
|
3
|
+
/** The records load_file read; any past the end of the file are zeros here (DOS left whatever was in memory). */
|
|
4
|
+
instruments: Uint8Array[];
|
|
5
|
+
}
|
|
6
|
+
export declare function loadSong(bytes: Uint8Array | undefined): LoadedSong | undefined;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Opl2 } from './opl.js';
|
|
2
|
+
/**
|
|
3
|
+
* Timer ticks per second: 1193180 / (65535 / 8). PLAYGAME.C reprograms PIT channel 0 with
|
|
4
|
+
* divisor 65535/8 (8 times the normal 18.2 Hz), giving about 145.67 ticks per second.
|
|
5
|
+
*/
|
|
6
|
+
export declare const TICK_RATE: number;
|
|
7
|
+
export declare class CmfPlayer {
|
|
8
|
+
private opl;
|
|
9
|
+
private music;
|
|
10
|
+
private instruments;
|
|
11
|
+
private offset;
|
|
12
|
+
private wait;
|
|
13
|
+
private channel;
|
|
14
|
+
private funct;
|
|
15
|
+
private rhythm;
|
|
16
|
+
private rhythmKeys;
|
|
17
|
+
private notes;
|
|
18
|
+
private programs;
|
|
19
|
+
playing: boolean;
|
|
20
|
+
constructor(opl: Opl2);
|
|
21
|
+
/** sbfd_init: enable waveform select, melody mode (0xBD = deep tremolo and vibrato, rhythm off). */
|
|
22
|
+
private init;
|
|
23
|
+
load(music: Uint8Array, instruments: Uint8Array[]): void;
|
|
24
|
+
/** sbfd_music_off + rewind. */
|
|
25
|
+
stop(): void;
|
|
26
|
+
private allNotesOff;
|
|
27
|
+
/**
|
|
28
|
+
* *(APOS) in SBMUSIC.C. PlayIt read sbmusic+offset with no bounds check, so past the end of
|
|
29
|
+
* the farmalloc'd music block it read whatever heap memory followed. Every CMF ends with the
|
|
30
|
+
* FF 2F 00 end marker, which restarts the song before the read gets there; only a truncated
|
|
31
|
+
* file runs off the end, and for that the port reads 0xFF, which takes the same path as the
|
|
32
|
+
* end marker (sbfd_music_off, offset = 0).
|
|
33
|
+
*/
|
|
34
|
+
private byte;
|
|
35
|
+
/**
|
|
36
|
+
* getpaws() in SBMUSIC.C: reads a MIDI variable length number (7 bits per byte, high bit
|
|
37
|
+
* set on every byte but the last), with no limit on the number of bytes:
|
|
38
|
+
* do { offset++; value = (value << 7) | ((c=*(APOS)) & 0x07F); } while (c & 0x80);
|
|
39
|
+
* value is an unsigned long, so bits shifted past 32 are lost (>>> 0). The one difference:
|
|
40
|
+
* the loop stops at the end of the data, where DOS read on into unknown memory.
|
|
41
|
+
*/
|
|
42
|
+
private getPaws;
|
|
43
|
+
/** One timer tick of PlayIt(). */
|
|
44
|
+
tick(): void;
|
|
45
|
+
/** sbfd_setmode: switch melody/rhythm mode and reload the drum channels' instruments. */
|
|
46
|
+
private setMode;
|
|
47
|
+
private programChange;
|
|
48
|
+
private melodyVoices;
|
|
49
|
+
/**
|
|
50
|
+
* Writes one operator from a 16 byte SBI instrument record, whose bytes alternate
|
|
51
|
+
* modulator/carrier: 0/1 AM-VIB-EG-KSR-MULT, 2/3 KSL-TL, 4/5 AR-DR, 6/7 SL-RR, 8/9 waveform.
|
|
52
|
+
*/
|
|
53
|
+
private loadOperator;
|
|
54
|
+
private loadVoice;
|
|
55
|
+
/**
|
|
56
|
+
* MIDI note -> OPL frequency: picks the lowest block (octave) whose F-number fits in 10 bits,
|
|
57
|
+
* which keeps the most pitch resolution (Hz = fnum * 49716 / 2^(20 - block)).
|
|
58
|
+
*/
|
|
59
|
+
private setPitch;
|
|
60
|
+
/**
|
|
61
|
+
* SBFMDRV's loudness by velocity: it scales the instrument's carrier level (TL is an
|
|
62
|
+
* attenuation, 0 loudest .. 63 silent) and keeps the key-scaling bits:
|
|
63
|
+
* TL = 63 - floor((velocity + 128) * (63 - instrumentTL) / 256). So velocity 127 plays
|
|
64
|
+
* the instrument almost as loud as written and velocity 1 about half as loud in TL steps.
|
|
65
|
+
*/
|
|
66
|
+
private applyVelocity;
|
|
67
|
+
private noteOn;
|
|
68
|
+
private noteOff;
|
|
69
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** The page's AudioContext (made on first use; undefined where there is no Web Audio). */
|
|
2
|
+
export declare function audioContext(): AudioContext | undefined;
|
|
3
|
+
/** True once a gesture has let the page's sound start (the context is running, or was). */
|
|
4
|
+
export declare function soundUnlocked(): boolean;
|
|
5
|
+
/** Calls `f` (inside the gesture's handler, so it may create and start nodes) each time sound unlocks. */
|
|
6
|
+
export declare function onSoundUnlocked(f: () => void): () => void;
|
|
7
|
+
/**
|
|
8
|
+
* Resumes the context; must run inside a user gesture's handler the first time (iOS).
|
|
9
|
+
* Called by the page's own gesture listeners; call it too from a handler that also starts
|
|
10
|
+
* a sound, before any await.
|
|
11
|
+
*/
|
|
12
|
+
export declare function unlock(): void;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export declare class AudioEngine {
|
|
2
|
+
private ctx?;
|
|
3
|
+
private master?;
|
|
4
|
+
/** Music and effects each go through their own gain, set by the visitor's sound settings (mix.ts). */
|
|
5
|
+
private musicGain?;
|
|
6
|
+
private sfxGain?;
|
|
7
|
+
/** Music and effects of a game being played also pass the Games setting (setGame). */
|
|
8
|
+
private gameGain?;
|
|
9
|
+
private game;
|
|
10
|
+
private level;
|
|
11
|
+
private unmix?;
|
|
12
|
+
private music?;
|
|
13
|
+
private musicReady?;
|
|
14
|
+
private speaker?;
|
|
15
|
+
private voc?;
|
|
16
|
+
private vocCache;
|
|
17
|
+
musicEnabled: boolean;
|
|
18
|
+
soundEnabled: boolean;
|
|
19
|
+
private cardEnabled;
|
|
20
|
+
private requestedSong?;
|
|
21
|
+
private loadedSong?;
|
|
22
|
+
get soundCardEnabled(): boolean;
|
|
23
|
+
/** Optional live host control: card removal pauses FM and stops digital effects, leaving the PC speaker alone. */
|
|
24
|
+
setSoundCard(enabled: boolean): void;
|
|
25
|
+
/**
|
|
26
|
+
* Starts the sound. The first time, call it from a user gesture's handler (iOS: inside
|
|
27
|
+
* the touchend/click itself, before any await); the page's one AudioContext (context.ts)
|
|
28
|
+
* is resumed there.
|
|
29
|
+
*/
|
|
30
|
+
resume(): Promise<void>;
|
|
31
|
+
/** Marks this engine as a game's: its sound also follows the Games setting (live). */
|
|
32
|
+
setGame(game: boolean): void;
|
|
33
|
+
/** A fixed trim (0 to 1) under the visitor's settings, for sound meant to sit quietly in the background. */
|
|
34
|
+
setLevel(level: number): void;
|
|
35
|
+
private gameLevel;
|
|
36
|
+
/** Where this engine's sound leaves it (for recording just this game's sound). */
|
|
37
|
+
get node(): AudioNode | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Stops everything and lets go of the page's context (it is shared, so it stays open);
|
|
40
|
+
* a later resume() starts afresh.
|
|
41
|
+
*/
|
|
42
|
+
dispose(): void;
|
|
43
|
+
get context(): AudioContext | undefined;
|
|
44
|
+
private post;
|
|
45
|
+
/** PlaySong: returns false (silently, as the original did) for invalid songs. */
|
|
46
|
+
playSong(bytes: Uint8Array | undefined): Promise<boolean>;
|
|
47
|
+
/** Counts songs asked for, so one still waiting for the worklet doesn't start after a newer one (or a stop). */
|
|
48
|
+
private songs;
|
|
49
|
+
stopSong(): void;
|
|
50
|
+
/** The song stands still for `ms` (its notes keep sounding), then goes on from where it was: a slow PC's disk read. */
|
|
51
|
+
holdMusic(ms: number): void;
|
|
52
|
+
pauseMusic(paused: boolean): void;
|
|
53
|
+
/** DoSound's PC speaker path: one frequency per 1/145.6 s tick; 0 = silence. */
|
|
54
|
+
playSpeaker(freqs: ArrayLike<number>): void;
|
|
55
|
+
stopSpeaker(): void;
|
|
56
|
+
/** PlaySbVocFile: a new digital sound cuts off the previous one. */
|
|
57
|
+
playVoc(bytes: Uint8Array | undefined): boolean;
|
|
58
|
+
stopVoc(): void;
|
|
59
|
+
stopAll(): void;
|
|
60
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type Channel = 'music' | 'voice' | 'sfx' | 'games';
|
|
2
|
+
export interface ChannelMix {
|
|
3
|
+
on: boolean;
|
|
4
|
+
/** 0 to 100. */
|
|
5
|
+
volume: number;
|
|
6
|
+
}
|
|
7
|
+
export type Mix = Record<Channel, ChannelMix>;
|
|
8
|
+
export declare const CHANNELS: readonly Channel[];
|
|
9
|
+
export declare const getMix: () => Mix;
|
|
10
|
+
/** The gain (0 to 1) a channel plays at now: 0 when it is off. */
|
|
11
|
+
export declare const channelGain: (c: Channel) => number;
|
|
12
|
+
export declare function setChannel(c: Channel, change: Partial<ChannelMix>): void;
|
|
13
|
+
/** Calls `f` whenever a setting changes; returns a function that stops it. */
|
|
14
|
+
export declare function onMix(f: (m: Mix) => void): () => void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type MusicMessage = {
|
|
2
|
+
type: 'load';
|
|
3
|
+
music: Uint8Array;
|
|
4
|
+
instruments: Uint8Array[];
|
|
5
|
+
} | {
|
|
6
|
+
type: 'stop';
|
|
7
|
+
} | {
|
|
8
|
+
type: 'pause';
|
|
9
|
+
paused: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* An emulated slow PC is reading the disk with the timer held (engine/slowPc.ts readHoldsMusic): PlayIt
|
|
13
|
+
* gets no interrupts for `ms`, so the song stands still while the FM chip keeps sounding its notes.
|
|
14
|
+
*/
|
|
15
|
+
| {
|
|
16
|
+
type: 'hold';
|
|
17
|
+
ms: number;
|
|
18
|
+
}
|
|
19
|
+
/** The engine is done with this node (the page's context lives on): stop processing. */
|
|
20
|
+
| {
|
|
21
|
+
type: 'end';
|
|
22
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export declare class Opl2 {
|
|
2
|
+
readonly sampleRate: number;
|
|
3
|
+
private channels;
|
|
4
|
+
private regs;
|
|
5
|
+
private waveSelect;
|
|
6
|
+
private noteSel;
|
|
7
|
+
private amDepth;
|
|
8
|
+
private vibDepth;
|
|
9
|
+
private rhythm;
|
|
10
|
+
private time;
|
|
11
|
+
private noise;
|
|
12
|
+
constructor(sampleRate: number);
|
|
13
|
+
reset(): void;
|
|
14
|
+
read(reg: number): number;
|
|
15
|
+
write(reg: number, value: number): void;
|
|
16
|
+
private rhythmKeys;
|
|
17
|
+
/**
|
|
18
|
+
* Register 0xBD: bit 7 tremolo depth, bit 6 vibrato depth, bit 5 rhythm mode, bits 0-4 the
|
|
19
|
+
* drum keys. In rhythm mode channels 6-8 become the bass drum (both operators of channel 6),
|
|
20
|
+
* hi-hat and snare (channel 7) and tom-tom and cymbal (channel 8).
|
|
21
|
+
*/
|
|
22
|
+
private writeRhythm;
|
|
23
|
+
/** Renders mono samples into out (added to existing content). */
|
|
24
|
+
render(out: Float32Array, gain?: number): void;
|
|
25
|
+
/** Linear amplitude from the summed attenuation: envelope + TL (0.75 dB steps) + KSL + tremolo. */
|
|
26
|
+
private opLevel;
|
|
27
|
+
private advance;
|
|
28
|
+
private channelSample;
|
|
29
|
+
/**
|
|
30
|
+
* Approximates the five drums. The bass drum is a normal FM channel (at double level); the
|
|
31
|
+
* hi-hat, snare and cymbal mix operator tone with LFSR noise, and the tom-tom is a plain tone.
|
|
32
|
+
* The mixing weights are this port's approximation, not the chip's exact phase logic.
|
|
33
|
+
*/
|
|
34
|
+
private rhythmSample;
|
|
35
|
+
}
|
|
36
|
+
/** Register offsets of the modulator for each FM channel (carrier = +3). */
|
|
37
|
+
export declare const MODULATOR_OFFSET: number[];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const getVolume: () => number;
|
|
2
|
+
/** 0 (silent) to 1 (full). */
|
|
3
|
+
export declare function setVolume(v: number): void;
|
|
4
|
+
/** Where a context's sound should go: its destination, through the volume. */
|
|
5
|
+
export declare function output(ctx: BaseAudioContext): AudioNode;
|
|
6
|
+
type Tap = (ctx: BaseAudioContext, node: AudioNode) => void;
|
|
7
|
+
/**
|
|
8
|
+
* Calls `f` for every context's line out, now and as new ones appear (for recording the
|
|
9
|
+
* sound). Like a capture card on the sound card's line out, a recording has the PC's sound
|
|
10
|
+
* whatever the speakers' volume knob is set to, even turned all the way down.
|
|
11
|
+
*/
|
|
12
|
+
export declare function tapOutputs(f: Tap): () => void;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** Files of a game still on their way from the site (project/streamGame.ts). */
|
|
2
|
+
export interface FileStream {
|
|
3
|
+
/** Resolves once these files are in, or known not to come; undefined when none is still coming. */
|
|
4
|
+
need(names: string[]): Promise<void> | undefined;
|
|
5
|
+
/** Fetches these next, without waiting for them. */
|
|
6
|
+
want(names: string[]): void;
|
|
7
|
+
}
|
|
8
|
+
export declare class GameFiles {
|
|
9
|
+
private files;
|
|
10
|
+
/** Notified after any change. */
|
|
11
|
+
onChange?: (name: string) => void;
|
|
12
|
+
/** Set while files are still arriving: the game waits for one it needs (engine/machine.ts, need). */
|
|
13
|
+
stream?: FileStream;
|
|
14
|
+
/** Asked before set or delete changes a file; throws to refuse (a game opened to look inside, editor/core/readOnly.ts). */
|
|
15
|
+
guard?: (name: string) => void;
|
|
16
|
+
constructor(entries?: Iterable<[string, Uint8Array]>);
|
|
17
|
+
get(name: string | undefined): Uint8Array | undefined;
|
|
18
|
+
has(name: string | undefined): boolean;
|
|
19
|
+
/** The stored name a reference opens (see cdName), or undefined when there is none. */
|
|
20
|
+
resolve(name: string | undefined): string | undefined;
|
|
21
|
+
set(name: string, bytes: Uint8Array): void;
|
|
22
|
+
/**
|
|
23
|
+
* A copy of these files to change freely. While files are still arriving here, the copy
|
|
24
|
+
* gets them too as it needs them (its own changes stay).
|
|
25
|
+
*/
|
|
26
|
+
copy(): GameFiles;
|
|
27
|
+
/** Adds a file that arrived (not one the game wrote): onChange is not told, and a file already here stays. */
|
|
28
|
+
put(name: string, bytes: Uint8Array): void;
|
|
29
|
+
delete(name: string): void;
|
|
30
|
+
names(): string[];
|
|
31
|
+
entries(): [string, Uint8Array][];
|
|
32
|
+
byExtension(ext: string): string[];
|
|
33
|
+
get size(): number;
|
|
34
|
+
/** The .gam file to play: the one named like the folder, else the first. */
|
|
35
|
+
mainGame(preferred?: string): string | undefined;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* File names as DOS saw them: lower case, without folders, and cut to 8.3. DOS dropped the
|
|
39
|
+
* extra letters silently, so games could name "nejillian.gif" and open NEJILLIA.GIF.
|
|
40
|
+
*/
|
|
41
|
+
export declare function normalize(name: string): string;
|
|
42
|
+
/**
|
|
43
|
+
* The name a file got on the Game-Maker CD. Its ISO 9660 copy allowed only A-Z, 0-9 and _,
|
|
44
|
+
* so A-J.BKD, PARSEC-W.GIF and CAN'T.GIF are a_j.bkd, parsec_w.gif and can_t.gif there,
|
|
45
|
+
* while the games still name them the DOS way. A name not found as is is looked up this way.
|
|
46
|
+
*/
|
|
47
|
+
export declare function cdName(name: string): string;
|
|
48
|
+
/** Files only meaningful to DOS. */
|
|
49
|
+
export declare const IGNORED_FILE: RegExp;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Frame } from '../formats/character.js';
|
|
2
|
+
import { type World } from './world.js';
|
|
3
|
+
/** Asks the player which inventory slot to drop; resolves -1 for Esc. */
|
|
4
|
+
type DropPicker = () => Promise<number>;
|
|
5
|
+
/**
|
|
6
|
+
* CHRFRAME with the original's out-of-range behavior: frame -1 read the 17 bytes
|
|
7
|
+
* before the sequence's first frame (the tail of the previous sequence record).
|
|
8
|
+
*/
|
|
9
|
+
export declare function currentFrame(w: World): Frame;
|
|
10
|
+
/**
|
|
11
|
+
* MoveCharGrav: every GRAVSPEED ticks (w.tune), accelerate by one pixel a tick in each
|
|
12
|
+
* direction the block's grav bits name (1 up, 2 right, 4 down, 8 left), capped at
|
|
13
|
+
* MAXGRAV * 4. Returns true while there is any gravity momentum.
|
|
14
|
+
*/
|
|
15
|
+
export declare function moveCharGrav(w: World, reset?: boolean): boolean;
|
|
16
|
+
/** HandleJStick: joystick directions/buttons can trigger sequences too. */
|
|
17
|
+
export declare function handleJoystick(w: World, reset?: boolean): boolean;
|
|
18
|
+
/** movechars: one game tick of character animation and movement. Returns true when dead. */
|
|
19
|
+
export declare function moveChars(w: World, pickDrop: DropPicker): Promise<boolean>;
|
|
20
|
+
/**
|
|
21
|
+
* Screen coordinates of the character's bottom block (nextx/nexty), the tail of
|
|
22
|
+
* movechars (PLAYGAME.C 2593-2601; the func-key return at 1643 is the same with
|
|
23
|
+
* scroll.nx 0). The strict < matches the C: column mx itself counts as MLEN blocks
|
|
24
|
+
* away, so nextx is 2000+ (row my likewise). chkScrnBounds keeps a walk from
|
|
25
|
+
* entering it, but a solid monster's push (C 2508) can put the character there;
|
|
26
|
+
* the C then draws it off screen and ChangeScroll scrolls hard toward it. The port
|
|
27
|
+
* keeps that. test/charScreenColumn.test.ts covers it, across the map wrap too.
|
|
28
|
+
*/
|
|
29
|
+
export declare function updateCharScreenPos(w: World): void;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Machine } from './machine.js';
|
|
2
|
+
import type { Screen } from '../gfx/screen.js';
|
|
3
|
+
import { type PlayerLook } from './playerLook.js';
|
|
4
|
+
import { type World } from './world.js';
|
|
5
|
+
/** What the status and drop screens read of a level: its palette, blocks, inventory and clock. */
|
|
6
|
+
export type InventoryWorld = Pick<World, 'palette' | 'bg' | 'clock'> & {
|
|
7
|
+
ci: Pick<World['ci'], 'inv' | 'score' | 'meter' | 'hitpts' | 'lives'>;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* F1: HelpFiles. XFERPLAY.EXE (PLAYGAME.C built with TRANSFER, the player of every transferred
|
|
11
|
+
* game) shows the game's instructions, or one red line; it never reads GMHELP.TXT. PLAYGAME.EXE,
|
|
12
|
+
* run from Game-Maker, first shows Game-Maker's own GMHELP.TXT (`gmHelp`) in a blue frame.
|
|
13
|
+
*/
|
|
14
|
+
export declare function helpScreen(m: Machine, w: World, instructions: string | undefined, gmHelp?: Uint8Array, look?: PlayerLook): Promise<void>;
|
|
15
|
+
/** Display_Invent's page (F2). */
|
|
16
|
+
export declare function drawStatus(screen: Screen, w: InventoryWorld, look: PlayerLook): void;
|
|
17
|
+
/** F2: Display_Invent */
|
|
18
|
+
export declare function statusScreen(m: Machine, w: World, look?: PlayerLook): Promise<void>;
|
|
19
|
+
/** How many pages GMabout shows (two, as the DOS player does). */
|
|
20
|
+
export declare const aboutPages: (look: PlayerLook) => number;
|
|
21
|
+
/** One page of GMabout (0: the first, as F10 opens it), framed; returns the text color. */
|
|
22
|
+
export declare function drawAbout(screen: Screen, palette: Uint8Array, look: PlayerLook, page?: number): number;
|
|
23
|
+
/** F10: GMabout */
|
|
24
|
+
export declare function aboutScreen(m: Machine, w: World, look?: PlayerLook): Promise<void>;
|
|
25
|
+
/** DropBloc's picker screen, with the selection box on slot (j, k); returns the box's color. */
|
|
26
|
+
export declare function drawDropPicker(screen: Screen, w: InventoryWorld, look: PlayerLook, j?: number, k?: number): number;
|
|
27
|
+
/** DropBloc's picker: arrows choose a slot, Enter drops, Esc cancels (-1). */
|
|
28
|
+
export declare function pickDropSlot(m: Machine, w: World, look?: PlayerLook): Promise<number>;
|
|
29
|
+
/** The load or save heading and slot marks, drawn when the game has no load or save picture. */
|
|
30
|
+
export declare function drawLoadHeading(screen: Screen, look: PlayerLook, cols: Uint8Array): void;
|
|
31
|
+
export declare function drawSaveHeading(screen: Screen, look: PlayerLook, cols: Uint8Array): void;
|
|
32
|
+
/** The ten slot names, in the load or save screen's color. */
|
|
33
|
+
export declare function drawSaveSlots(screen: Screen, look: PlayerLook, pal: Uint8Array, names: string[], saving: boolean): number;
|
|
34
|
+
/** SelectGameToLoad / SelectGameToSave: returns the slot (0..9) or -1. */
|
|
35
|
+
export declare function pickSaveSlot(m: Machine, pal: Uint8Array, saving: boolean, look?: PlayerLook): Promise<number>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Machine } from './machine.js';
|
|
2
|
+
import { type Session, type SpeedSetting } from './scene.js';
|
|
3
|
+
import { type PlayerAbout } from './playerLook.js';
|
|
4
|
+
import type { PlayerPatches } from '../player/patchRules.js';
|
|
5
|
+
import { type Game } from '../formats/game.js';
|
|
6
|
+
export interface RunOptions {
|
|
7
|
+
/** Called when the player picks Quit; return true to show the menu again. */
|
|
8
|
+
onQuit?: () => Promise<boolean> | boolean;
|
|
9
|
+
speakerOnly?: boolean;
|
|
10
|
+
/** No Sound Blaster (PLAYGAME's SoundCard() found none): no songs, every sound on the PC speaker. */
|
|
11
|
+
noSoundCard?: boolean;
|
|
12
|
+
joystick?: Session['joystick'];
|
|
13
|
+
/** Play a .rec demo immediately instead of showing the menu. */
|
|
14
|
+
playback?: Uint8Array;
|
|
15
|
+
/** Start playing at once, recording the keys (for making a demo); the menu is skipped. */
|
|
16
|
+
record?: boolean;
|
|
17
|
+
/** Receives the game session as it starts (e.g. to read the recording so far). */
|
|
18
|
+
onSession?: (s: Session) => void;
|
|
19
|
+
/** Called every frame while a level is being played. */
|
|
20
|
+
onFrame?: Session['onFrame'];
|
|
21
|
+
/** Emulated PC speed (shared object: change slowPc at any time). */
|
|
22
|
+
speed?: SpeedSetting;
|
|
23
|
+
/**
|
|
24
|
+
* Play as PLAYGAME.EXE, Game-Maker's own player: F1 shows this file (GMHELP.TXT from
|
|
25
|
+
* Game-Maker's directory) before the game's instructions. Left out, the game plays as
|
|
26
|
+
* XFERPLAY.EXE, the stand-alone player every transferred game runs on, whose F1 shows only
|
|
27
|
+
* the instructions (PLAYGAME.C HelpFiles: the gmhelp.txt part is #ifndef TRANSFER).
|
|
28
|
+
*/
|
|
29
|
+
gmHelp?: Uint8Array;
|
|
30
|
+
/**
|
|
31
|
+
* The project's DOS player customizations (dosPlayer/): XFERPLAY's words, colors, frames,
|
|
32
|
+
* positions, times and F-keys as its patched .EXE shows them. Left out, the CD's player.
|
|
33
|
+
*/
|
|
34
|
+
player?: PlayerPatches;
|
|
35
|
+
/** An imported game's own player About page and first build (F10 shows them, read-only). */
|
|
36
|
+
playerAbout?: PlayerAbout;
|
|
37
|
+
/** A touch changed a map cell while the player played (never during a demo's playback). */
|
|
38
|
+
onTouched?: Session['onTouched'];
|
|
39
|
+
/** Play ended with this score (never during a demo's playback; see Session.onPlayEnd). */
|
|
40
|
+
onPlayEnd?: Session['onPlayEnd'];
|
|
41
|
+
/** A player lost a life, including game over; never reported during playback. */
|
|
42
|
+
onLifeLost?: Session['onLifeLost'];
|
|
43
|
+
/**
|
|
44
|
+
* The editor's Play Level test only (never a saved, exported or DOS game): skip the title, its
|
|
45
|
+
* song and the menu, and start play at once by scene 0's first link (which the test copy points
|
|
46
|
+
* at the picked level and spot, editor/editors/integrator/startAt.ts) with a new game's
|
|
47
|
+
* character, as the menu's Play would. When that play ends (won, lost or Esc), the usual end
|
|
48
|
+
* follows (the won or dead picture, the high scores) and then the menu, as after any play.
|
|
49
|
+
*/
|
|
50
|
+
skipTitle?: boolean;
|
|
51
|
+
}
|
|
52
|
+
export declare function gameNameOf(gamFile: string): string;
|
|
53
|
+
export declare function loadGameFile(m: Machine, gamFile: string): Game;
|
|
54
|
+
/** Runs a game until the player quits. */
|
|
55
|
+
export declare function runGame(m: Machine, gamFile: string, opts?: RunOptions): Promise<void>;
|
|
56
|
+
/** play(curlink): from scene 0's link to the end. */
|
|
57
|
+
export declare function play(s: Session, startLink: number): Promise<void>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Frame, type Sequence } from '../formats/character.js';
|
|
2
|
+
import { type World } from './world.js';
|
|
3
|
+
export declare function chrSeq(w: World): Sequence;
|
|
4
|
+
/** CHRFRAME. cframe can be -1 between sequences; the original then read stray memory. */
|
|
5
|
+
export declare function chrFrame(w: World): Frame;
|
|
6
|
+
/**
|
|
7
|
+
* SimKeyPress. A press starts the matching sequence only if the character isn't dying,
|
|
8
|
+
* the running sequence can be interrupted (not `ground`), the sequence still has uses
|
|
9
|
+
* (meter > 0) and is turned on (seqon, e.g. its inventory block is carried).
|
|
10
|
+
*/
|
|
11
|
+
export declare function simKeyPress(w: World, key: number): void;
|
|
12
|
+
/** PushKey. The overflow handling is the port's; the C pushed without a bounds check. */
|
|
13
|
+
export declare function pushKey(w: World): void;
|
|
14
|
+
/** PopKey: drop `key` from the stack and resume what is under it, or idle when empty. */
|
|
15
|
+
export declare function popKey(w: World, key: number): void;
|
|
16
|
+
/** The key down and key stack reset at the end of StartSceneInits (also used after F-keys). */
|
|
17
|
+
export declare function resetKeys(w: World): void;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Screen } from '../gfx/screen.js';
|
|
2
|
+
import { Keyboard, type TypedKey } from '../input/keyboard.js';
|
|
3
|
+
import { AudioEngine } from '../audio/engine.js';
|
|
4
|
+
import { GameFiles } from '../core/gameFiles.js';
|
|
5
|
+
/** Thrown to unwind the game when the player is closed. */
|
|
6
|
+
export declare class GameAborted extends Error {
|
|
7
|
+
constructor();
|
|
8
|
+
}
|
|
9
|
+
interface PointerState {
|
|
10
|
+
/** Screen coordinates (0..319, 0..199) of the last pointer position. */
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
clicks: number;
|
|
14
|
+
}
|
|
15
|
+
/** How a Machine is driven (the defaults are a live player's). */
|
|
16
|
+
interface MachineOptions {
|
|
17
|
+
/**
|
|
18
|
+
* 'manual': no animation frame loop; whoever made the Machine calls presentFrame() for
|
|
19
|
+
* each frame, and now() is theirs too (a walkthrough steps the game on a clock of its own).
|
|
20
|
+
*/
|
|
21
|
+
frames?: 'auto' | 'manual';
|
|
22
|
+
/** False: the pointer, the desk mouse and the keyboard never reach the game. */
|
|
23
|
+
input?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare class Machine {
|
|
26
|
+
readonly screen: Screen;
|
|
27
|
+
readonly keyboard: Keyboard;
|
|
28
|
+
readonly audio: AudioEngine;
|
|
29
|
+
files: GameFiles;
|
|
30
|
+
readonly pointer: PointerState;
|
|
31
|
+
aborted: boolean;
|
|
32
|
+
/** Observer only (the walkthrough player's item marks): a picture, cartoon, text page or slide list is about to be shown. Never changes timing. */
|
|
33
|
+
onItem?: (kind: 'picture' | 'cartoon' | 'text' | 'slides', name: string) => void;
|
|
34
|
+
private frameWaiters;
|
|
35
|
+
private raf;
|
|
36
|
+
/** The ball mouse on the desk moves the pointer and clicks too. */
|
|
37
|
+
private offDeskMouse;
|
|
38
|
+
/** The engine was made here (not passed in): it goes with the Machine. */
|
|
39
|
+
private ownsAudio;
|
|
40
|
+
constructor(canvas: HTMLCanvasElement, files: GameFiles, audio?: AudioEngine, opts?: MachineOptions);
|
|
41
|
+
private listen;
|
|
42
|
+
/** The time in ms the game goes by (waits, fades, animations, the game clock). */
|
|
43
|
+
now(): number;
|
|
44
|
+
/** One display frame: the screen is shown (unless `show` is false) and everything waiting for a frame goes on. */
|
|
45
|
+
presentFrame(show?: boolean): void;
|
|
46
|
+
/** How many are waiting for the next frame (a stepped Machine's game is idle when one is). */
|
|
47
|
+
get frameWaiting(): number;
|
|
48
|
+
private toScreen;
|
|
49
|
+
private onPointer;
|
|
50
|
+
private onMove;
|
|
51
|
+
destroy(): void;
|
|
52
|
+
/** Told when the game waits for files still on their way (true) and when they are in. */
|
|
53
|
+
onLoading?: (loading: boolean) => void;
|
|
54
|
+
/**
|
|
55
|
+
* Waits for game files still on their way from the site (a hosted game starts before
|
|
56
|
+
* all its files are in, project/streamGame.ts); a short wait shows no cue. Names the
|
|
57
|
+
* game doesn't have, or that are in already, return at once.
|
|
58
|
+
*/
|
|
59
|
+
need(...names: (string | undefined)[]): Promise<void>;
|
|
60
|
+
/** Fetches these game files next, if they are still on their way, without waiting. */
|
|
61
|
+
want(...names: (string | undefined)[]): void;
|
|
62
|
+
checkAbort(): void;
|
|
63
|
+
/** Waits for the next animation frame (the screen is presented every frame). */
|
|
64
|
+
frame(): Promise<void>;
|
|
65
|
+
sleep(ms: number): Promise<void>;
|
|
66
|
+
takeClick(): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* PauseTimeKey: waits up to `seconds` (forever if omitted) for a key or click.
|
|
69
|
+
* Returns the key, a pseudo key for a click (ascii 1, as the C returned 1 for a mouse
|
|
70
|
+
* button; scan 28 is Enter's), or undefined on time out (the C returned FALSE).
|
|
71
|
+
*/
|
|
72
|
+
pauseTimeKey(seconds?: number): Promise<TypedKey | undefined>;
|
|
73
|
+
private waitDepth;
|
|
74
|
+
private polledAt;
|
|
75
|
+
/**
|
|
76
|
+
* Runs `fn` as PLAYGAME code that read keys through GetKey (key waits, pictures,
|
|
77
|
+
* animations, text pages): while it runs, each frame hands the demo recorder the polls
|
|
78
|
+
* the DOS PC would have made meanwhile (keyPoll). Gameplay itself stole the keyboard
|
|
79
|
+
* interrupt and never called GetKey, so it does not count.
|
|
80
|
+
*/
|
|
81
|
+
waiting<T>(fn: () => Promise<T>): Promise<T>;
|
|
82
|
+
private pollKeys;
|
|
83
|
+
/**
|
|
84
|
+
* Demo playback: called while a screen waits for a key with how many GetKey polls the
|
|
85
|
+
* DOS PC would have made meanwhile; returns recorded keys that become pending.
|
|
86
|
+
*/
|
|
87
|
+
keyPoll?: (polls: number) => number[];
|
|
88
|
+
/** Demo playback: a key-reading screen ended; returns recorded keys it must have taken. */
|
|
89
|
+
keyPollEnd?: () => number[];
|
|
90
|
+
/** Demo playback: one GetKey poll by a screen (tick-counted recordings); returns the recorded keys now due. */
|
|
91
|
+
keyPollOnce?: () => number[];
|
|
92
|
+
/** Clears keyboard input (while (GetKey(1)) GetKey(0)). */
|
|
93
|
+
flushKeys(): void;
|
|
94
|
+
/**
|
|
95
|
+
* FadeTo: 65 retrace-synchronized steps from the current palette to `dest`. The C
|
|
96
|
+
* waited for one VGA vertical retrace (70 Hz in mode 13h) per step, hence steps/70 s;
|
|
97
|
+
* it stepped each channel Bresenham-style, which the truncated d*step/steps matches
|
|
98
|
+
* at every step.
|
|
99
|
+
*/
|
|
100
|
+
fadeTo(dest: ArrayLike<number>, steps?: number): Promise<void>;
|
|
101
|
+
fadeAllTo(r: number, g: number, b: number, steps?: number): Promise<void>;
|
|
102
|
+
}
|
|
103
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Machine } from './machine.js';
|
|
2
|
+
import type { Screen } from '../gfx/screen.js';
|
|
3
|
+
import { type PlayerLook } from './playerLook.js';
|
|
4
|
+
import { type HighScore } from '../formats/highscore.js';
|
|
5
|
+
/**
|
|
6
|
+
* GVertMenu: a marker box left of `count` rows (`dy` pixels apart starting at y).
|
|
7
|
+
* Returns 1..count, 0 for Esc, count+1 when idle for `idleSeconds`. The C timed the
|
|
8
|
+
* idle wait in game ticks (IdleTime*18 of TimerCounter); this uses wall-clock time.
|
|
9
|
+
*
|
|
10
|
+
* The C cleared only the mouse buttons (mouclearbut), not the keyboard: a key typed
|
|
11
|
+
* while the menu picture faded in (after the one ShowGraphic's PauseTimeKey(0) took)
|
|
12
|
+
* was the menu's. `flushKeys` false keeps that; the default clears keys too, for menus
|
|
13
|
+
* opened mid-level, where this port's keyboard also queues the keys gameplay used
|
|
14
|
+
* (PLAYGAME's own keyboard interrupt kept those out of the BIOS buffer).
|
|
15
|
+
*/
|
|
16
|
+
export declare function gVertMenu(m: Machine, x: number, y: number, dy: number, count: number, color: number, idleSeconds?: number, choice?: number, flushKeys?: boolean,
|
|
17
|
+
/** The marker's width minus 1 (the player's border.marker.width patch). */
|
|
18
|
+
markerWidth?: number): Promise<number>;
|
|
19
|
+
/** GGet: line editor with a blinking box cursor. Returns null on Esc. */
|
|
20
|
+
export declare function gGet(m: Machine, x: number, y: number, col: number, bcol: number, initial: string, maxlen: number): Promise<string | null>;
|
|
21
|
+
/** DrawDefaultScrn: concentric colored frames when a game has no menu graphic. */
|
|
22
|
+
export declare function drawDefaultScreen(m: {
|
|
23
|
+
screen: Screen;
|
|
24
|
+
}, colors: Uint8Array, rand?: () => number): void;
|
|
25
|
+
export declare function highScoreFile(gamename: string): string;
|
|
26
|
+
export declare function readHighScores(m: Machine, gamename: string): HighScore[];
|
|
27
|
+
/** The main menu's words over the menu picture: the game's name and the six choices (DoGame). Returns their color. */
|
|
28
|
+
export declare function drawMenu(screen: Screen, look: PlayerLook, colors: Uint8Array, title: string): number;
|
|
29
|
+
/** The menu's GVertMenu call (x, first y, spacing, idle seconds, marker width), as the player's patches set them. */
|
|
30
|
+
export declare function menuMarker(look: PlayerLook): {
|
|
31
|
+
x: number;
|
|
32
|
+
y: number;
|
|
33
|
+
dy: number;
|
|
34
|
+
idle: number;
|
|
35
|
+
width: number;
|
|
36
|
+
};
|
|
37
|
+
/** One of the menu's "No game-specific ..." lines (they share one GWrite: one position, one color). */
|
|
38
|
+
export declare function drawNoFile(screen: Screen, look: PlayerLook, colors: Uint8Array, id: 'noInstructions' | 'noStoryline' | 'noCredits'): void;
|
|
39
|
+
/** The high score table's words and rows; the rows get closer together further down. */
|
|
40
|
+
export declare function drawHighScores(screen: Screen, look: PlayerLook, colors: Uint8Array, top: HighScore[], score: number): void;
|
|
41
|
+
/** ShowHighScores (HISCOREL.C). */
|
|
42
|
+
export declare function showHighScores(m: Machine, gamename: string, colors: Uint8Array, score?: number, look?: PlayerLook): Promise<void>;
|
|
43
|
+
/** CheckHighScores' words for a new high score (place is 1-based); returns the name's color. */
|
|
44
|
+
export declare function drawNewHighScore(screen: Screen, look: PlayerLook, colors: Uint8Array, place: number): number;
|
|
45
|
+
/** CheckHighScores: asks for a name when the score makes the top ten; returns the 1-based place or 0. */
|
|
46
|
+
export declare function checkHighScores(m: Machine, gamename: string, colors: Uint8Array, score: number, look?: PlayerLook): Promise<number>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type MonInfo, type World } from './world.js';
|
|
2
|
+
export declare function resetMonInfo(mi: MonInfo): void;
|
|
3
|
+
export declare function monPicNum(w: World, mm: number): number;
|
|
4
|
+
/** minfo::CalcDraw */
|
|
5
|
+
export declare function calcDraw(w: World, mi: MonInfo): boolean;
|
|
6
|
+
/** BirthMon: puts monster `mon` in slot mm (or the first empty slot when mm >= LASTMM). */
|
|
7
|
+
export declare function birthMon(w: World, mm: number, mon: number, x: number, y: number): number;
|
|
8
|
+
/** BlocBirthMon: blocks that give birth to monsters near the screen. */
|
|
9
|
+
export declare function blockBirthMonsters(w: World): void;
|
|
10
|
+
/** CharBirthMon: a character sequence frame that fires a monster (a shot, a bomb…). */
|
|
11
|
+
export declare function charBirthMon(w: World, x: number, y: number, monNum: number): void;
|
|
12
|
+
/**
|
|
13
|
+
* PicChkTouch: pixel-exact overlap of two 20x20 sprites (255 = transparent).
|
|
14
|
+
* Both positions are shifted so the overlap is measured from the nearer corner;
|
|
15
|
+
* each of the four branches handles one relative placement of sprite 2.
|
|
16
|
+
*/
|
|
17
|
+
export declare function picChkTouch(x1: number, y1: number, pic1: Uint8Array, x2: number, y2: number, pic2: Uint8Array): boolean;
|
|
18
|
+
/** moveallmons: animate and move every live monster one game tick. */
|
|
19
|
+
export declare function moveAllMonsters(w: World): void;
|