@moonbase-machines/player 0.12.0 → 0.13.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/README.md CHANGED
@@ -36,7 +36,9 @@ No title is named in it. A title is a folder of its own, kept with the title, wh
36
36
  - its scenes (`<name>.scene`) and `compiled/` (`moonbase-compile`); `remake/README.md` says what a scene is, how it
37
37
  is compiled and run, and the two engines.
38
38
 
39
- Beside it the game's data, `<name>.json` (its disks' files, its kind, and where it saves: `saves`).
39
+ Beside it the game's data, `<name>.json` (its disks' files, its kind, where it saves, `saves`, and its demonstrations,
40
+ `demonstrations`, where its sheet has some: each a name and the steps a person types to see it, which the Original
41
+ types into a Commodore 64 game at a button of that name; `data.js` makes the file and checks every step).
40
42
 
41
43
  ```html
42
44
  <link rel="stylesheet" href="/packages/player/player.css">
package/audio.js CHANGED
@@ -1,17 +1,25 @@
1
1
  // The speaker. The Apple II makes sound by clicking the speaker, a toggle at $C030, and the
2
2
  // machine keeps the cycle of each click. `Speaker` turns a run of cycles into a square wave
3
3
  // at the sound card's rate and plays it through a worklet, which keeps a queue of what it has
4
- // been given and holds the last level when the queue runs dry.
4
+ // been given and holds the last level when the queue runs dry. The queue keeps a quarter of a
5
+ // second at most, the oldest dropped: sound made faster than it plays (a machine catching up a
6
+ // hitch, a pause in a hidden tab) would otherwise put the sound behind the picture for good.
5
7
  const CYCLES_PER_SECOND = 1020484;
6
8
 
7
9
  const WORKLET = `
8
10
  class SpeakerProcessor extends AudioWorkletProcessor {
9
- constructor() { super(); this.queue = []; this.at = 0; this.level = 0; this.port.onmessage = e => this.queue.push(e.data); }
11
+ constructor() {
12
+ super(); this.queue = []; this.at = 0; this.level = 0; this.queued = 0;
13
+ this.port.onmessage = e => {
14
+ this.queue.push(e.data); this.queued += e.data.length;
15
+ while (this.queued > sampleRate / 4 && this.queue.length > 1) { this.queued -= this.queue[0].length - this.at; this.queue.shift(); this.at = 0; }
16
+ };
17
+ }
10
18
  process(inputs, outputs) {
11
19
  const out = outputs[0][0];
12
20
  for (let i = 0; i < out.length; i++) {
13
21
  while (this.queue.length && this.at >= this.queue[0].length) { this.queue.shift(); this.at = 0; }
14
- if (this.queue.length) this.level = this.queue[0][this.at++];
22
+ if (this.queue.length) { this.level = this.queue[0][this.at++]; this.queued--; }
15
23
  out[i] = this.level;
16
24
  }
17
25
  return true;
package/data.js CHANGED
@@ -4,15 +4,21 @@
4
4
  // whole as well, for a machine with Apple's own ROMs, which boots them (`images`, @moonbase-machines/apple2e/disk2.js,
5
5
  // blocks.js), the data naming them.
6
6
  //
7
- // const { data, images } = gameData(slug, { title, kind, disks, system, call, loads, wait, start, saves })
7
+ // const { data, images } = gameData(slug, { title, kind, disks, system, call, loads, wait, start, saves, demonstrations })
8
8
  // kind 'prodos', 'dos33' or 'c64'
9
9
  // disks each disk image's bytes, in order (a 140K .dsk, a .2mg; a C64's .d64)
10
10
  // saves where the game saves, { volume, dos } (@moonbase-machines/apple2e/saves.js), if it does
11
+ // demonstrations
12
+ // what the game's own sheet has a person type to see it work, each a name and its steps, typed into the
13
+ // game by the player's button of that name (play.js): [{ name, steps: [{ key: 'return' }, { key: 'f4' },
14
+ // { type: '1 PISTONS' }, ...] }] (keys.js `typing` says what a step is); a C64 game's, whose engine types
15
+ // them (engines/original.js); refused for another kind
11
16
  // data the game's data, for <slug>.json
12
17
  // images an Apple game's disks, [{ name: <slug>-<n>.dsk or .2mg, bytes }]
13
18
  import { prodos } from '@moonbase-machines/apple2e/prodos-disk.js';
14
19
  import { dos33 } from '@moonbase-machines/apple2e/dos33-disk.js';
15
20
  import { read as d64 } from '@moonbase-machines/c64/d64.js';
21
+ import { typing } from './keys.js';
16
22
 
17
23
  const b64 = bytes => Buffer.from(bytes).toString('base64');
18
24
 
@@ -35,5 +41,14 @@ export function gameData(slug, game) {
35
41
  }
36
42
  }
37
43
  if (game.saves) data.saves = game.saves;
44
+ if (game.demonstrations) {
45
+ if (game.kind !== 'c64') throw new Error(`${slug}: a demonstration is typed into a C64 game only`);
46
+ if (!Array.isArray(game.demonstrations)) throw new Error(`${slug}: demonstrations is a list`);
47
+ data.demonstrations = game.demonstrations.map(d => {
48
+ if (typeof d?.name !== 'string' || !d.name) throw new Error(`${slug}: a demonstration has a name`);
49
+ typing(d.steps, game.kind); // (checked here, once, so that the player never meets a step it cannot type)
50
+ return { name: d.name, steps: d.steps };
51
+ });
52
+ }
38
53
  return { data, images };
39
54
  }