sci2-ts 0.0.0-stage → 0.2.2
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 +78 -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
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the compiler needs to know about the game it builds for: which classes rooms
|
|
3
|
+
* subclass, where the system objects live (globals) and how messages are numbered. The
|
|
4
|
+
* compiler itself knows nothing about any particular game.
|
|
5
|
+
*/
|
|
6
|
+
export interface Target {
|
|
7
|
+
/** The class new rooms subclass: the game's own room class. */
|
|
8
|
+
roomClass: string;
|
|
9
|
+
/** Property values every room gets unless the YAML overrides them. */
|
|
10
|
+
roomDefaults: Record<string, number>;
|
|
11
|
+
/** Global variable numbers (SCI's script 0 locals). */
|
|
12
|
+
globals: {
|
|
13
|
+
ego: number;
|
|
14
|
+
game: number;
|
|
15
|
+
curRoom: number;
|
|
16
|
+
/** The Messager instance whose `say:` shows a message. */
|
|
17
|
+
messager: number;
|
|
18
|
+
/** The narrator object (what unknown talker numbers fall back to). */
|
|
19
|
+
narratorObject: number;
|
|
20
|
+
/** The Sound object playing the music, and the one for sound effects. */
|
|
21
|
+
music: number;
|
|
22
|
+
sound: number;
|
|
23
|
+
};
|
|
24
|
+
/** Message talker number for narration (no speaker). */
|
|
25
|
+
narrator: number;
|
|
26
|
+
/** Message talker number for the hero (`Hero:` lines, and the topics they pick). */
|
|
27
|
+
heroTalker: number;
|
|
28
|
+
/**
|
|
29
|
+
* Talker numbers from here up are characters defined by compiled rooms: the game asks
|
|
30
|
+
* the current room's `findTalker:` for them (needs the target's support patch).
|
|
31
|
+
*/
|
|
32
|
+
firstRoomTalker: number;
|
|
33
|
+
/** A character without a portrait: a plain text box, this class and properties. */
|
|
34
|
+
voice: {
|
|
35
|
+
class: string;
|
|
36
|
+
props: Record<string, number>;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* A character with a portrait view: loop 0 the bust, loop 1 mouth shapes, loop 2 eyes
|
|
40
|
+
* (cel 0 open), all cels the same size so the parts line up. The talker class gets
|
|
41
|
+
* `init: mouth bust eyes frame`; parts are a View (bust) and Props at `at`.
|
|
42
|
+
*/
|
|
43
|
+
portrait: {
|
|
44
|
+
class: string;
|
|
45
|
+
props: Record<string, number>;
|
|
46
|
+
at: [number, number];
|
|
47
|
+
frameSignal: number;
|
|
48
|
+
partSignal: number;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Conversations: an instance of this class runs a menu of topics for a thing (e.g. a
|
|
52
|
+
* Teller with `init: client modNum sayNoun verb rootNoun`; topic labels are messages at
|
|
53
|
+
* rootNoun/verb/cond, answers at sayNoun/verb/cond).
|
|
54
|
+
*/
|
|
55
|
+
teller: {
|
|
56
|
+
class: string;
|
|
57
|
+
props: Record<string, number>;
|
|
58
|
+
verb: number;
|
|
59
|
+
};
|
|
60
|
+
/** The class that cycles a prop's cels forever (<<animate x forever>>, cycle: forward). */
|
|
61
|
+
forwardCycle: string;
|
|
62
|
+
/** Verb number for "said on arrival" messages. */
|
|
63
|
+
narrationVerb: number;
|
|
64
|
+
/** Verb names as used in Yarn node titles (lower case) -> verb numbers. */
|
|
65
|
+
verbs: Record<string, number>;
|
|
66
|
+
/** Message file version written in new message files. */
|
|
67
|
+
messageVersion: number;
|
|
68
|
+
/**
|
|
69
|
+
* Flags (Yarn's true/false variables): procedures `set`, `clear`, `test` (export numbers
|
|
70
|
+
* of `script`, each taking the flag number), and the range a mod may use.
|
|
71
|
+
*/
|
|
72
|
+
flags: {
|
|
73
|
+
script: number;
|
|
74
|
+
set: number;
|
|
75
|
+
clear: number;
|
|
76
|
+
test: number;
|
|
77
|
+
first: number;
|
|
78
|
+
last: number;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the compiler needs to know about the game it builds for: which classes rooms
|
|
3
|
+
* subclass, where the system objects live (globals) and how messages are numbered. The
|
|
4
|
+
* compiler itself knows nothing about any particular game.
|
|
5
|
+
*/
|
|
6
|
+
export interface Target {
|
|
7
|
+
/** The class new rooms subclass: the game's own room class. */
|
|
8
|
+
roomClass: string;
|
|
9
|
+
/** Property values every room gets unless the YAML overrides them. */
|
|
10
|
+
roomDefaults: Record<string, number>;
|
|
11
|
+
/** Global variable numbers (SCI's script 0 locals). */
|
|
12
|
+
globals: {
|
|
13
|
+
ego: number;
|
|
14
|
+
game: number;
|
|
15
|
+
curRoom: number;
|
|
16
|
+
/** The Messager instance whose `say:` shows a message. */
|
|
17
|
+
messager: number;
|
|
18
|
+
/** The narrator object (what unknown talker numbers fall back to). */
|
|
19
|
+
narratorObject: number;
|
|
20
|
+
/** The Sound object playing the music, and the one for sound effects. */
|
|
21
|
+
music: number;
|
|
22
|
+
sound: number;
|
|
23
|
+
};
|
|
24
|
+
/** Message talker number for narration (no speaker). */
|
|
25
|
+
narrator: number;
|
|
26
|
+
/** Message talker number for the hero (`Hero:` lines, and the topics they pick). */
|
|
27
|
+
heroTalker: number;
|
|
28
|
+
/**
|
|
29
|
+
* Talker numbers from here up are characters defined by compiled rooms: the game asks
|
|
30
|
+
* the current room's `findTalker:` for them (needs the target's support patch).
|
|
31
|
+
*/
|
|
32
|
+
firstRoomTalker: number;
|
|
33
|
+
/** A character without a portrait: a plain text box, this class and properties. */
|
|
34
|
+
voice: { class: string; props: Record<string, number> };
|
|
35
|
+
/**
|
|
36
|
+
* A character with a portrait view: loop 0 the bust, loop 1 mouth shapes, loop 2 eyes
|
|
37
|
+
* (cel 0 open), all cels the same size so the parts line up. The talker class gets
|
|
38
|
+
* `init: mouth bust eyes frame`; parts are a View (bust) and Props at `at`.
|
|
39
|
+
*/
|
|
40
|
+
portrait: { class: string; props: Record<string, number>; at: [number, number]; frameSignal: number; partSignal: number };
|
|
41
|
+
/**
|
|
42
|
+
* Conversations: an instance of this class runs a menu of topics for a thing (e.g. a
|
|
43
|
+
* Teller with `init: client modNum sayNoun verb rootNoun`; topic labels are messages at
|
|
44
|
+
* rootNoun/verb/cond, answers at sayNoun/verb/cond).
|
|
45
|
+
*/
|
|
46
|
+
teller: { class: string; props: Record<string, number>; verb: number };
|
|
47
|
+
/** The class that cycles a prop's cels forever (<<animate x forever>>, cycle: forward). */
|
|
48
|
+
forwardCycle: string;
|
|
49
|
+
/** Verb number for "said on arrival" messages. */
|
|
50
|
+
narrationVerb: number;
|
|
51
|
+
/** Verb names as used in Yarn node titles (lower case) -> verb numbers. */
|
|
52
|
+
verbs: Record<string, number>;
|
|
53
|
+
/** Message file version written in new message files. */
|
|
54
|
+
messageVersion: number;
|
|
55
|
+
/**
|
|
56
|
+
* Flags (Yarn's true/false variables): procedures `set`, `clear`, `test` (export numbers
|
|
57
|
+
* of `script`, each taking the flag number), and the range a mod may use.
|
|
58
|
+
*/
|
|
59
|
+
flags: { script: number; set: number; clear: number; test: number; first: number; last: number };
|
|
60
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Yarn Spinner's file format (https://docs.yarnspinner.dev), the part rooms use so far:
|
|
3
|
+
*
|
|
4
|
+
* title: wisp.talk <- headers, `key: value`, until ---
|
|
5
|
+
* ---
|
|
6
|
+
* Golden pods hang from the rock. <- a line; `Speaker: text` names who says it
|
|
7
|
+
* <<if $met_wisp>> <- conditions on true/false variables:
|
|
8
|
+
* They hum when you're near. not, and, or, ==, !=, (...), true, false
|
|
9
|
+
* <<else>>
|
|
10
|
+
* They're silent.
|
|
11
|
+
* <<endif>>
|
|
12
|
+
* <<set $looked to true>>
|
|
13
|
+
* -> Who are you? <- a choice; its body is indented below it
|
|
14
|
+
* Wisp: A memory of this place.
|
|
15
|
+
* -> Sing for me <<if $met_wisp>> <- a choice only offered when its condition holds
|
|
16
|
+
* Wisp: Not yet.
|
|
17
|
+
* // a comment
|
|
18
|
+
* ===
|
|
19
|
+
*
|
|
20
|
+
* Other commands (<<walk hero 110 160>>, <<wait 2>>...) are kept as name + arguments for
|
|
21
|
+
* the compiler to check. Choices inside choices or inside <<if>> are rejected with the
|
|
22
|
+
* line they're on, until the compiler supports them.
|
|
23
|
+
*/
|
|
24
|
+
export interface YarnNode {
|
|
25
|
+
title: string;
|
|
26
|
+
headers: Record<string, string>;
|
|
27
|
+
body: YarnItem[];
|
|
28
|
+
/** Where the node starts, for error messages. */
|
|
29
|
+
line: number;
|
|
30
|
+
}
|
|
31
|
+
export type YarnItem = YarnLine | YarnChoice | YarnSet | YarnIf | YarnCommand;
|
|
32
|
+
/** Any other <<command arg arg ...>>; the compiler knows which exist (walk, wait, ...). */
|
|
33
|
+
export interface YarnCommand {
|
|
34
|
+
kind: "command";
|
|
35
|
+
name: string;
|
|
36
|
+
args: string[];
|
|
37
|
+
line: number;
|
|
38
|
+
}
|
|
39
|
+
export interface YarnLine {
|
|
40
|
+
kind: "line";
|
|
41
|
+
speaker?: string;
|
|
42
|
+
text: string;
|
|
43
|
+
line: number;
|
|
44
|
+
}
|
|
45
|
+
export interface YarnChoice {
|
|
46
|
+
kind: "choice";
|
|
47
|
+
text: string;
|
|
48
|
+
/** Only offered when this holds. */
|
|
49
|
+
when?: YarnExpr;
|
|
50
|
+
body: YarnItem[];
|
|
51
|
+
line: number;
|
|
52
|
+
}
|
|
53
|
+
export interface YarnSet {
|
|
54
|
+
kind: "set";
|
|
55
|
+
name: string;
|
|
56
|
+
value: YarnExpr;
|
|
57
|
+
line: number;
|
|
58
|
+
}
|
|
59
|
+
export interface YarnIf {
|
|
60
|
+
kind: "if";
|
|
61
|
+
/** `if` and `elseif` branches in order; a final `else` has no condition. */
|
|
62
|
+
branches: {
|
|
63
|
+
when?: YarnExpr;
|
|
64
|
+
body: YarnItem[];
|
|
65
|
+
}[];
|
|
66
|
+
line: number;
|
|
67
|
+
}
|
|
68
|
+
/** Boolean expressions over variables (each a flag). */
|
|
69
|
+
export type YarnExpr = {
|
|
70
|
+
kind: "var";
|
|
71
|
+
name: string;
|
|
72
|
+
} | {
|
|
73
|
+
kind: "const";
|
|
74
|
+
value: boolean;
|
|
75
|
+
} | {
|
|
76
|
+
kind: "not";
|
|
77
|
+
of: YarnExpr;
|
|
78
|
+
} | {
|
|
79
|
+
kind: "and" | "or";
|
|
80
|
+
a: YarnExpr;
|
|
81
|
+
b: YarnExpr;
|
|
82
|
+
};
|
|
83
|
+
export declare class YarnError extends Error {
|
|
84
|
+
readonly file: string;
|
|
85
|
+
readonly line: number;
|
|
86
|
+
constructor(file: string, line: number, message: string);
|
|
87
|
+
}
|
|
88
|
+
export declare function parseYarn(source: string, file?: string): YarnNode[];
|
|
89
|
+
/** `$a and not ($b or $c == false)`: Yarn's boolean operators, both spellings. */
|
|
90
|
+
export declare function parseExpr(source: string, fail: (why: string) => never): YarnExpr;
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
export class YarnError extends Error {
|
|
2
|
+
file;
|
|
3
|
+
line;
|
|
4
|
+
constructor(file, line, message) {
|
|
5
|
+
super(`${file}:${line}: ${message}`);
|
|
6
|
+
this.file = file;
|
|
7
|
+
this.line = line;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/** Trailing #tags (Yarn's line ids and metadata) don't belong to the text. */
|
|
11
|
+
const stripTags = (s) => s.replace(/(\s+#[^\s#]+)+\s*$/, "");
|
|
12
|
+
const indentOf = (s) => /^[ \t]*/.exec(s)[0].replace(/\t/g, " ").length;
|
|
13
|
+
export function parseYarn(source, file = "<yarn>") {
|
|
14
|
+
const nodes = [];
|
|
15
|
+
const lines = source.split(/\r?\n/);
|
|
16
|
+
let i = 0;
|
|
17
|
+
const fail = (line, why) => {
|
|
18
|
+
throw new YarnError(file, line, why);
|
|
19
|
+
};
|
|
20
|
+
while (i < lines.length) {
|
|
21
|
+
// Headers.
|
|
22
|
+
const start = i + 1;
|
|
23
|
+
const headers = {};
|
|
24
|
+
for (; i < lines.length && lines[i].trim() !== "---"; i++) {
|
|
25
|
+
const raw = lines[i].trim();
|
|
26
|
+
if (!raw || raw.startsWith("//"))
|
|
27
|
+
continue;
|
|
28
|
+
const m = /^([A-Za-z_][\w.-]*)\s*:\s*(.*)$/.exec(raw);
|
|
29
|
+
if (!m)
|
|
30
|
+
fail(i + 1, `expected a header (key: value) or ---, got "${raw}"`);
|
|
31
|
+
headers[m[1]] = m[2].trim();
|
|
32
|
+
}
|
|
33
|
+
if (i >= lines.length) {
|
|
34
|
+
if (Object.keys(headers).length)
|
|
35
|
+
fail(start, "node has no body: expected --- after its headers");
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
const title = headers.title;
|
|
39
|
+
if (!title)
|
|
40
|
+
fail(start, "node has no title: header");
|
|
41
|
+
if (nodes.some((n) => n.title === title))
|
|
42
|
+
fail(start, `a node called "${title}" already exists`);
|
|
43
|
+
i++; // ---
|
|
44
|
+
// The body's lines up to ===, then parsed into a tree.
|
|
45
|
+
const body = [];
|
|
46
|
+
let closed = false;
|
|
47
|
+
for (; i < lines.length; i++) {
|
|
48
|
+
const raw = lines[i].trim();
|
|
49
|
+
if (raw === "===") {
|
|
50
|
+
closed = true;
|
|
51
|
+
i++;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
if (!raw || raw.startsWith("//"))
|
|
55
|
+
continue;
|
|
56
|
+
body.push({ text: raw, indent: indentOf(lines[i]), line: i + 1 });
|
|
57
|
+
}
|
|
58
|
+
if (!closed)
|
|
59
|
+
fail(start, `node "${title}" isn't closed with ===`);
|
|
60
|
+
const parser = new BodyParser(body, fail);
|
|
61
|
+
nodes.push({ title: title, headers, body: parser.block(-1, false, false, []), line: start });
|
|
62
|
+
if (parser.at < body.length) {
|
|
63
|
+
const extra = body[parser.at];
|
|
64
|
+
fail(extra.line, `unexpected ${extra.text.split(/\s/)[0]} (no <<if>> is open)`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return nodes;
|
|
68
|
+
}
|
|
69
|
+
class BodyParser {
|
|
70
|
+
lines;
|
|
71
|
+
fail;
|
|
72
|
+
at = 0;
|
|
73
|
+
constructor(lines, fail) {
|
|
74
|
+
this.lines = lines;
|
|
75
|
+
this.fail = fail;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Items until a line indented at most `parentIndent` (the end of a choice's body) or, in
|
|
79
|
+
* an <<if>>, one of `stopAt` (elseif/else/endif).
|
|
80
|
+
*/
|
|
81
|
+
block(parentIndent, inChoice, inIf, stopAt) {
|
|
82
|
+
const items = [];
|
|
83
|
+
let choiceIndent;
|
|
84
|
+
while (this.at < this.lines.length) {
|
|
85
|
+
const { text, indent, line } = this.lines[this.at];
|
|
86
|
+
if (indent <= parentIndent)
|
|
87
|
+
break;
|
|
88
|
+
const command = /^<<\s*(\w+)\s*(.*?)\s*>>$/.exec(text);
|
|
89
|
+
if (command && stopAt.includes(command[1]))
|
|
90
|
+
break;
|
|
91
|
+
this.at++;
|
|
92
|
+
if (text.startsWith("->")) {
|
|
93
|
+
if (inChoice)
|
|
94
|
+
this.fail(line, "choices inside choices aren't supported yet");
|
|
95
|
+
if (inIf)
|
|
96
|
+
this.fail(line, "choices inside <<if>> aren't supported yet (use -> text <<if $x>>)");
|
|
97
|
+
if (choiceIndent !== undefined && indent !== choiceIndent)
|
|
98
|
+
this.fail(line, "choices in a group must line up");
|
|
99
|
+
choiceIndent = indent;
|
|
100
|
+
let rest = stripTags(text.slice(2).trim());
|
|
101
|
+
let when;
|
|
102
|
+
const cond = /^(.*?)\s*<<\s*if\s+(.+?)\s*>>$/.exec(rest);
|
|
103
|
+
if (cond) {
|
|
104
|
+
rest = cond[1];
|
|
105
|
+
when = parseExpr(cond[2], (why) => this.fail(line, why));
|
|
106
|
+
}
|
|
107
|
+
if (!rest)
|
|
108
|
+
this.fail(line, "a choice needs text after ->");
|
|
109
|
+
items.push({ kind: "choice", text: rest, when, body: this.block(indent, true, false, []), line });
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (command) {
|
|
113
|
+
const [, name, args] = command;
|
|
114
|
+
if (name === "set") {
|
|
115
|
+
const m = /^\$([A-Za-z_]\w*)\s*(?:to|=)\s*(.+)$/.exec(args);
|
|
116
|
+
if (!m)
|
|
117
|
+
this.fail(line, "expected <<set $name to true>> (or false, or a condition)");
|
|
118
|
+
items.push({ kind: "set", name: m[1], value: parseExpr(m[2], (why) => this.fail(line, why)), line });
|
|
119
|
+
}
|
|
120
|
+
else if (name === "if") {
|
|
121
|
+
items.push(this.ifBlock(args, line, indent, inChoice));
|
|
122
|
+
}
|
|
123
|
+
else if (["elseif", "else", "endif"].includes(name)) {
|
|
124
|
+
this.fail(line, `<<${name}>> without an <<if>>`);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
items.push({ kind: "command", name: name, args: args ? args.split(/[\s,]+/).filter(Boolean) : [], line });
|
|
128
|
+
}
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (text.startsWith("<<"))
|
|
132
|
+
this.fail(line, `expected <<command ...>>, got "${text}"`);
|
|
133
|
+
const clean = stripTags(text);
|
|
134
|
+
const m = /^([A-Za-z][\w ]*?)\s*:\s+(.+)$/.exec(clean);
|
|
135
|
+
items.push(m ? { kind: "line", speaker: m[1], text: m[2], line } : { kind: "line", text: clean, line });
|
|
136
|
+
}
|
|
137
|
+
return items;
|
|
138
|
+
}
|
|
139
|
+
ifBlock(firstCond, line, indent, inChoice) {
|
|
140
|
+
const fail = (why) => this.fail(line, why);
|
|
141
|
+
const branches = [{ when: parseExpr(firstCond, fail), body: [] }];
|
|
142
|
+
// An <<if>>'s body is whatever comes before its <<elseif>>/<<else>>/<<endif>>, at any
|
|
143
|
+
// indentation deeper than the enclosing choice (Yarn doesn't require indenting it).
|
|
144
|
+
for (;;) {
|
|
145
|
+
branches[branches.length - 1].body = this.block(inChoice ? indent - 1 : -1, inChoice, true, ["elseif", "else", "endif"]);
|
|
146
|
+
const next = this.lines[this.at];
|
|
147
|
+
const command = next && /^<<\s*(\w+)\s*(.*?)\s*>>$/.exec(next.text);
|
|
148
|
+
if (!command)
|
|
149
|
+
this.fail(line, "<<if>> without <<endif>>");
|
|
150
|
+
this.at++;
|
|
151
|
+
if (command[1] === "endif")
|
|
152
|
+
return { kind: "if", branches, line };
|
|
153
|
+
if (branches.at(-1).when === undefined)
|
|
154
|
+
this.fail(next.line, `<<${command[1]}>> after <<else>>`);
|
|
155
|
+
if (command[1] === "else")
|
|
156
|
+
branches.push({ body: [] });
|
|
157
|
+
else
|
|
158
|
+
branches.push({ when: parseExpr(command[2], (why) => this.fail(next.line, why)), body: [] });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/** `$a and not ($b or $c == false)`: Yarn's boolean operators, both spellings. */
|
|
163
|
+
export function parseExpr(source, fail) {
|
|
164
|
+
const tokens = source.match(/\$[A-Za-z_]\w*|&&|\|\||==|!=|[()!]|[A-Za-z_]\w*|\S/g) ?? [];
|
|
165
|
+
let p = 0;
|
|
166
|
+
const peek = () => tokens[p];
|
|
167
|
+
const take = () => tokens[p++];
|
|
168
|
+
const word = (t, ...names) => t !== undefined && names.includes(t.toLowerCase());
|
|
169
|
+
const or = () => {
|
|
170
|
+
let a = and();
|
|
171
|
+
while (word(peek(), "or", "||"))
|
|
172
|
+
(take(), (a = { kind: "or", a, b: and() }));
|
|
173
|
+
return a;
|
|
174
|
+
};
|
|
175
|
+
const and = () => {
|
|
176
|
+
let a = compare();
|
|
177
|
+
while (word(peek(), "and", "&&"))
|
|
178
|
+
(take(), (a = { kind: "and", a, b: compare() }));
|
|
179
|
+
return a;
|
|
180
|
+
};
|
|
181
|
+
const compare = () => {
|
|
182
|
+
const a = unary();
|
|
183
|
+
if (word(peek(), "==", "!=", "is", "eq", "neq")) {
|
|
184
|
+
const op = take().toLowerCase();
|
|
185
|
+
const b = unary();
|
|
186
|
+
// a == b is (a and b) or (not a and not b).
|
|
187
|
+
const same = { kind: "or", a: { kind: "and", a, b }, b: { kind: "and", a: { kind: "not", of: a }, b: { kind: "not", of: b } } };
|
|
188
|
+
return op === "!=" || op === "neq" ? { kind: "not", of: same } : same;
|
|
189
|
+
}
|
|
190
|
+
return a;
|
|
191
|
+
};
|
|
192
|
+
const unary = () => {
|
|
193
|
+
const t = take();
|
|
194
|
+
if (t === undefined)
|
|
195
|
+
fail(`incomplete condition "${source}"`);
|
|
196
|
+
if (word(t, "not", "!"))
|
|
197
|
+
return { kind: "not", of: unary() };
|
|
198
|
+
if (t === "(") {
|
|
199
|
+
const e = or();
|
|
200
|
+
if (take() !== ")")
|
|
201
|
+
fail(`missing ) in "${source}"`);
|
|
202
|
+
return e;
|
|
203
|
+
}
|
|
204
|
+
if (word(t, "true", "false"))
|
|
205
|
+
return { kind: "const", value: t.toLowerCase() === "true" };
|
|
206
|
+
if (t.startsWith("$"))
|
|
207
|
+
return { kind: "var", name: t.slice(1) };
|
|
208
|
+
return fail(`unexpected "${t}" in "${source}" (variables are $name; numbers and text aren't supported yet)`);
|
|
209
|
+
};
|
|
210
|
+
const e = or();
|
|
211
|
+
if (p < tokens.length)
|
|
212
|
+
fail(`unexpected "${tokens[p]}" in "${source}"`);
|
|
213
|
+
return e;
|
|
214
|
+
}
|