sci2-ts 0.0.0-stage → 0.2.1
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 +72 -0
- package/LICENSE +21 -0
- package/README.md +113 -2
- package/apps/viewer/editor.html +43 -0
- package/apps/viewer/explore.html +27 -0
- package/apps/viewer/index.html +26 -0
- package/apps/viewer/package.json +27 -0
- package/apps/viewer/play.html +26 -0
- package/apps/viewer/plugin.d.ts +18 -0
- package/apps/viewer/plugin.js +75 -0
- package/apps/viewer/plugin.ts +84 -0
- package/apps/viewer/src/adlib.d.ts +20 -0
- package/apps/viewer/src/adlib.js +55 -0
- package/apps/viewer/src/adlib.ts +62 -0
- package/apps/viewer/src/app.d.ts +5 -0
- package/apps/viewer/src/app.js +5 -0
- package/apps/viewer/src/app.ts +5 -0
- package/apps/viewer/src/asset-index.d.ts +22 -0
- package/apps/viewer/src/asset-index.js +74 -0
- package/apps/viewer/src/asset-index.ts +90 -0
- package/apps/viewer/src/audio.d.ts +28 -0
- package/apps/viewer/src/audio.js +102 -0
- package/apps/viewer/src/audio.ts +110 -0
- package/apps/viewer/src/editor-handles.d.ts +63 -0
- package/apps/viewer/src/editor-handles.js +332 -0
- package/apps/viewer/src/editor-handles.ts +368 -0
- package/apps/viewer/src/editor-languages.d.ts +23 -0
- package/apps/viewer/src/editor-languages.js +157 -0
- package/apps/viewer/src/editor-languages.ts +135 -0
- package/apps/viewer/src/editor.css +213 -0
- package/apps/viewer/src/editor.d.ts +1 -0
- package/apps/viewer/src/editor.js +393 -0
- package/apps/viewer/src/editor.ts +412 -0
- package/apps/viewer/src/explore/classes.d.ts +7 -0
- package/apps/viewer/src/explore/classes.js +63 -0
- package/apps/viewer/src/explore/classes.ts +61 -0
- package/apps/viewer/src/explore/context.d.ts +33 -0
- package/apps/viewer/src/explore/context.js +96 -0
- package/apps/viewer/src/explore/context.ts +124 -0
- package/apps/viewer/src/explore/explore.css +93 -0
- package/apps/viewer/src/explore/explore.d.ts +1 -0
- package/apps/viewer/src/explore/explore.js +102 -0
- package/apps/viewer/src/explore/explore.ts +104 -0
- package/apps/viewer/src/explore/inspect.d.ts +5 -0
- package/apps/viewer/src/explore/inspect.js +208 -0
- package/apps/viewer/src/explore/inspect.ts +279 -0
- package/apps/viewer/src/explore/live.d.ts +22 -0
- package/apps/viewer/src/explore/live.js +318 -0
- package/apps/viewer/src/explore/live.ts +365 -0
- package/apps/viewer/src/explore/map.d.ts +11 -0
- package/apps/viewer/src/explore/map.js +182 -0
- package/apps/viewer/src/explore/map.ts +193 -0
- package/apps/viewer/src/files.d.ts +21 -0
- package/apps/viewer/src/files.js +69 -0
- package/apps/viewer/src/files.ts +72 -0
- package/apps/viewer/src/game-profile.d.ts +19 -0
- package/apps/viewer/src/game-profile.js +4 -0
- package/apps/viewer/src/game-profile.ts +26 -0
- package/apps/viewer/src/main.d.ts +1 -0
- package/apps/viewer/src/main.js +473 -0
- package/apps/viewer/src/main.ts +527 -0
- package/apps/viewer/src/music.d.ts +14 -0
- package/apps/viewer/src/music.js +32 -0
- package/apps/viewer/src/music.ts +34 -0
- package/apps/viewer/src/opl-worklet.d.ts +1 -0
- package/apps/viewer/src/opl-worklet.js +47 -0
- package/apps/viewer/src/opl-worklet.ts +55 -0
- package/apps/viewer/src/overlay.d.ts +31 -0
- package/apps/viewer/src/overlay.js +103 -0
- package/apps/viewer/src/overlay.ts +123 -0
- package/apps/viewer/src/play.css +14 -0
- package/apps/viewer/src/play.d.ts +1 -0
- package/apps/viewer/src/play.js +179 -0
- package/apps/viewer/src/play.ts +177 -0
- package/apps/viewer/src/saves.d.ts +10 -0
- package/apps/viewer/src/saves.js +50 -0
- package/apps/viewer/src/saves.ts +51 -0
- package/apps/viewer/src/session.d.ts +91 -0
- package/apps/viewer/src/session.js +301 -0
- package/apps/viewer/src/session.ts +321 -0
- package/apps/viewer/src/sound-preview.d.ts +7 -0
- package/apps/viewer/src/sound-preview.js +214 -0
- package/apps/viewer/src/sound-preview.ts +228 -0
- package/apps/viewer/src/style.css +64 -0
- package/apps/viewer/vite.config.ts +25 -0
- package/bin/sci-ts.mjs +9 -0
- package/lib/994.sc +49 -0
- package/lib/995.sc +53 -0
- package/lib/996.sc +299 -0
- package/lib/997.sc +198 -0
- package/lib/998.sc +338 -0
- package/lib/999.sc +189 -0
- package/lib/resources.d.ts +2 -0
- package/lib/resources.js +84 -0
- package/lib/resources.ts +88 -0
- package/lib/system.sh +62 -0
- package/package.json +75 -4
- package/packages/content/room.schema.json +267 -0
- package/packages/content/src/index.d.ts +3 -0
- package/packages/content/src/index.js +3 -0
- package/packages/content/src/index.ts +3 -0
- package/packages/content/src/room.d.ts +111 -0
- package/packages/content/src/room.js +886 -0
- package/packages/content/src/room.ts +1011 -0
- package/packages/content/src/target.d.ts +80 -0
- package/packages/content/src/target.js +1 -0
- package/packages/content/src/target.ts +60 -0
- package/packages/content/src/yarn.d.ts +90 -0
- package/packages/content/src/yarn.js +214 -0
- package/packages/content/src/yarn.ts +261 -0
- package/packages/sci/src/analysis/game.d.ts +90 -0
- package/packages/sci/src/analysis/game.js +221 -0
- package/packages/sci/src/analysis/game.ts +305 -0
- package/packages/sci/src/analysis/runtime.d.ts +58 -0
- package/packages/sci/src/analysis/runtime.js +133 -0
- package/packages/sci/src/analysis/runtime.ts +163 -0
- package/packages/sci/src/audio/adlib.d.ts +73 -0
- package/packages/sci/src/audio/adlib.js +280 -0
- package/packages/sci/src/audio/adlib.ts +329 -0
- package/packages/sci/src/audio/index.d.ts +43 -0
- package/packages/sci/src/audio/index.js +99 -0
- package/packages/sci/src/audio/index.ts +122 -0
- package/packages/sci/src/audio/midi.d.ts +92 -0
- package/packages/sci/src/audio/midi.js +242 -0
- package/packages/sci/src/audio/midi.ts +262 -0
- package/packages/sci/src/audio/opl2.d.ts +74 -0
- package/packages/sci/src/audio/opl2.js +283 -0
- package/packages/sci/src/audio/opl2.ts +283 -0
- package/packages/sci/src/audio/sol.d.ts +32 -0
- package/packages/sci/src/audio/sol.js +81 -0
- package/packages/sci/src/audio/sol.ts +100 -0
- package/packages/sci/src/audio/write.d.ts +35 -0
- package/packages/sci/src/audio/write.js +91 -0
- package/packages/sci/src/audio/write.ts +108 -0
- package/packages/sci/src/gfx/cel.d.ts +36 -0
- package/packages/sci/src/gfx/cel.js +82 -0
- package/packages/sci/src/gfx/cel.ts +110 -0
- package/packages/sci/src/gfx/palette.d.ts +24 -0
- package/packages/sci/src/gfx/palette.js +49 -0
- package/packages/sci/src/gfx/palette.ts +56 -0
- package/packages/sci/src/gfx/pic-file.d.ts +46 -0
- package/packages/sci/src/gfx/pic-file.js +114 -0
- package/packages/sci/src/gfx/pic-file.ts +155 -0
- package/packages/sci/src/gfx/pic.d.ts +27 -0
- package/packages/sci/src/gfx/pic.js +34 -0
- package/packages/sci/src/gfx/pic.ts +53 -0
- package/packages/sci/src/gfx/quantize.d.ts +42 -0
- package/packages/sci/src/gfx/quantize.js +199 -0
- package/packages/sci/src/gfx/quantize.ts +218 -0
- package/packages/sci/src/gfx/view-file.d.ts +62 -0
- package/packages/sci/src/gfx/view-file.js +182 -0
- package/packages/sci/src/gfx/view-file.ts +233 -0
- package/packages/sci/src/gfx/view.d.ts +28 -0
- package/packages/sci/src/gfx/view.js +45 -0
- package/packages/sci/src/gfx/view.ts +62 -0
- package/packages/sci/src/index.d.ts +38 -0
- package/packages/sci/src/index.js +38 -0
- package/packages/sci/src/index.ts +38 -0
- package/packages/sci/src/motion/pathfinding.d.ts +40 -0
- package/packages/sci/src/motion/pathfinding.js +140 -0
- package/packages/sci/src/motion/pathfinding.ts +147 -0
- package/packages/sci/src/resource/archive.d.ts +16 -0
- package/packages/sci/src/resource/archive.js +51 -0
- package/packages/sci/src/resource/archive.ts +56 -0
- package/packages/sci/src/resource/lzs.d.ts +12 -0
- package/packages/sci/src/resource/lzs.js +64 -0
- package/packages/sci/src/resource/lzs.ts +66 -0
- package/packages/sci/src/resource/manager.d.ts +45 -0
- package/packages/sci/src/resource/manager.js +158 -0
- package/packages/sci/src/resource/manager.ts +184 -0
- package/packages/sci/src/resource/map.d.ts +18 -0
- package/packages/sci/src/resource/map.js +34 -0
- package/packages/sci/src/resource/map.ts +44 -0
- package/packages/sci/src/resource/types.d.ts +37 -0
- package/packages/sci/src/resource/types.js +45 -0
- package/packages/sci/src/resource/types.ts +57 -0
- package/packages/sci/src/script/assembly.d.ts +67 -0
- package/packages/sci/src/script/assembly.js +748 -0
- package/packages/sci/src/script/assembly.ts +714 -0
- package/packages/sci/src/script/compiler.d.ts +75 -0
- package/packages/sci/src/script/compiler.js +993 -0
- package/packages/sci/src/script/compiler.ts +1040 -0
- package/packages/sci/src/script/disasm.d.ts +81 -0
- package/packages/sci/src/script/disasm.js +318 -0
- package/packages/sci/src/script/disasm.ts +323 -0
- package/packages/sci/src/script/kernel-names.d.ts +6 -0
- package/packages/sci/src/script/kernel-names.js +165 -0
- package/packages/sci/src/script/kernel-names.ts +165 -0
- package/packages/sci/src/script/opcodes.d.ts +22 -0
- package/packages/sci/src/script/opcodes.js +45 -0
- package/packages/sci/src/script/opcodes.ts +72 -0
- package/packages/sci/src/script/script.d.ts +56 -0
- package/packages/sci/src/script/script.js +63 -0
- package/packages/sci/src/script/script.ts +111 -0
- package/packages/sci/src/script/sexpr.d.ts +45 -0
- package/packages/sci/src/script/sexpr.js +151 -0
- package/packages/sci/src/script/sexpr.ts +139 -0
- package/packages/sci/src/script/vocab.d.ts +15 -0
- package/packages/sci/src/script/vocab.js +44 -0
- package/packages/sci/src/script/vocab.ts +48 -0
- package/packages/sci/src/script/world.d.ts +25 -0
- package/packages/sci/src/script/world.js +65 -0
- package/packages/sci/src/script/world.ts +70 -0
- package/packages/sci/src/text/font.d.ts +37 -0
- package/packages/sci/src/text/font.js +103 -0
- package/packages/sci/src/text/font.ts +125 -0
- package/packages/sci/src/text/message.d.ts +69 -0
- package/packages/sci/src/text/message.js +171 -0
- package/packages/sci/src/text/message.ts +205 -0
- package/packages/sci/src/vm/kernels/arrays.d.ts +19 -0
- package/packages/sci/src/vm/kernels/arrays.js +182 -0
- package/packages/sci/src/vm/kernels/arrays.ts +164 -0
- package/packages/sci/src/vm/kernels/audio.d.ts +70 -0
- package/packages/sci/src/vm/kernels/audio.js +347 -0
- package/packages/sci/src/vm/kernels/audio.ts +349 -0
- package/packages/sci/src/vm/kernels/core.d.ts +5 -0
- package/packages/sci/src/vm/kernels/core.js +87 -0
- package/packages/sci/src/vm/kernels/core.ts +91 -0
- package/packages/sci/src/vm/kernels/graphics.d.ts +141 -0
- package/packages/sci/src/vm/kernels/graphics.js +467 -0
- package/packages/sci/src/vm/kernels/graphics.ts +502 -0
- package/packages/sci/src/vm/kernels/index.d.ts +8 -0
- package/packages/sci/src/vm/kernels/index.js +29 -0
- package/packages/sci/src/vm/kernels/index.ts +32 -0
- package/packages/sci/src/vm/kernels/lists.d.ts +6 -0
- package/packages/sci/src/vm/kernels/lists.js +127 -0
- package/packages/sci/src/vm/kernels/lists.ts +111 -0
- package/packages/sci/src/vm/kernels/motion.d.ts +7 -0
- package/packages/sci/src/vm/kernels/motion.js +204 -0
- package/packages/sci/src/vm/kernels/motion.ts +194 -0
- package/packages/sci/src/vm/kernels/palette.d.ts +82 -0
- package/packages/sci/src/vm/kernels/palette.js +292 -0
- package/packages/sci/src/vm/kernels/palette.ts +303 -0
- package/packages/sci/src/vm/kernels/saves.d.ts +45 -0
- package/packages/sci/src/vm/kernels/saves.js +123 -0
- package/packages/sci/src/vm/kernels/saves.ts +149 -0
- package/packages/sci/src/vm/kernels/system.d.ts +62 -0
- package/packages/sci/src/vm/kernels/system.js +110 -0
- package/packages/sci/src/vm/kernels/system.ts +128 -0
- package/packages/sci/src/vm/kernels/text.d.ts +13 -0
- package/packages/sci/src/vm/kernels/text.js +338 -0
- package/packages/sci/src/vm/kernels/text.ts +328 -0
- package/packages/sci/src/vm/memory.d.ts +138 -0
- package/packages/sci/src/vm/memory.js +168 -0
- package/packages/sci/src/vm/memory.ts +266 -0
- package/packages/sci/src/vm/replace.d.ts +11 -0
- package/packages/sci/src/vm/replace.js +14 -0
- package/packages/sci/src/vm/replace.ts +16 -0
- package/packages/sci/src/vm/savegame.d.ts +89 -0
- package/packages/sci/src/vm/savegame.js +161 -0
- package/packages/sci/src/vm/savegame.ts +188 -0
- package/packages/sci/src/vm/value.d.ts +17 -0
- package/packages/sci/src/vm/value.js +12 -0
- package/packages/sci/src/vm/value.ts +25 -0
- package/packages/sci/src/vm/vm.d.ts +155 -0
- package/packages/sci/src/vm/vm.js +1053 -0
- package/packages/sci/src/vm/vm.ts +914 -0
- package/tools/adlib-render.d.ts +1 -0
- package/tools/adlib-render.js +49 -0
- package/tools/adlib-render.ts +42 -0
- package/tools/analyze.d.ts +1 -0
- package/tools/analyze.js +25 -0
- package/tools/analyze.ts +25 -0
- package/tools/art/build.d.ts +34 -0
- package/tools/art/build.js +175 -0
- package/tools/art/build.ts +153 -0
- package/tools/art.d.ts +1 -0
- package/tools/art.js +31 -0
- package/tools/art.ts +29 -0
- package/tools/asm.d.ts +1 -0
- package/tools/asm.js +61 -0
- package/tools/asm.ts +55 -0
- package/tools/cli.d.ts +1 -0
- package/tools/cli.js +99 -0
- package/tools/cli.ts +100 -0
- package/tools/editor-server.d.ts +29 -0
- package/tools/editor-server.js +162 -0
- package/tools/editor-server.ts +176 -0
- package/tools/explore.d.ts +1 -0
- package/tools/explore.js +305 -0
- package/tools/explore.ts +250 -0
- package/tools/game/audio.d.ts +19 -0
- package/tools/game/audio.js +143 -0
- package/tools/game/audio.ts +130 -0
- package/tools/game/build.d.ts +46 -0
- package/tools/game/build.js +259 -0
- package/tools/game/build.ts +283 -0
- package/tools/game/defaults.d.ts +26 -0
- package/tools/game/defaults.js +82 -0
- package/tools/game/defaults.ts +83 -0
- package/tools/game/font.d.ts +3 -0
- package/tools/game/font.js +124 -0
- package/tools/game/font.ts +126 -0
- package/tools/game/kit.d.ts +7 -0
- package/tools/game/kit.js +7 -0
- package/tools/game/kit.ts +10 -0
- package/tools/game/new.d.ts +8 -0
- package/tools/game/new.js +39 -0
- package/tools/game/new.ts +38 -0
- package/tools/game/target.d.ts +7 -0
- package/tools/game/target.js +41 -0
- package/tools/game/target.ts +42 -0
- package/tools/game/template/resources.ts.tmpl +43 -0
- package/tools/game/template/rooms/1.room.yaml +9 -0
- package/tools/game/template/rooms/1.yarn +17 -0
- package/tools/game/template/scripts/0.sc +24 -0
- package/tools/game.d.ts +1 -0
- package/tools/game.js +77 -0
- package/tools/game.ts +70 -0
- package/tools/mod-build.d.ts +28 -0
- package/tools/mod-build.js +173 -0
- package/tools/mod-build.ts +179 -0
- package/tools/mod-target.d.ts +16 -0
- package/tools/mod-target.js +26 -0
- package/tools/mod-target.ts +32 -0
- package/tools/mod.d.ts +1 -0
- package/tools/mod.js +47 -0
- package/tools/mod.ts +45 -0
- package/tools/msg.d.ts +1 -0
- package/tools/msg.js +40 -0
- package/tools/msg.ts +36 -0
- package/tools/node-files.d.ts +3 -0
- package/tools/node-files.js +34 -0
- package/tools/node-files.ts +33 -0
- package/tools/patches.d.ts +3 -0
- package/tools/patches.js +13 -0
- package/tools/patches.ts +13 -0
- package/tools/pic-build.d.ts +9 -0
- package/tools/pic-build.js +26 -0
- package/tools/pic-build.ts +27 -0
- package/tools/pic.d.ts +1 -0
- package/tools/pic.js +64 -0
- package/tools/pic.ts +61 -0
- package/tools/play.d.ts +1 -0
- package/tools/play.js +54 -0
- package/tools/play.ts +54 -0
- package/tools/png.d.ts +16 -0
- package/tools/png.js +124 -0
- package/tools/png.ts +123 -0
- package/tools/res.d.ts +1 -0
- package/tools/res.js +48 -0
- package/tools/res.ts +50 -0
- package/tools/scenario.d.ts +1 -0
- package/tools/scenario.js +74 -0
- package/tools/scenario.ts +80 -0
- package/tools/site/build.d.ts +8 -0
- package/tools/site/build.js +110 -0
- package/tools/site/build.ts +116 -0
- package/tools/site/markdown.d.ts +11 -0
- package/tools/site/markdown.js +88 -0
- package/tools/site/markdown.ts +84 -0
- package/tools/view-build.d.ts +34 -0
- package/tools/view-build.js +47 -0
- package/tools/view-build.ts +71 -0
- package/tools/view.d.ts +1 -0
- package/tools/view.js +54 -0
- package/tools/view.ts +52 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
4
|
+
versions follow [Semantic Versioning](https://semver.org/), and the entries are generated
|
|
5
|
+
from commit messages ([Conventional Commits](https://www.conventionalcommits.org/)).
|
|
6
|
+
|
|
7
|
+
## [0.2.1] - 2026-10-01
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **tools:** Publish as sci2-ts
|
|
12
|
+
|
|
13
|
+
## [0.2.0] - 2026-10-01
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **tools:** An art tool for PNGs exported from a paint program (pnpm art)
|
|
18
|
+
- **tools:** Sci-ts as a package, with the sci-ts command
|
|
19
|
+
- **tools:** Publish sci-ts to npm
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- **viewer:** Play games without an AdLib bank or a SoundFont
|
|
24
|
+
- **viewer:** A neutral sample text in the font preview
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- **game:** Sherlock moves to its own repository, sci-sherlock
|
|
29
|
+
|
|
30
|
+
### Documentation
|
|
31
|
+
|
|
32
|
+
- A game in its own repository, and the art tool
|
|
33
|
+
- The README shows the tools, and the package is on npm
|
|
34
|
+
|
|
35
|
+
## [0.1.0] - 2026-10-01
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- SCI2 engine, content compiler, viewer and tools
|
|
40
|
+
- **sci:** Resource archive, vocab and font writers
|
|
41
|
+
- **tools:** Build games from nothing with pnpm game build
|
|
42
|
+
- **sci:** Script compiler
|
|
43
|
+
- **sci:** Global declarations and computed selectors
|
|
44
|
+
- **lib:** The class library
|
|
45
|
+
- **game:** Hello on the class library
|
|
46
|
+
- **lib:** Talkers, portraits, conversations, flags and cutscenes
|
|
47
|
+
- **tools:** YAML and Yarn rooms for the class library, and the editor for our games
|
|
48
|
+
- **game:** Hello's road as a YAML room with someone to talk to
|
|
49
|
+
- **sci:** Write sound resources, SOL clips and sound effects
|
|
50
|
+
- **sci:** Switchto, @[buf i], selectors as values, and warnings for unknown sends
|
|
51
|
+
- **tools:** Music and effects, new games, a static site, and editing scripts live
|
|
52
|
+
- **game:** Music for hello, and a lantern that chimes
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
|
|
56
|
+
- **tools:** Games/hello in the script language
|
|
57
|
+
|
|
58
|
+
### Documentation
|
|
59
|
+
|
|
60
|
+
- README, how SCI works, the plan and the Sherlock Holmes teaser
|
|
61
|
+
- Making a game, and milestone 1 done
|
|
62
|
+
- The script language, and milestone 2 done
|
|
63
|
+
- The class library, and milestone 3 done
|
|
64
|
+
- Rooms as YAML and Yarn, and milestone 4 done
|
|
65
|
+
- Building a game from nothing, sound, the site and the tooling
|
|
66
|
+
|
|
67
|
+
### Maintenance
|
|
68
|
+
|
|
69
|
+
- Workspace, typecheck, tests and CI
|
|
70
|
+
- Build every game, and publish the site to GitHub Pages by hand
|
|
71
|
+
|
|
72
|
+
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rafael Lüder
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,114 @@
|
|
|
1
|
-
#
|
|
1
|
+
# sci-ts
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An engine for Sierra's SCI2 adventure games, written from scratch in TypeScript, and the
|
|
4
|
+
tools to make new games with it: scripts in SCI's own Lisp-like language on a class library
|
|
5
|
+
of our own, rooms written as YAML and [Yarn](https://docs.yarnspinner.dev), a live editor,
|
|
6
|
+
and writers for every kind of resource.
|
|
7
|
+
|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
It runs in the browser and in Node. It was built by making one game, *Quest for Glory IV:
|
|
11
|
+
Shadows of Darkness* (CD), play from its title screen on, and it now builds games that need
|
|
12
|
+
nothing from Sierra: `games/hello` here, and a Sherlock Holmes teaser in progress.
|
|
13
|
+
|
|
14
|
+
> **No game data here.** This repository contains no files, scripts, art, text or music from
|
|
15
|
+
> any Sierra game, and none are needed to build, test or use it. To play a Sierra game, point
|
|
16
|
+
> the tools at your own copy. Sierra, Quest for Glory and other names are trademarks of their
|
|
17
|
+
> owners and are used only to say what the software works with.
|
|
18
|
+
|
|
19
|
+
## Make a game
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
mkdir night-walk && cd night-walk
|
|
23
|
+
npm init -y && npm install --save-dev sci2-ts
|
|
24
|
+
npx sci-ts new . # a room in YAML and Yarn, a hero, placeholder art
|
|
25
|
+
npx sci-ts play # build it and play it in the browser
|
|
26
|
+
npx sci-ts edit # the live editor for its rooms
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
A game is a folder: scripts (`scripts/<n>.sc`), rooms as data (`rooms/<n>.room.yaml` and
|
|
30
|
+
`.yarn`), message files, music (MIDI files), sound effects (WAV files), and art drawn in code
|
|
31
|
+
or exported from a paint program. `sci-ts build` turns it into the `RESOURCE.MAP` and
|
|
32
|
+
`RESOURCE.000` an SCI interpreter opens. See [docs/games.md](docs/games.md).
|
|
33
|
+
|
|
34
|
+
```lisp
|
|
35
|
+
(instance lantern of Prop
|
|
36
|
+
(properties noun N_LANTERN view 100 x 160 y 172 cycleSpeed 12)
|
|
37
|
+
|
|
38
|
+
;; It chimes when touched, then says its line.
|
|
39
|
+
(method (doVerb verb)
|
|
40
|
+
(if (== verb V_DO) (sfx number: 50 play:))
|
|
41
|
+
(super doVerb: verb)))
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+

|
|
45
|
+
|
|
46
|
+
| | |
|
|
47
|
+
|---|---|
|
|
48
|
+
| [docs/games.md](docs/games.md) | a game's folder, the build, the `sci-ts` command and the package's imports |
|
|
49
|
+
| [docs/language.md](docs/language.md) | the script language |
|
|
50
|
+
| [docs/library.md](docs/library.md) | the class library: rooms, actors, walking, talking, conversations, flags, sound |
|
|
51
|
+
| [docs/rooms.md](docs/rooms.md) | rooms as YAML and Yarn: features, exits, characters, topic menus, cutscenes |
|
|
52
|
+
| [docs/art.md](docs/art.md) | art from a paint program: the manifest, the palette, the checks |
|
|
53
|
+
|
|
54
|
+
## The tools
|
|
55
|
+
|
|
56
|
+
**The player** plays a game in the page: saved games, a link to any room
|
|
57
|
+
(`play.html#room/2`), music through a SoundFont or an emulated AdLib card.
|
|
58
|
+
|
|
59
|
+

|
|
60
|
+
|
|
61
|
+
**The live editor** shows a room's YAML and Yarn, or its script, next to the running game.
|
|
62
|
+
Saving (or a pause in typing) rebuilds the game and walks into the room again; errors are
|
|
63
|
+
marked on their line. Outlines name the features, exits, props and walkable floor; in Move
|
|
64
|
+
mode things are dragged into place and floors painted with a brush, as edits to the YAML.
|
|
65
|
+
|
|
66
|
+

|
|
67
|
+
|
|
68
|
+

|
|
69
|
+
|
|
70
|
+
**The resource viewer** lists every resource with a thumbnail and the name the game's
|
|
71
|
+
scripts give it, searchable, with a player for sounds.
|
|
72
|
+
|
|
73
|
+

|
|
74
|
+
|
|
75
|
+
**The explorer** maps a game's rooms and how they connect, its classes and objects, and
|
|
76
|
+
inspects a running game.
|
|
77
|
+
|
|
78
|
+

|
|
79
|
+
|
|
80
|
+
**On the command line:** `sci-ts build`, `play`, `edit`, `new`, `site` (the game and its
|
|
81
|
+
docs as a static site) and `art` (check and build exported art). The compiler warns about
|
|
82
|
+
sends no class defines; `editors/vscode` highlights the language in VS Code.
|
|
83
|
+
|
|
84
|
+
## Inside
|
|
85
|
+
|
|
86
|
+
| | |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `packages/sci` | the engine: resources, the SCI2 virtual machine and its kernel, graphics, text, motion, sound, saves; readers and byte-exact writers for every resource; the script compiler and assembler |
|
|
89
|
+
| `packages/content` | the room compiler: YAML and Yarn to scripts and messages |
|
|
90
|
+
| `lib` | the class library, in the script language |
|
|
91
|
+
| `apps/viewer` | the player, editor, resource viewer and explorer |
|
|
92
|
+
| `tools` | the `sci-ts` command, the game build, the art tool, and tools for reading SCI2 games |
|
|
93
|
+
| `games/hello` | the example game |
|
|
94
|
+
|
|
95
|
+
How SCI works, as far as we found out by running a game: [docs/sci](docs/sci/README.md).
|
|
96
|
+
|
|
97
|
+
## Developing sci-ts
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
pnpm install
|
|
101
|
+
pnpm check # typecheck and tests; no game files needed
|
|
102
|
+
pnpm game build games/hello
|
|
103
|
+
SCI_GAME=out/games/hello pnpm viewer
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
With an SCI2 game of your own in `original/` (or `SCI_GAME=<dir>`), `pnpm viewer` opens it,
|
|
107
|
+
and `pnpm res`, `pnpm asm`, `pnpm msg` and `pnpm play` read, disassemble and run it.
|
|
108
|
+
|
|
109
|
+
See [docs/plan.md](docs/plan.md) for where this is going and [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
110
|
+
for how to help. Changes are in [CHANGELOG.md](CHANGELOG.md), generated from commit messages.
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Room Editor</title>
|
|
7
|
+
<link rel="stylesheet" href="/src/editor.css" />
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<main class="editor">
|
|
11
|
+
<section class="source">
|
|
12
|
+
<header>
|
|
13
|
+
<label>Mod <select id="mod"></select></label>
|
|
14
|
+
<label>Room <select id="room"></select></label>
|
|
15
|
+
<span class="spacer"></span>
|
|
16
|
+
<label class="auto" title="Rebuild a moment after you stop typing"><input id="auto" type="checkbox" checked /> live</label>
|
|
17
|
+
<button id="save" type="button" title="Save and rebuild (⌘S / Ctrl+S)">Save ⌘S</button>
|
|
18
|
+
</header>
|
|
19
|
+
<nav id="tabs"></nav>
|
|
20
|
+
<div class="code" id="code"></div>
|
|
21
|
+
<div id="problems" hidden></div>
|
|
22
|
+
</section>
|
|
23
|
+
<section class="game">
|
|
24
|
+
<div class="stage"><div class="screen" id="screen-box"><canvas id="screen" width="320" height="200"></canvas></div></div>
|
|
25
|
+
<div class="bar">
|
|
26
|
+
<span id="status">Loading…</span>
|
|
27
|
+
<span class="spacer"></span>
|
|
28
|
+
<span class="modes" id="modes" role="radiogroup" aria-label="What the mouse does on the game">
|
|
29
|
+
<button type="button" data-mode="play" title="Clicks go to the game">Play</button>
|
|
30
|
+
<button type="button" data-mode="move" title="Drag features, exits, props, the hero's points and floor corners; Alt-click a corner to remove it">Move</button>
|
|
31
|
+
<button type="button" data-mode="floor" title="Paint the walkable floor's outline">Draw floor</button>
|
|
32
|
+
<button type="button" data-mode="obstacle" title="Paint an obstacle the hero walks around">Draw obstacle</button>
|
|
33
|
+
</span>
|
|
34
|
+
<label title="Outline features, exits, sprites and walk areas"><input id="outlines" type="checkbox" checked /> Outlines</label>
|
|
35
|
+
<span class="legend" id="legend"></span>
|
|
36
|
+
<button id="restart" type="button" title="Back to the moment before entering the room, then in again">Restart scene</button>
|
|
37
|
+
<button id="sound" type="button">Sound off</button>
|
|
38
|
+
</div>
|
|
39
|
+
</section>
|
|
40
|
+
</main>
|
|
41
|
+
<script type="module" src="/src/editor.ts"></script>
|
|
42
|
+
</body>
|
|
43
|
+
</html>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>SCI Explorer</title>
|
|
7
|
+
<link rel="stylesheet" href="/src/explore/explore.css" />
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<header>
|
|
11
|
+
<strong>SCI Explorer</strong>
|
|
12
|
+
<nav>
|
|
13
|
+
<a href="#/map" data-tab="map">Room map</a>
|
|
14
|
+
<a href="#/classes" data-tab="classes">Classes</a>
|
|
15
|
+
<a href="#/live" data-tab="live">Live</a>
|
|
16
|
+
<a href="/index.html">Resources</a>
|
|
17
|
+
<a href="/play.html">Play</a>
|
|
18
|
+
</nav>
|
|
19
|
+
<input id="search" type="search" placeholder="Jump to room, class or object…" list="search-options" autocomplete="off" />
|
|
20
|
+
<datalist id="search-options"></datalist>
|
|
21
|
+
<span id="status"></span>
|
|
22
|
+
</header>
|
|
23
|
+
<main id="stage"></main>
|
|
24
|
+
<aside id="inspector"><p class="meta">Select a room or class.</p></aside>
|
|
25
|
+
<script type="module" src="/src/explore/explore.ts"></script>
|
|
26
|
+
</body>
|
|
27
|
+
</html>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>SCI Resources</title>
|
|
7
|
+
<link rel="stylesheet" href="/src/style.css" />
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<aside>
|
|
11
|
+
<select id="type"></select>
|
|
12
|
+
<input id="search" type="search" placeholder="Search: number, name, description ( / )" autocomplete="off" spellcheck="false" />
|
|
13
|
+
<div class="keys" id="index-status">Indexing the scripts…</div>
|
|
14
|
+
<label class="opt"><input type="checkbox" id="aspect" checked /> 4:3 aspect</label>
|
|
15
|
+
<div class="keys">↑↓ resources · ←→ type · PgUp/PgDn · Home/End · / search</div>
|
|
16
|
+
<ul id="list"></ul>
|
|
17
|
+
</aside>
|
|
18
|
+
<main>
|
|
19
|
+
<h1 id="title">Pick a resource</h1>
|
|
20
|
+
<div id="uses"></div>
|
|
21
|
+
<div id="view"></div>
|
|
22
|
+
<details><summary>Hex</summary><pre id="hex"></pre></details>
|
|
23
|
+
</main>
|
|
24
|
+
<script type="module" src="/src/main.ts"></script>
|
|
25
|
+
</body>
|
|
26
|
+
</html>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sci-ts/viewer",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "vite",
|
|
7
|
+
"build": "vite build"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@codemirror/commands": "^6.11.1",
|
|
11
|
+
"@codemirror/lang-yaml": "^6.1.3",
|
|
12
|
+
"@codemirror/language": "^6.12.4",
|
|
13
|
+
"@codemirror/lint": "^6.9.7",
|
|
14
|
+
"@codemirror/state": "^6.7.6",
|
|
15
|
+
"@codemirror/theme-one-dark": "^6.1.3",
|
|
16
|
+
"@codemirror/view": "^6.43.13",
|
|
17
|
+
"@sci-ts/sci": "workspace:*",
|
|
18
|
+
"codemirror": "^6.0.2",
|
|
19
|
+
"cytoscape": "^3.34.3",
|
|
20
|
+
"spessasynth_lib": "^4.3.14",
|
|
21
|
+
"yaml": "^2.9.1"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"sirv": "^3.0.2",
|
|
25
|
+
"vite": "^8.3.1"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>SCI Player</title>
|
|
7
|
+
<link rel="stylesheet" href="/src/play.css" />
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<main>
|
|
11
|
+
<canvas id="screen" width="320" height="200"></canvas>
|
|
12
|
+
<div class="bar">
|
|
13
|
+
<div id="status">Loading game files…</div>
|
|
14
|
+
<details id="mods">
|
|
15
|
+
<summary>Mods</summary>
|
|
16
|
+
<div id="mod-list"></div>
|
|
17
|
+
<button id="mods-apply" type="button">Apply (restarts the game)</button>
|
|
18
|
+
</details>
|
|
19
|
+
<button id="export-saves" type="button" title="Download every saved game as JSON (for tools/explore.ts loadsaves:)">Export saves</button>
|
|
20
|
+
<button id="music" type="button">Music</button>
|
|
21
|
+
</div>
|
|
22
|
+
<pre id="error" hidden></pre>
|
|
23
|
+
</main>
|
|
24
|
+
<script type="module" src="/src/play.ts"></script>
|
|
25
|
+
</body>
|
|
26
|
+
</html>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
export interface SciGameOptions {
|
|
3
|
+
/** The built game's folder (RESOURCE.MAP, RESOURCE.000...), served as /game/. */
|
|
4
|
+
game: string;
|
|
5
|
+
/** Built mods (one folder each), served as /game/MODS/<name> and listed at /__mods. */
|
|
6
|
+
mods?: string;
|
|
7
|
+
/** SoundFonts for music, served as /soundfonts/ (GeneralUser-GS.sf2 is the one used). */
|
|
8
|
+
soundfonts?: string;
|
|
9
|
+
/** The live editor's routes (/__editor): edits and rebuilds the game being served. */
|
|
10
|
+
editor?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A Vite plugin that serves an SCI game to pages using the player (`sci-ts/viewer`): the
|
|
14
|
+
* game's files under /game/ (Range requests too), directory listings at /__list, and
|
|
15
|
+
* optionally mods, SoundFonts and the editor's routes. Development only; a built site
|
|
16
|
+
* carries the game itself (see `sci-ts site`).
|
|
17
|
+
*/
|
|
18
|
+
export declare function sciGame(options: SciGameOptions): Plugin;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
const EDITOR_SERVER = resolve(import.meta.dirname, "../../tools/editor-server.ts");
|
|
4
|
+
/**
|
|
5
|
+
* A Vite plugin that serves an SCI game to pages using the player (`sci-ts/viewer`): the
|
|
6
|
+
* game's files under /game/ (Range requests too), directory listings at /__list, and
|
|
7
|
+
* optionally mods, SoundFonts and the editor's routes. Development only; a built site
|
|
8
|
+
* carries the game itself (see `sci-ts site`).
|
|
9
|
+
*/
|
|
10
|
+
export function sciGame(options) {
|
|
11
|
+
const game = resolve(options.game);
|
|
12
|
+
const mods = options.mods && resolve(options.mods);
|
|
13
|
+
return {
|
|
14
|
+
name: "sci-game",
|
|
15
|
+
// Pages outside this repository import the player's sources from it.
|
|
16
|
+
config: () => ({ server: { fs: { allow: [resolve(import.meta.dirname, "../.."), process.cwd()] } } }),
|
|
17
|
+
async configureServer(server) {
|
|
18
|
+
const sirv = (await import("sirv")).default;
|
|
19
|
+
// Before /game: mods look like a MODS folder inside the game, as patch directories.
|
|
20
|
+
if (mods) {
|
|
21
|
+
server.middlewares.use("/game/MODS", sirv(mods, { dev: true }));
|
|
22
|
+
server.middlewares.use("/__mods", async (_req, res) => {
|
|
23
|
+
const entries = await readdir(mods, { withFileTypes: true }).catch(() => []);
|
|
24
|
+
res.setHeader("content-type", "application/json");
|
|
25
|
+
res.end(JSON.stringify(entries.filter((e) => e.isDirectory()).map((e) => e.name).sort()));
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
// A file that isn't there is a 404, not the page (Vite's fallback for unknown paths):
|
|
29
|
+
// the player asks for files a game may not have (RESOURCE.SFX, the SoundFont).
|
|
30
|
+
const notFound = (_req, res) => ((res.statusCode = 404), res.end());
|
|
31
|
+
server.middlewares.use("/game", sirv(game, { dev: true }));
|
|
32
|
+
server.middlewares.use("/game", notFound);
|
|
33
|
+
if (options.soundfonts)
|
|
34
|
+
server.middlewares.use("/soundfonts", sirv(resolve(options.soundfonts), { dev: true }));
|
|
35
|
+
server.middlewares.use("/soundfonts", notFound);
|
|
36
|
+
if (options.editor) {
|
|
37
|
+
// Loaded through Vite so edits to the tools take effect; the game stays loaded in it.
|
|
38
|
+
const editor = () => server.ssrLoadModule(EDITOR_SERVER);
|
|
39
|
+
server.middlewares.use("/__editor", async (req, res) => {
|
|
40
|
+
const url = new URL(req.url ?? "", "http://x");
|
|
41
|
+
const json = (status, body) => {
|
|
42
|
+
res.statusCode = status;
|
|
43
|
+
res.setHeader("content-type", "application/json");
|
|
44
|
+
res.end(JSON.stringify(body));
|
|
45
|
+
};
|
|
46
|
+
try {
|
|
47
|
+
const mod = url.searchParams.get("mod") ?? "";
|
|
48
|
+
if (req.method === "GET" && url.pathname === "/mods")
|
|
49
|
+
return json(200, (await editor()).listMods());
|
|
50
|
+
if (req.method === "GET" && url.pathname === "/files")
|
|
51
|
+
return json(200, (await editor()).readFiles(mod));
|
|
52
|
+
if (req.method === "POST" && url.pathname === "/save") {
|
|
53
|
+
let body = "";
|
|
54
|
+
for await (const chunk of req)
|
|
55
|
+
body += chunk;
|
|
56
|
+
const { files } = JSON.parse(body);
|
|
57
|
+
return json(200, await (await editor()).save(mod, files));
|
|
58
|
+
}
|
|
59
|
+
json(404, { error: "unknown editor route" });
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
json(500, { error: e.message });
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
server.middlewares.use("/__list", async (req, res) => {
|
|
67
|
+
const dir = new URL(req.url ?? "", "http://x").searchParams.get("dir") ?? "";
|
|
68
|
+
const base = mods && (dir === "MODS" || dir.startsWith("MODS/")) ? resolve(mods, dir.slice(5)) : resolve(game, dir);
|
|
69
|
+
const names = await readdir(base).catch(() => []);
|
|
70
|
+
res.setHeader("content-type", "application/json");
|
|
71
|
+
res.end(JSON.stringify(names));
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import type { Plugin } from "vite";
|
|
4
|
+
|
|
5
|
+
export interface SciGameOptions {
|
|
6
|
+
/** The built game's folder (RESOURCE.MAP, RESOURCE.000...), served as /game/. */
|
|
7
|
+
game: string;
|
|
8
|
+
/** Built mods (one folder each), served as /game/MODS/<name> and listed at /__mods. */
|
|
9
|
+
mods?: string;
|
|
10
|
+
/** SoundFonts for music, served as /soundfonts/ (GeneralUser-GS.sf2 is the one used). */
|
|
11
|
+
soundfonts?: string;
|
|
12
|
+
/** The live editor's routes (/__editor): edits and rebuilds the game being served. */
|
|
13
|
+
editor?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const EDITOR_SERVER = resolve(import.meta.dirname, "../../tools/editor-server.ts");
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A Vite plugin that serves an SCI game to pages using the player (`sci-ts/viewer`): the
|
|
20
|
+
* game's files under /game/ (Range requests too), directory listings at /__list, and
|
|
21
|
+
* optionally mods, SoundFonts and the editor's routes. Development only; a built site
|
|
22
|
+
* carries the game itself (see `sci-ts site`).
|
|
23
|
+
*/
|
|
24
|
+
export function sciGame(options: SciGameOptions): Plugin {
|
|
25
|
+
const game = resolve(options.game);
|
|
26
|
+
const mods = options.mods && resolve(options.mods);
|
|
27
|
+
return {
|
|
28
|
+
name: "sci-game",
|
|
29
|
+
// Pages outside this repository import the player's sources from it.
|
|
30
|
+
config: () => ({ server: { fs: { allow: [resolve(import.meta.dirname, "../.."), process.cwd()] } } }),
|
|
31
|
+
async configureServer(server) {
|
|
32
|
+
const sirv = (await import("sirv")).default;
|
|
33
|
+
// Before /game: mods look like a MODS folder inside the game, as patch directories.
|
|
34
|
+
if (mods) {
|
|
35
|
+
server.middlewares.use("/game/MODS", sirv(mods, { dev: true }));
|
|
36
|
+
server.middlewares.use("/__mods", async (_req, res) => {
|
|
37
|
+
const entries = await readdir(mods, { withFileTypes: true }).catch(() => []);
|
|
38
|
+
res.setHeader("content-type", "application/json");
|
|
39
|
+
res.end(JSON.stringify(entries.filter((e) => e.isDirectory()).map((e) => e.name).sort()));
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
// A file that isn't there is a 404, not the page (Vite's fallback for unknown paths):
|
|
43
|
+
// the player asks for files a game may not have (RESOURCE.SFX, the SoundFont).
|
|
44
|
+
const notFound = (_req: unknown, res: { statusCode: number; end: () => void }) => ((res.statusCode = 404), res.end());
|
|
45
|
+
server.middlewares.use("/game", sirv(game, { dev: true }));
|
|
46
|
+
server.middlewares.use("/game", notFound);
|
|
47
|
+
if (options.soundfonts) server.middlewares.use("/soundfonts", sirv(resolve(options.soundfonts), { dev: true }));
|
|
48
|
+
server.middlewares.use("/soundfonts", notFound);
|
|
49
|
+
if (options.editor) {
|
|
50
|
+
// Loaded through Vite so edits to the tools take effect; the game stays loaded in it.
|
|
51
|
+
const editor = () => server.ssrLoadModule(EDITOR_SERVER) as Promise<typeof import("../../tools/editor-server.ts")>;
|
|
52
|
+
server.middlewares.use("/__editor", async (req, res) => {
|
|
53
|
+
const url = new URL(req.url ?? "", "http://x");
|
|
54
|
+
const json = (status: number, body: unknown) => {
|
|
55
|
+
res.statusCode = status;
|
|
56
|
+
res.setHeader("content-type", "application/json");
|
|
57
|
+
res.end(JSON.stringify(body));
|
|
58
|
+
};
|
|
59
|
+
try {
|
|
60
|
+
const mod = url.searchParams.get("mod") ?? "";
|
|
61
|
+
if (req.method === "GET" && url.pathname === "/mods") return json(200, (await editor()).listMods());
|
|
62
|
+
if (req.method === "GET" && url.pathname === "/files") return json(200, (await editor()).readFiles(mod));
|
|
63
|
+
if (req.method === "POST" && url.pathname === "/save") {
|
|
64
|
+
let body = "";
|
|
65
|
+
for await (const chunk of req) body += chunk;
|
|
66
|
+
const { files } = JSON.parse(body) as { files: Record<string, string> };
|
|
67
|
+
return json(200, await (await editor()).save(mod, files));
|
|
68
|
+
}
|
|
69
|
+
json(404, { error: "unknown editor route" });
|
|
70
|
+
} catch (e) {
|
|
71
|
+
json(500, { error: (e as Error).message });
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
server.middlewares.use("/__list", async (req, res) => {
|
|
76
|
+
const dir = new URL(req.url ?? "", "http://x").searchParams.get("dir") ?? "";
|
|
77
|
+
const base = mods && (dir === "MODS" || dir.startsWith("MODS/")) ? resolve(mods, dir.slice(5)) : resolve(game, dir);
|
|
78
|
+
const names = await readdir(base).catch(() => []);
|
|
79
|
+
res.setHeader("content-type", "application/json");
|
|
80
|
+
res.end(JSON.stringify(names));
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type AdLibBank, type MidiOutput } from "../../../packages/sci/src/index.ts";
|
|
2
|
+
/**
|
|
3
|
+
* AdLib music: Sierra's driver runs here and batches OPL register writes to the chip
|
|
4
|
+
* emulator in an AudioWorklet (flushed once per microtask, i.e. per burst of MIDI events).
|
|
5
|
+
*/
|
|
6
|
+
export declare class AdLibOutput implements MidiOutput {
|
|
7
|
+
private readonly node;
|
|
8
|
+
private readonly bank;
|
|
9
|
+
private driver;
|
|
10
|
+
private queue;
|
|
11
|
+
private flushScheduled;
|
|
12
|
+
private constructor();
|
|
13
|
+
static create(ctx: AudioContext, bank: AdLibBank): Promise<AdLibOutput>;
|
|
14
|
+
private newDriver;
|
|
15
|
+
/** Silences the chip and starts from a clean driver (used when switching devices). */
|
|
16
|
+
reset(): void;
|
|
17
|
+
send(bytes: number[]): void;
|
|
18
|
+
claimVoices(channel: number, count: number): void;
|
|
19
|
+
setMasterVolume(volume: number): void;
|
|
20
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { AdLibDriver } from "../../../packages/sci/src/index.js";
|
|
2
|
+
import workletUrl from "./opl-worklet.ts?worker&url";
|
|
3
|
+
/**
|
|
4
|
+
* AdLib music: Sierra's driver runs here and batches OPL register writes to the chip
|
|
5
|
+
* emulator in an AudioWorklet (flushed once per microtask, i.e. per burst of MIDI events).
|
|
6
|
+
*/
|
|
7
|
+
export class AdLibOutput {
|
|
8
|
+
node;
|
|
9
|
+
bank;
|
|
10
|
+
driver;
|
|
11
|
+
queue = [];
|
|
12
|
+
flushScheduled = false;
|
|
13
|
+
constructor(node, bank) {
|
|
14
|
+
this.node = node;
|
|
15
|
+
this.bank = bank;
|
|
16
|
+
this.driver = this.newDriver();
|
|
17
|
+
}
|
|
18
|
+
static async create(ctx, bank) {
|
|
19
|
+
await ctx.audioWorklet.addModule(workletUrl);
|
|
20
|
+
const node = new AudioWorkletNode(ctx, "opl2", { outputChannelCount: [2] });
|
|
21
|
+
node.connect(ctx.destination);
|
|
22
|
+
return new AdLibOutput(node, bank);
|
|
23
|
+
}
|
|
24
|
+
newDriver() {
|
|
25
|
+
const chip = {
|
|
26
|
+
write: (reg, value) => {
|
|
27
|
+
this.queue.push(reg, value);
|
|
28
|
+
if (!this.flushScheduled) {
|
|
29
|
+
this.flushScheduled = true;
|
|
30
|
+
queueMicrotask(() => {
|
|
31
|
+
this.flushScheduled = false;
|
|
32
|
+
this.node.port.postMessage(this.queue);
|
|
33
|
+
this.queue = [];
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
return new AdLibDriver(chip, this.bank);
|
|
39
|
+
}
|
|
40
|
+
/** Silences the chip and starts from a clean driver (used when switching devices). */
|
|
41
|
+
reset() {
|
|
42
|
+
this.queue = [];
|
|
43
|
+
this.node.port.postMessage("reset");
|
|
44
|
+
this.driver = this.newDriver();
|
|
45
|
+
}
|
|
46
|
+
send(bytes) {
|
|
47
|
+
this.driver.send(bytes);
|
|
48
|
+
}
|
|
49
|
+
claimVoices(channel, count) {
|
|
50
|
+
this.driver.claimVoices(channel, count);
|
|
51
|
+
}
|
|
52
|
+
setMasterVolume(volume) {
|
|
53
|
+
this.driver.setMasterVolume(volume);
|
|
54
|
+
}
|
|
55
|
+
}
|