sci2-ts 0.15.1 → 0.16.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 +6 -0
- package/lib/993.sc +3 -1
- package/lib/995.sc +5 -1
- package/lib/996.sc +35 -6
- package/package.json +1 -1
- package/packages/sci/src/vm/kernels/graphics.d.ts +10 -0
- package/packages/sci/src/vm/kernels/graphics.js +37 -3
- package/packages/sci/src/vm/kernels/graphics.ts +34 -3
- package/tools/game/build.d.ts +3 -1
- package/tools/game/build.js +8 -4
- package/tools/game/build.ts +8 -4
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to this project. Versions follow [Semantic Versioning](https
|
|
|
4
4
|
and the entries are generated from commit messages
|
|
5
5
|
([Conventional Commits](https://www.conventionalcommits.org/)) when a release is made.
|
|
6
6
|
|
|
7
|
+
## [0.16.0](https://github.com/rlueder/sci-ts/compare/v0.15.1...v0.16.0) (2026-10-02)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
* **lib:** a lens magnifies what's under it, and portraits don't cover faces ([#19](https://github.com/rlueder/sci-ts/issues/19)) ([cc901d2](https://github.com/rlueder/sci-ts/commit/cc901d23716fad1b6466950fb77d7809f00b7f00))
|
|
12
|
+
|
|
7
13
|
## [0.15.1](https://github.com/rlueder/sci-ts/compare/v0.15.0...v0.15.1) (2026-10-02)
|
|
8
14
|
|
|
9
15
|
### Fixed
|
package/lib/993.sc
CHANGED
|
@@ -5,13 +5,15 @@
|
|
|
5
5
|
|
|
6
6
|
;; Something the hero can carry. Its view's loop 0 is its icon in the inventory window and
|
|
7
7
|
;; loop 1 the cursor while it's being used (the cel's anchor is the hotspot); both anchored
|
|
8
|
-
;; at the top-left corner.
|
|
8
|
+
;; at the top-left corner. One that magnifies (a lens) has its glass as loop 2, placed like
|
|
9
|
+
;; the cursor: while it's in use, the room shows through the glass `magnify` times larger. Using it on something sends that thing doVerb: with the item's
|
|
9
10
|
;; own verb, 10 and up, so the room answers with noun and that verb (in Yarn, a node like
|
|
10
11
|
;; filings.lens: the game names its items' verbs in items.yaml).
|
|
11
12
|
(class InvItem of Obj
|
|
12
13
|
(properties
|
|
13
14
|
view -1
|
|
14
15
|
verb 0
|
|
16
|
+
magnify 0 ; 0, or how much bigger things look through it
|
|
15
17
|
description 0) ; what looking at it in the window says
|
|
16
18
|
|
|
17
19
|
;; Looked at in the inventory window.
|
package/lib/995.sc
CHANGED
|
@@ -65,7 +65,11 @@
|
|
|
65
65
|
(if (or (!= v cursor) (!= l cursorLoop))
|
|
66
66
|
(= cursor v)
|
|
67
67
|
(= cursorLoop l)
|
|
68
|
-
(SetCursor v l 0)
|
|
68
|
+
(SetCursor v l 0)
|
|
69
|
+
(if (and (== l 1) theItem (theItem magnify?))
|
|
70
|
+
(AddMagnify v 2 0 (theItem magnify?))
|
|
71
|
+
else
|
|
72
|
+
(DeleteMagnify))))
|
|
69
73
|
|
|
70
74
|
(method (doit)
|
|
71
75
|
(self showCursor:)
|
package/lib/996.sc
CHANGED
|
@@ -233,18 +233,47 @@
|
|
|
233
233
|
(= mouth ((Prop new:) view: view yourself:))
|
|
234
234
|
(= eyes ((Prop new:) view: view yourself:))))
|
|
235
235
|
|
|
236
|
-
;; This line's side: see above.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
(= s
|
|
240
|
-
|
|
236
|
+
;; This line's side: see above. A side whose portrait would cover the speaker or the hero
|
|
237
|
+
;; (a face under the frame) gives way to the other, if that one covers no one.
|
|
238
|
+
(method (pickSide face &tmp s)
|
|
239
|
+
(= s
|
|
240
|
+
(cond
|
|
241
|
+
((== self heroTalker) (- 1 otherSide))
|
|
242
|
+
((and who ego (< (who x?) (ego x?))) 0)
|
|
243
|
+
(else 1)))
|
|
244
|
+
(if (and face (self covers: face s) (not (self covers: face (- 1 s)))) (= s (- 1 s)))
|
|
245
|
+
(if (and (!= self heroTalker) heroTalker (heroTalker respondsTo: #otherSide)) (heroTalker otherSide: s))
|
|
241
246
|
(return s))
|
|
242
247
|
|
|
248
|
+
;; Whether the portrait on side s (frame and all) would be over the speaker or the hero.
|
|
249
|
+
(method (covers face s &tmp pw ph over left right bottom)
|
|
250
|
+
(= pw (CelWide (face view?) 0 0))
|
|
251
|
+
(= ph (CelHigh (face view?) 0 0))
|
|
252
|
+
(= over (if (!= (textStyle portraitFrame?) -1) (/ (- (CelWide (textStyle portraitFrame?) 0 0) pw) 2) else 0))
|
|
253
|
+
(= left (if s (- SCREEN_WIDTH (+ (textStyle portraitX?) pw over)) else (- (textStyle portraitX?) over)))
|
|
254
|
+
(= right (+ left pw over over))
|
|
255
|
+
(= bottom (+ (textStyle portraitY?) ph over))
|
|
256
|
+
(return
|
|
257
|
+
(or
|
|
258
|
+
(self over: (if (== self heroTalker) ego else who) left right bottom)
|
|
259
|
+
(and (!= self heroTalker) (self over: ego left right bottom)))))
|
|
260
|
+
|
|
261
|
+
;; Whether someone's figure reaches into the screen's top band from left to right, down to bottom.
|
|
262
|
+
(method (over body left right bottom &tmp w h)
|
|
263
|
+
(if (or (not body) (not (body respondsTo: #view)) (& (body signal?) SIG_HIDDEN)) (return FALSE))
|
|
264
|
+
(= w (CelWide (body view?) (body loop?) (body cel?)))
|
|
265
|
+
(= h (CelHigh (body view?) (body loop?) (body cel?)))
|
|
266
|
+
(if (& (body scaleSignal?) SCALE_ON)
|
|
267
|
+
(= w (/ (* w (body scaleX?)) 128))
|
|
268
|
+
(= h (/ (* h (body scaleY?)) 128)))
|
|
269
|
+
(return
|
|
270
|
+
(and (< (- (body x?) (/ w 2)) right) (> (+ (body x?) (/ w 2)) left) (< (- (body y?) h) bottom))))
|
|
271
|
+
|
|
243
272
|
(method (say txt whoCares &tmp face l pw f fx fy over)
|
|
244
273
|
(self init: makeParts:)
|
|
245
274
|
(= face (if frame frame else bust))
|
|
246
275
|
(if face
|
|
247
|
-
(= side (self pickSide:))
|
|
276
|
+
(= side (self pickSide: face))
|
|
248
277
|
(= l (if (and side (>= (NumLoops face) 6)) 3 else 0))
|
|
249
278
|
(= pw (CelWide (face view?) l 0))
|
|
250
279
|
(= f (textStyle portraitFrame?))
|
package/package.json
CHANGED
|
@@ -56,6 +56,16 @@ export declare class Graphics {
|
|
|
56
56
|
x: number;
|
|
57
57
|
y: number;
|
|
58
58
|
};
|
|
59
|
+
/**
|
|
60
|
+
* The cursor as a magnifying glass (AddMagnify): where this cel is opaque, placed like the
|
|
61
|
+
* cursor, the screen under the cursor's hotspot shows `zoom` times larger.
|
|
62
|
+
*/
|
|
63
|
+
magnify: {
|
|
64
|
+
view: number;
|
|
65
|
+
loop: number;
|
|
66
|
+
cel: number;
|
|
67
|
+
zoom: number;
|
|
68
|
+
} | undefined;
|
|
59
69
|
/** Palette range affected by fade show styles (SetPalStyleRange). */
|
|
60
70
|
styleRange: {
|
|
61
71
|
from: number;
|
|
@@ -85,6 +85,11 @@ export class Graphics {
|
|
|
85
85
|
transitions = new Map();
|
|
86
86
|
/** The mouse cursor: a view cel drawn on top at the mouse position (its origin = hotspot). */
|
|
87
87
|
cursor = { view: -1, loop: 0, cel: 0, visible: true, x: 160, y: 100 };
|
|
88
|
+
/**
|
|
89
|
+
* The cursor as a magnifying glass (AddMagnify): where this cel is opaque, placed like the
|
|
90
|
+
* cursor, the screen under the cursor's hotspot shows `zoom` times larger.
|
|
91
|
+
*/
|
|
92
|
+
magnify;
|
|
88
93
|
/** Palette range affected by fade show styles (SetPalStyleRange). */
|
|
89
94
|
styleRange = { from: 0, to: 255 };
|
|
90
95
|
lastFrame;
|
|
@@ -218,8 +223,28 @@ export class Graphics {
|
|
|
218
223
|
for (const d of draws)
|
|
219
224
|
blit(pixels, d, clip, remap);
|
|
220
225
|
}
|
|
221
|
-
// The cursor goes on top of everything.
|
|
226
|
+
// The cursor goes on top of everything: first what a magnifier shows through its glass.
|
|
222
227
|
const cur = this.cursor;
|
|
228
|
+
const mag = this.magnify;
|
|
229
|
+
const glass = cur.visible && mag ? this.cel(mag.view, mag.loop, mag.cel) : undefined;
|
|
230
|
+
if (glass && mag) {
|
|
231
|
+
const scene = pixels.slice();
|
|
232
|
+
const o = celOrigin(glass.cel, glass.mirror);
|
|
233
|
+
const { width: w, height: h, skipColor } = glass.cel;
|
|
234
|
+
for (let gy = 0; gy < h; gy++) {
|
|
235
|
+
for (let gx = 0; gx < w; gx++) {
|
|
236
|
+
if (glass.cel.pixels[gy * w + (glass.mirror ? w - 1 - gx : gx)] === skipColor)
|
|
237
|
+
continue;
|
|
238
|
+
const x = cur.x - o.x + gx, y = cur.y - o.y + gy;
|
|
239
|
+
if (x < 0 || y < 0 || x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT)
|
|
240
|
+
continue;
|
|
241
|
+
const sx = cur.x + Math.floor((x - cur.x) / mag.zoom), sy = cur.y + Math.floor((y - cur.y) / mag.zoom);
|
|
242
|
+
if (sx < 0 || sy < 0 || sx >= SCREEN_WIDTH || sy >= SCREEN_HEIGHT)
|
|
243
|
+
continue;
|
|
244
|
+
pixels[y * SCREEN_WIDTH + x] = scene[sy * SCREEN_WIDTH + sx];
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
223
248
|
if (cur.visible && cur.view >= 0) {
|
|
224
249
|
const found = this.cel(cur.view, cur.loop, cur.cel);
|
|
225
250
|
if (found) {
|
|
@@ -467,8 +492,17 @@ export const graphicsKernels = {
|
|
|
467
492
|
HaveMouse: () => 1,
|
|
468
493
|
ShakeScreen: () => 0,
|
|
469
494
|
SetScroll: () => 0,
|
|
470
|
-
AddMagnify
|
|
471
|
-
|
|
495
|
+
// AddMagnify(view, loop, cel, zoom): sci-ts makes the cursor a magnifying glass, the cel's
|
|
496
|
+
// opaque pixels its glass (placed like the cursor), showing what's under the hotspot zoom
|
|
497
|
+
// times larger. DeleteMagnify() stops it.
|
|
498
|
+
AddMagnify: (vm, [view = 0, loop = 0, cel = 0, zoom = 2]) => {
|
|
499
|
+
graphics(vm).magnify = { view: toSigned(view), loop, cel, zoom: Math.max(1, toSigned(zoom)) };
|
|
500
|
+
return 0;
|
|
501
|
+
},
|
|
502
|
+
DeleteMagnify: (vm) => {
|
|
503
|
+
graphics(vm).magnify = undefined;
|
|
504
|
+
return 0;
|
|
505
|
+
},
|
|
472
506
|
GetHighItemPri: () => 0,
|
|
473
507
|
SetFontRes: () => 0,
|
|
474
508
|
NULL_: () => NULL,
|
|
@@ -90,6 +90,11 @@ export class Graphics {
|
|
|
90
90
|
readonly transitions = new Map<Value, Transition>();
|
|
91
91
|
/** The mouse cursor: a view cel drawn on top at the mouse position (its origin = hotspot). */
|
|
92
92
|
cursor = { view: -1, loop: 0, cel: 0, visible: true, x: 160, y: 100 };
|
|
93
|
+
/**
|
|
94
|
+
* The cursor as a magnifying glass (AddMagnify): where this cel is opaque, placed like the
|
|
95
|
+
* cursor, the screen under the cursor's hotspot shows `zoom` times larger.
|
|
96
|
+
*/
|
|
97
|
+
magnify: { view: number; loop: number; cel: number; zoom: number } | undefined;
|
|
93
98
|
/** Palette range affected by fade show styles (SetPalStyleRange). */
|
|
94
99
|
styleRange = { from: 0, to: 255 };
|
|
95
100
|
lastFrame: Frame | undefined;
|
|
@@ -224,8 +229,25 @@ export class Graphics {
|
|
|
224
229
|
}
|
|
225
230
|
for (const d of draws) blit(pixels, d, clip, remap);
|
|
226
231
|
}
|
|
227
|
-
// The cursor goes on top of everything.
|
|
232
|
+
// The cursor goes on top of everything: first what a magnifier shows through its glass.
|
|
228
233
|
const cur = this.cursor;
|
|
234
|
+
const mag = this.magnify;
|
|
235
|
+
const glass = cur.visible && mag ? this.cel(mag.view, mag.loop, mag.cel) : undefined;
|
|
236
|
+
if (glass && mag) {
|
|
237
|
+
const scene = pixels.slice();
|
|
238
|
+
const o = celOrigin(glass.cel, glass.mirror);
|
|
239
|
+
const { width: w, height: h, skipColor } = glass.cel;
|
|
240
|
+
for (let gy = 0; gy < h; gy++) {
|
|
241
|
+
for (let gx = 0; gx < w; gx++) {
|
|
242
|
+
if (glass.cel.pixels[gy * w + (glass.mirror ? w - 1 - gx : gx)] === skipColor) continue;
|
|
243
|
+
const x = cur.x - o.x + gx, y = cur.y - o.y + gy;
|
|
244
|
+
if (x < 0 || y < 0 || x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) continue;
|
|
245
|
+
const sx = cur.x + Math.floor((x - cur.x) / mag.zoom), sy = cur.y + Math.floor((y - cur.y) / mag.zoom);
|
|
246
|
+
if (sx < 0 || sy < 0 || sx >= SCREEN_WIDTH || sy >= SCREEN_HEIGHT) continue;
|
|
247
|
+
pixels[y * SCREEN_WIDTH + x] = scene[sy * SCREEN_WIDTH + sx]!;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
229
251
|
if (cur.visible && cur.view >= 0) {
|
|
230
252
|
const found = this.cel(cur.view, cur.loop, cur.cel);
|
|
231
253
|
if (found) {
|
|
@@ -501,8 +523,17 @@ export const graphicsKernels: Record<string, KernelFn> = {
|
|
|
501
523
|
HaveMouse: () => 1,
|
|
502
524
|
ShakeScreen: () => 0,
|
|
503
525
|
SetScroll: () => 0,
|
|
504
|
-
AddMagnify
|
|
505
|
-
|
|
526
|
+
// AddMagnify(view, loop, cel, zoom): sci-ts makes the cursor a magnifying glass, the cel's
|
|
527
|
+
// opaque pixels its glass (placed like the cursor), showing what's under the hotspot zoom
|
|
528
|
+
// times larger. DeleteMagnify() stops it.
|
|
529
|
+
AddMagnify: (vm, [view = 0, loop = 0, cel = 0, zoom = 2]) => {
|
|
530
|
+
graphics(vm).magnify = { view: toSigned(view), loop, cel, zoom: Math.max(1, toSigned(zoom)) };
|
|
531
|
+
return 0;
|
|
532
|
+
},
|
|
533
|
+
DeleteMagnify: (vm) => {
|
|
534
|
+
graphics(vm).magnify = undefined;
|
|
535
|
+
return 0;
|
|
536
|
+
},
|
|
506
537
|
GetHighItemPri: () => 0,
|
|
507
538
|
SetFontRes: () => 0,
|
|
508
539
|
NULL_: () => NULL,
|
package/tools/game/build.d.ts
CHANGED
|
@@ -60,12 +60,14 @@ export interface GameItem {
|
|
|
60
60
|
verb: number;
|
|
61
61
|
view?: number;
|
|
62
62
|
description?: string;
|
|
63
|
+
/** How much bigger things look through it (a lens): its view's loop 2 is the glass. */
|
|
64
|
+
magnify?: number;
|
|
63
65
|
}
|
|
64
66
|
/**
|
|
65
67
|
* items.yaml: each thing the hero can carry, by name. `lens: 10` names just its verb (10 to
|
|
66
68
|
* 255; 1 to 4 are the player's), for a game whose scripts make the item; with a view, the
|
|
67
69
|
* build makes it too, in script ITEMS_SCRIPT, and rooms can give it (`<<get lens>>`):
|
|
68
70
|
*
|
|
69
|
-
* lens: { verb: 10, view: 250, description: "Holmes's lens." }
|
|
71
|
+
* lens: { verb: 10, view: 250, description: "Holmes's lens.", magnify: 2 }
|
|
70
72
|
*/
|
|
71
73
|
export declare function gameItems(dir: string): Record<string, GameItem>;
|
package/tools/game/build.js
CHANGED
|
@@ -340,7 +340,7 @@ export async function buildGame(dir, options = {}) {
|
|
|
340
340
|
* 255; 1 to 4 are the player's), for a game whose scripts make the item; with a view, the
|
|
341
341
|
* build makes it too, in script ITEMS_SCRIPT, and rooms can give it (`<<get lens>>`):
|
|
342
342
|
*
|
|
343
|
-
* lens: { verb: 10, view: 250, description: "Holmes's lens." }
|
|
343
|
+
* lens: { verb: 10, view: 250, description: "Holmes's lens.", magnify: 2 }
|
|
344
344
|
*/
|
|
345
345
|
export function gameItems(dir) {
|
|
346
346
|
const file = join(dir, "items.yaml");
|
|
@@ -366,7 +366,7 @@ export function gameItems(dir) {
|
|
|
366
366
|
const spec = typeof value === "number" ? { verb: value } : value;
|
|
367
367
|
if (!spec || typeof spec !== "object" || Array.isArray(spec))
|
|
368
368
|
return fail(`${name}: expected a verb, or { verb, view, description }`);
|
|
369
|
-
const { verb, view, description, ...rest } = spec;
|
|
369
|
+
const { verb, view, description, magnify, ...rest } = spec;
|
|
370
370
|
const unknown = Object.keys(rest)[0];
|
|
371
371
|
if (unknown)
|
|
372
372
|
fail(`${name}: unknown key ${unknown}`);
|
|
@@ -380,7 +380,11 @@ export function gameItems(dir) {
|
|
|
380
380
|
fail(`${name}: description is text without quotes or backslashes`);
|
|
381
381
|
if (description !== undefined && view === undefined)
|
|
382
382
|
fail(`${name}: an item the build makes needs a view`);
|
|
383
|
-
|
|
383
|
+
if (magnify !== undefined && (typeof magnify !== "number" || !Number.isInteger(magnify) || magnify < 2 || magnify > 8))
|
|
384
|
+
fail(`${name}: magnify is how much bigger, 2 to 8`);
|
|
385
|
+
if (magnify !== undefined && view === undefined)
|
|
386
|
+
fail(`${name}: an item that magnifies needs a view (its loop 2 is the glass)`);
|
|
387
|
+
items[name] = { verb: verb, view: view, description: description, ...(magnify === undefined ? {} : { magnify: magnify }) };
|
|
384
388
|
}
|
|
385
389
|
return items;
|
|
386
390
|
}
|
|
@@ -394,7 +398,7 @@ function itemsScript(items) {
|
|
|
394
398
|
`(script ${ITEMS_SCRIPT})`,
|
|
395
399
|
'(include "system.sh")',
|
|
396
400
|
`(public ${made.map(([name], i) => `${name} ${i}`).join(" ")})`,
|
|
397
|
-
...made.map(([name, i]) => `(instance ${name} of InvItem (properties view ${i.view} verb ${i.verb}${i.description ? ` description "${i.description}"` : ""}))`),
|
|
401
|
+
...made.map(([name, i]) => `(instance ${name} of InvItem (properties view ${i.view} verb ${i.verb}${i.magnify ? ` magnify ${i.magnify}` : ""}${i.description ? ` description "${i.description}"` : ""}))`),
|
|
398
402
|
"",
|
|
399
403
|
].join("\n");
|
|
400
404
|
}
|
package/tools/game/build.ts
CHANGED
|
@@ -370,6 +370,8 @@ export interface GameItem {
|
|
|
370
370
|
verb: number;
|
|
371
371
|
view?: number;
|
|
372
372
|
description?: string;
|
|
373
|
+
/** How much bigger things look through it (a lens): its view's loop 2 is the glass. */
|
|
374
|
+
magnify?: number;
|
|
373
375
|
}
|
|
374
376
|
|
|
375
377
|
/**
|
|
@@ -377,7 +379,7 @@ export interface GameItem {
|
|
|
377
379
|
* 255; 1 to 4 are the player's), for a game whose scripts make the item; with a view, the
|
|
378
380
|
* build makes it too, in script ITEMS_SCRIPT, and rooms can give it (`<<get lens>>`):
|
|
379
381
|
*
|
|
380
|
-
* lens: { verb: 10, view: 250, description: "Holmes's lens." }
|
|
382
|
+
* lens: { verb: 10, view: 250, description: "Holmes's lens.", magnify: 2 }
|
|
381
383
|
*/
|
|
382
384
|
export function gameItems(dir: string): Record<string, GameItem> {
|
|
383
385
|
const file = join(dir, "items.yaml");
|
|
@@ -394,7 +396,7 @@ export function gameItems(dir: string): Record<string, GameItem> {
|
|
|
394
396
|
if (!/^[a-z][A-Za-z0-9]*$/.test(name) || ["look", "talk", "walk", "do", "enter"].includes(name)) fail(`"${name}" can't name an item (lower camelCase, and not a verb)`);
|
|
395
397
|
const spec = typeof value === "number" ? { verb: value } : value;
|
|
396
398
|
if (!spec || typeof spec !== "object" || Array.isArray(spec)) return fail(`${name}: expected a verb, or { verb, view, description }`);
|
|
397
|
-
const { verb, view, description, ...rest } = spec as Record<string, unknown>;
|
|
399
|
+
const { verb, view, description, magnify, ...rest } = spec as Record<string, unknown>;
|
|
398
400
|
const unknown = Object.keys(rest)[0];
|
|
399
401
|
if (unknown) fail(`${name}: unknown key ${unknown}`);
|
|
400
402
|
if (typeof verb !== "number" || !Number.isInteger(verb) || verb < 10 || verb > 255) fail(`${name}: the verb is a number from 10 to 255`);
|
|
@@ -402,7 +404,9 @@ export function gameItems(dir: string): Record<string, GameItem> {
|
|
|
402
404
|
if (view !== undefined && (typeof view !== "number" || !Number.isInteger(view) || view < 0 || view > 65535)) fail(`${name}: view is a view number`);
|
|
403
405
|
if (description !== undefined && (typeof description !== "string" || /["\\]/.test(description))) fail(`${name}: description is text without quotes or backslashes`);
|
|
404
406
|
if (description !== undefined && view === undefined) fail(`${name}: an item the build makes needs a view`);
|
|
405
|
-
|
|
407
|
+
if (magnify !== undefined && (typeof magnify !== "number" || !Number.isInteger(magnify) || magnify < 2 || magnify > 8)) fail(`${name}: magnify is how much bigger, 2 to 8`);
|
|
408
|
+
if (magnify !== undefined && view === undefined) fail(`${name}: an item that magnifies needs a view (its loop 2 is the glass)`);
|
|
409
|
+
items[name] = { verb: verb as number, view: view as number | undefined, description: description as string | undefined, ...(magnify === undefined ? {} : { magnify: magnify as number }) };
|
|
406
410
|
}
|
|
407
411
|
return items;
|
|
408
412
|
}
|
|
@@ -416,7 +420,7 @@ function itemsScript(items: Record<string, GameItem>): string | undefined {
|
|
|
416
420
|
`(script ${ITEMS_SCRIPT})`,
|
|
417
421
|
'(include "system.sh")',
|
|
418
422
|
`(public ${made.map(([name], i) => `${name} ${i}`).join(" ")})`,
|
|
419
|
-
...made.map(([name, i]) => `(instance ${name} of InvItem (properties view ${i.view} verb ${i.verb}${i.description ? ` description "${i.description}"` : ""}))`),
|
|
423
|
+
...made.map(([name, i]) => `(instance ${name} of InvItem (properties view ${i.view} verb ${i.verb}${i.magnify ? ` magnify ${i.magnify}` : ""}${i.description ? ` description "${i.description}"` : ""}))`),
|
|
420
424
|
"",
|
|
421
425
|
].join("\n");
|
|
422
426
|
}
|