sci2-ts 0.17.0 → 0.18.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/992.sc +5 -1
- package/lib/995.sc +3 -2
- package/lib/996.sc +221 -46
- package/lib/system.sh +8 -0
- package/package.json +1 -1
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.18.0](https://github.com/rlueder/sci-ts/compare/v0.17.0...v0.18.0) (2026-10-03)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
* **lib:** painted game menu with lit rows, arrow keys, Escape and unavailable choices ([#21](https://github.com/rlueder/sci-ts/issues/21)) ([17dfd28](https://github.com/rlueder/sci-ts/commit/17dfd28c0f16379714a058869b7b698dc5338344))
|
|
12
|
+
|
|
7
13
|
## [0.17.0](https://github.com/rlueder/sci-ts/compare/v0.16.0...v0.17.0) (2026-10-02)
|
|
8
14
|
|
|
9
15
|
### Added
|
package/lib/992.sc
CHANGED
|
@@ -51,14 +51,18 @@
|
|
|
51
51
|
field 0 ; the description being typed
|
|
52
52
|
slot 0) ; the save it goes into
|
|
53
53
|
|
|
54
|
+
;; Painted with the textStyle's menuSkin, if it has one; Restore is unavailable there until
|
|
55
|
+
;; there's a save.
|
|
54
56
|
(method (showMenu &tmp menu)
|
|
55
57
|
(= mode SR_MENU)
|
|
56
|
-
(
|
|
58
|
+
(self load:)
|
|
59
|
+
(= menu ((Menu new:) painted: TRUE yourself:))
|
|
57
60
|
(menu
|
|
58
61
|
add: SR_SAVE "Save the game"
|
|
59
62
|
add: SR_RESTORE "Restore a game"
|
|
60
63
|
add: SR_RESTART "Start again"
|
|
61
64
|
add: SR_TEXT (String STRING_FORMAT "Text speed: %s" (self textSpeedName:)))
|
|
65
|
+
(if (not count) ((menu valued: SR_RESTORE) disabled: TRUE))
|
|
62
66
|
;; Only a game with recorded lines asks how to have them.
|
|
63
67
|
(if (DoAudio 9)
|
|
64
68
|
(menu add: SR_SPEECH (String STRING_FORMAT "Speech: %s" (self speechName:))))
|
package/lib/995.sc
CHANGED
|
@@ -76,9 +76,10 @@
|
|
|
76
76
|
(if (and iconBar (iconBar box?)) (iconBar step:))
|
|
77
77
|
(while (GetEvent EV_ALL theEvent)
|
|
78
78
|
(self handleEvent: theEvent))
|
|
79
|
-
;; theEvent now says where the pointer is:
|
|
79
|
+
;; theEvent now says where the pointer is: an open menu or the icon bar follows it, and at
|
|
80
|
+
;; the top edge the icon bar comes down.
|
|
80
81
|
(cond
|
|
81
|
-
((
|
|
82
|
+
((and dialog (dialog respondsTo: #pointerAt)) (dialog pointerAt: (theEvent x?) (theEvent y?)))
|
|
82
83
|
((and canInput (not dialog) (not talking) (<= (theEvent y?) ICON_BAR_EDGE)) (iconBar show:))))
|
|
83
84
|
|
|
84
85
|
;; The verb right-click goes to: walk, do, look, talk, the item picked (if any), walk.
|
package/lib/996.sc
CHANGED
|
@@ -10,6 +10,14 @@
|
|
|
10
10
|
;; A frame is a view whose loop 0 has eight cels, each anchored at its top-left corner: the
|
|
11
11
|
;; corners (top-left, top-right, bottom-left, bottom-right), then the edges (top, bottom, left,
|
|
12
12
|
;; right). The edges are tiled between the corners; transparent pixels show the paper.
|
|
13
|
+
;;
|
|
14
|
+
;; The game menu can be painted instead (the casebook, say): `menuSkin` is a view whose loop
|
|
15
|
+
;; 0, cel 0 is the panel, its title painted in, loop 1 the row behind a choice and loop 2 the
|
|
16
|
+
;; bullet before it, each with a cel for a choice as it is, under the pointer or keyboard
|
|
17
|
+
;; focus, pressed and unavailable; all anchored at their top-left corners. The panel goes at
|
|
18
|
+
;; menuX, menuY (-1: centred), the rows from menuRowX, menuRowY down by menuRowStep, the
|
|
19
|
+
;; bullet and the text at their offsets in the row. The text is in the four menu colours.
|
|
20
|
+
;; (textStyle menuSkin: 269 menuX: 38 menuY: 11 menuRowX: 10 menuRowY: 29 menuRowStep: 22)
|
|
13
21
|
(class TextStyle of Obj
|
|
14
22
|
(properties
|
|
15
23
|
font 0
|
|
@@ -21,7 +29,16 @@
|
|
|
21
29
|
portraitFrame -1 ; a view around portraits: loop 0 behind the face, loop 1 over its edges
|
|
22
30
|
portraitX 8 ; where a portrait's face goes on the left (mirrored on the right)
|
|
23
31
|
portraitY 8 ; its top; below 0, its bottom that far above the screen's, its text with it
|
|
24
|
-
nameFont -1
|
|
32
|
+
nameFont -1 ; the font for a speaker's name before their line (-1: the text's)
|
|
33
|
+
menuSkin -1 ; the game menu's painted panel, rows and bullets, or -1 (above)
|
|
34
|
+
menuX -1 menuY -1
|
|
35
|
+
menuRowX 10 menuRowY 29 menuRowStep 22
|
|
36
|
+
menuBulletX 5 menuBulletY 5
|
|
37
|
+
menuTextX 25 menuTextY 4
|
|
38
|
+
menuFore -1 ; the text of a choice, under the pointer, pressed, unavailable (-1: fore)
|
|
39
|
+
menuHover -1
|
|
40
|
+
menuPressed -1
|
|
41
|
+
menuDisabled -1))
|
|
25
42
|
|
|
26
43
|
;; A box of text over the room: drawn by the interpreter into a bitmap, shown as a screen
|
|
27
44
|
;; item in the UI plane. Set text (and width, x, y), then init; it's as tall as the text
|
|
@@ -44,6 +61,7 @@
|
|
|
44
61
|
borderColor -2 ; -1: none
|
|
45
62
|
frame -2 ; -1: none
|
|
46
63
|
textLeft 0 textTop 0 textRight -1 textBottom -1
|
|
64
|
+
margin -1 ; between the text and the edge, or the frame (-1: the textStyle's)
|
|
47
65
|
width 200
|
|
48
66
|
height 0
|
|
49
67
|
bottom -1) ; -1: placed at y
|
|
@@ -55,7 +73,7 @@
|
|
|
55
73
|
(if (== frame -2) (= frame (textStyle frame?)))
|
|
56
74
|
(if (== borderColor -2) (= borderColor (if (!= frame -1) -1 else (textStyle border?))))
|
|
57
75
|
;; As tall as the text needs, inside the margin and the frame.
|
|
58
|
-
(= m (textStyle margin?))
|
|
76
|
+
(= m (if (== margin -1) (textStyle margin?) else margin))
|
|
59
77
|
(= padL m) (= padT m) (= padR m) (= padB m)
|
|
60
78
|
(if (!= frame -1)
|
|
61
79
|
(+= padL (CelWide frame 0 6))
|
|
@@ -389,19 +407,57 @@
|
|
|
389
407
|
(method (cue)
|
|
390
408
|
(self sayNext:)))
|
|
391
409
|
|
|
392
|
-
;; One choice in a Menu.
|
|
410
|
+
;; One choice in a Menu. In a painted menu it has a row and a bullet behind it, and is in one
|
|
411
|
+
;; of the skin's states (MENU_NORMAL, MENU_HOVER, MENU_PRESSED, MENU_DISABLED).
|
|
393
412
|
(class MenuItem of TextItem
|
|
394
413
|
(properties
|
|
395
|
-
value 0
|
|
414
|
+
value 0
|
|
415
|
+
disabled 0 ; can't be chosen: shown unavailable in a painted menu (a plain one ignores it)
|
|
416
|
+
row 0
|
|
417
|
+
bullet 0
|
|
418
|
+
state -1)
|
|
419
|
+
|
|
420
|
+
;; Anywhere on its row, if it has one.
|
|
421
|
+
(method (onMe theX theY &tmp v)
|
|
422
|
+
(if (not row) (return (super onMe: theX theY)))
|
|
423
|
+
(= v (row view?))
|
|
424
|
+
(return
|
|
425
|
+
(and (>= theX (row x?)) (< theX (+ (row x?) (CelWide v 1 0)))
|
|
426
|
+
(>= theY (row y?)) (< theY (+ (row y?) (CelHigh v 1 0))))))
|
|
427
|
+
|
|
428
|
+
;; Its row, bullet and text as they look in state st.
|
|
429
|
+
(method (setState st &tmp c)
|
|
430
|
+
(if (or (not row) (== st state)) (return))
|
|
431
|
+
(= state st)
|
|
432
|
+
(row setCel: st)
|
|
433
|
+
(bullet setCel: st)
|
|
434
|
+
(= c
|
|
435
|
+
(switch st
|
|
436
|
+
(MENU_HOVER (textStyle menuHover?))
|
|
437
|
+
(MENU_PRESSED (textStyle menuPressed?))
|
|
438
|
+
(MENU_DISABLED (textStyle menuDisabled?))
|
|
439
|
+
(else (textStyle menuFore?))))
|
|
440
|
+
(= fore (if (== c -1) (textStyle fore?) else c))
|
|
441
|
+
(if bitmap
|
|
442
|
+
(Bitmap BITMAP_DISPOSE bitmap)
|
|
443
|
+
(= bitmap (CreateTextBitmap 0 width height self))
|
|
444
|
+
(UpdateScreenItem self)))
|
|
396
445
|
|
|
397
446
|
(method (dispose)
|
|
447
|
+
(if row (row dispose:) (= row 0))
|
|
448
|
+
(if bullet (bullet dispose:) (= bullet 0))
|
|
398
449
|
;; Its text was made for it (a literal string is left alone).
|
|
399
450
|
(String ARRAY_FREE text)
|
|
400
451
|
(super dispose:)))
|
|
401
452
|
|
|
402
|
-
;; Choices one under another in a box (the textStyle's frame around them all);
|
|
403
|
-
;;
|
|
404
|
-
;; hears the choice by `choose: value`.
|
|
453
|
+
;; Choices one under another in a box (the textStyle's frame around them all); a click on one
|
|
454
|
+
;; ends it, and Escape chooses the one worth 0 (Cancel, Carry on, Goodbye). While it's open it
|
|
455
|
+
;; gets every event (it's the `dialog`). The caller hears the choice by `choose: value`.
|
|
456
|
+
;;
|
|
457
|
+
;; A `painted` menu is drawn with the textStyle's menuSkin instead, if it has one and the
|
|
458
|
+
;; choices fit on its panel: each on its row, lit under the pointer, pressed while the button
|
|
459
|
+
;; is down; the arrow keys move between them and Enter or Space chooses, and an unavailable
|
|
460
|
+
;; one is passed over.
|
|
405
461
|
(class Menu of Obj
|
|
406
462
|
(properties
|
|
407
463
|
items 0
|
|
@@ -409,56 +465,175 @@
|
|
|
409
465
|
panel 0
|
|
410
466
|
y 20 ; the top of the box
|
|
411
467
|
width 240
|
|
412
|
-
next 0
|
|
468
|
+
next 0 ; where the next choice goes
|
|
469
|
+
painted 0 ; drawn with the textStyle's menuSkin, if it fits
|
|
470
|
+
skin -1 ; the skin it's drawn with, or -1
|
|
471
|
+
focus 0 ; the choice that's lit
|
|
472
|
+
pressed 0 ; the choice the button went down on
|
|
473
|
+
pointerX -1 pointerY -1)
|
|
474
|
+
|
|
475
|
+
(method (add v txt &tmp item)
|
|
476
|
+
(if (not items) (= items (List new:)))
|
|
477
|
+
(= item ((MenuItem new:) value: v text: txt yourself:))
|
|
478
|
+
(items add: item)
|
|
479
|
+
(return self))
|
|
413
480
|
|
|
414
|
-
|
|
481
|
+
;; The choices on their box, then it waits for one.
|
|
482
|
+
(method (show whoCares &tmp s)
|
|
483
|
+
(= caller whoCares)
|
|
484
|
+
(if (not items) (return))
|
|
485
|
+
(= s (textStyle menuSkin?))
|
|
486
|
+
(if (and painted (!= s -1)
|
|
487
|
+
(<= (+ (textStyle menuRowY?) (* (items size?) (textStyle menuRowStep?))) (CelHigh s 0 0)))
|
|
488
|
+
(= skin s)
|
|
489
|
+
(self showPainted:)
|
|
490
|
+
else
|
|
491
|
+
(self showPlain:))
|
|
492
|
+
(= dialog self))
|
|
493
|
+
|
|
494
|
+
(method (showPlain &tmp f node item)
|
|
415
495
|
(= f (textStyle frame?))
|
|
416
|
-
(if (
|
|
417
|
-
|
|
418
|
-
(=
|
|
419
|
-
|
|
420
|
-
((MenuItem new:)
|
|
421
|
-
value: v
|
|
422
|
-
text: txt
|
|
496
|
+
(= next (+ y (if (!= f -1) (CelHigh f 0 4) else 1)))
|
|
497
|
+
(for ((= node (FirstNode (items elements?)))) node ((= node (NextNode node)))
|
|
498
|
+
(= item (NodeValue node))
|
|
499
|
+
(item
|
|
423
500
|
frame: -1
|
|
424
501
|
borderColor: -1
|
|
425
502
|
width: (- width (if (!= f -1) (+ (CelWide f 0 6) (CelWide f 0 7)) else 2))
|
|
426
503
|
x: (+ (/ (- SCREEN_WIDTH width) 2) (if (!= f -1) (CelWide f 0 6) else 1))
|
|
427
504
|
y: next
|
|
505
|
+
disabled: 0)
|
|
506
|
+
(item init:)
|
|
507
|
+
(+= next (item height?)))
|
|
508
|
+
(= panel
|
|
509
|
+
((TextItem new:)
|
|
510
|
+
text: ""
|
|
511
|
+
x: (/ (- SCREEN_WIDTH width) 2)
|
|
512
|
+
y: y
|
|
513
|
+
width: width
|
|
514
|
+
height: (+ (- next y) (if (!= f -1) (CelHigh f 0 5) else 1))
|
|
515
|
+
priority: 99
|
|
428
516
|
yourself:))
|
|
429
|
-
(
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
(
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
(=
|
|
437
|
-
(=
|
|
438
|
-
|
|
439
|
-
(
|
|
440
|
-
(
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
517
|
+
(panel init:))
|
|
518
|
+
|
|
519
|
+
(method (showPainted &tmp px py rx ry node item)
|
|
520
|
+
(= px (if (== (textStyle menuX?) -1) (/ (- SCREEN_WIDTH (CelWide skin 0 0)) 2) else (textStyle menuX?)))
|
|
521
|
+
(= py (if (== (textStyle menuY?) -1) (/ (- SCREEN_HEIGHT (CelHigh skin 0 0)) 2) else (textStyle menuY?)))
|
|
522
|
+
(= panel (self part: 0 0 px py 99))
|
|
523
|
+
(= rx (+ px (textStyle menuRowX?)))
|
|
524
|
+
(= ry (+ py (textStyle menuRowY?)))
|
|
525
|
+
(for ((= node (FirstNode (items elements?)))) node ((= node (NextNode node)))
|
|
526
|
+
(= item (NodeValue node))
|
|
527
|
+
(item
|
|
528
|
+
row: (self part: 1 0 rx ry 100)
|
|
529
|
+
bullet: (self part: 2 0 (+ rx (textStyle menuBulletX?)) (+ ry (textStyle menuBulletY?)) 101)
|
|
530
|
+
frame: -1
|
|
531
|
+
borderColor: -1
|
|
532
|
+
margin: 0
|
|
533
|
+
back: 254
|
|
534
|
+
x: (+ rx (textStyle menuTextX?))
|
|
535
|
+
y: (+ ry (textStyle menuTextY?))
|
|
536
|
+
width: (- (CelWide skin 1 0) (textStyle menuTextX?))
|
|
537
|
+
height: (- (CelHigh skin 1 0) (textStyle menuTextY?))
|
|
538
|
+
priority: 102)
|
|
539
|
+
(item setState: (if (item disabled?) MENU_DISABLED else MENU_NORMAL))
|
|
540
|
+
(item init:)
|
|
541
|
+
(+= ry (textStyle menuRowStep?))))
|
|
542
|
+
|
|
543
|
+
;; A cel of the skin on the screen, over the room whether or not there is one.
|
|
544
|
+
(method (part l c theX theY pri &tmp p)
|
|
545
|
+
(= p
|
|
546
|
+
((View new:)
|
|
547
|
+
view: skin loop: l cel: c x: theX y: theY
|
|
548
|
+
plane: uiPlane priority: pri fixPriority: 1
|
|
549
|
+
yourself:))
|
|
550
|
+
(cast add: p)
|
|
551
|
+
(AddScreenItem p)
|
|
552
|
+
(return p))
|
|
553
|
+
|
|
554
|
+
;; Lights choice it (0: none), and only it.
|
|
555
|
+
(method (light it &tmp node item)
|
|
556
|
+
(= focus it)
|
|
557
|
+
(for ((= node (FirstNode (items elements?)))) node ((= node (NextNode node)))
|
|
558
|
+
(= item (NodeValue node))
|
|
559
|
+
(item setState:
|
|
560
|
+
(cond
|
|
561
|
+
((item disabled?) MENU_DISABLED)
|
|
562
|
+
((and (== item pressed) (== item it)) MENU_PRESSED)
|
|
563
|
+
((== item it) MENU_HOVER)
|
|
564
|
+
(else MENU_NORMAL)))))
|
|
565
|
+
|
|
566
|
+
;; The User says where the pointer is each cycle: when it moves, what's under it is lit.
|
|
567
|
+
(method (pointerAt theX theY &tmp item)
|
|
568
|
+
(if (or (== skin -1) (and (== theX pointerX) (== theY pointerY))) (return))
|
|
569
|
+
(= pointerX theX)
|
|
570
|
+
(= pointerY theY)
|
|
571
|
+
(= item (items firstTrue: #onMe theX theY))
|
|
572
|
+
(if (and item (item disabled?)) (= item 0))
|
|
573
|
+
(if (!= item focus) (self light: item)))
|
|
574
|
+
|
|
575
|
+
;; The i-th choice, from 0.
|
|
576
|
+
(method (nth i &tmp node)
|
|
577
|
+
(for ((= node (FirstNode (items elements?)))) (and node i) ((= node (NextNode node)))
|
|
578
|
+
(-- i))
|
|
579
|
+
(return (if node (NodeValue node) else 0)))
|
|
580
|
+
|
|
581
|
+
;; The choice worth v, or 0.
|
|
582
|
+
(method (valued v &tmp node)
|
|
583
|
+
(for ((= node (FirstNode (items elements?)))) node ((= node (NextNode node)))
|
|
584
|
+
(if (== ((NodeValue node) value?) v) (return (NodeValue node))))
|
|
585
|
+
(return 0))
|
|
586
|
+
|
|
587
|
+
;; Lights the next choice that's available, dir 1 down or -1 up, round from the end.
|
|
588
|
+
(method (step dir &tmp i n k node item)
|
|
589
|
+
(= n (items size?))
|
|
590
|
+
(= i (if (> dir 0) -1 else n))
|
|
591
|
+
(= k 0)
|
|
592
|
+
(for ((= node (FirstNode (items elements?)))) node ((= node (NextNode node)))
|
|
593
|
+
(if (== (NodeValue node) focus) (= i k))
|
|
594
|
+
(++ k))
|
|
595
|
+
(for ((= k 0)) (< k n) ((++ k))
|
|
596
|
+
(= i (mod (+ i dir n) n))
|
|
597
|
+
(= item (self nth: i))
|
|
598
|
+
(if (not (item disabled?))
|
|
599
|
+
(self light: item)
|
|
600
|
+
(return))))
|
|
601
|
+
|
|
602
|
+
(method (handleEvent event &tmp item)
|
|
452
603
|
(event claimed: TRUE)
|
|
453
|
-
(
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
604
|
+
(switch (event type?)
|
|
605
|
+
(EV_KEY_DOWN
|
|
606
|
+
(switch (event message?)
|
|
607
|
+
(KEY_ESCAPE (self pick: (self valued: 0)))
|
|
608
|
+
(KEY_UP (if (!= skin -1) (self step: -1)))
|
|
609
|
+
(KEY_DOWN (if (!= skin -1) (self step: 1)))
|
|
610
|
+
(KEY_ENTER (if focus (self pick: focus)))
|
|
611
|
+
(KEY_SPACE (if focus (self pick: focus)))))
|
|
612
|
+
(EV_MOUSE_DOWN
|
|
613
|
+
(= item (items firstTrue: #onMe (event x?) (event y?)))
|
|
614
|
+
(cond
|
|
615
|
+
((== skin -1) (self pick: item))
|
|
616
|
+
((and item (not (item disabled?)))
|
|
617
|
+
(= pressed item)
|
|
618
|
+
(self light: item))))
|
|
619
|
+
(EV_MOUSE_UP
|
|
620
|
+
(if pressed
|
|
621
|
+
(= item (items firstTrue: #onMe (event x?) (event y?)))
|
|
622
|
+
(if (== item pressed)
|
|
623
|
+
(self pick: item)
|
|
624
|
+
else
|
|
625
|
+
(= pressed 0)
|
|
626
|
+
(self light: (if (and item (not (item disabled?))) item else 0))))))
|
|
460
627
|
(return TRUE))
|
|
461
628
|
|
|
629
|
+
;; Ends it with that choice (none: it stays open).
|
|
630
|
+
(method (pick item &tmp v c)
|
|
631
|
+
(if (or (not item) (item disabled?)) (return))
|
|
632
|
+
(= v (item value?))
|
|
633
|
+
(= c caller)
|
|
634
|
+
(self dispose:)
|
|
635
|
+
(c choose: v))
|
|
636
|
+
|
|
462
637
|
;; Closed without a choice.
|
|
463
638
|
(method (dismiss)
|
|
464
639
|
(self dispose:))
|
package/lib/system.sh
CHANGED
|
@@ -39,6 +39,12 @@
|
|
|
39
39
|
|
|
40
40
|
(define SAVE_DESCRIPTION 36)
|
|
41
41
|
(define SAVES_SHOWN 8)
|
|
42
|
+
;; A painted menu choice's look: the cels of the skin's row and bullet loops.
|
|
43
|
+
(define MENU_NORMAL 0)
|
|
44
|
+
(define MENU_HOVER 1)
|
|
45
|
+
(define MENU_PRESSED 2)
|
|
46
|
+
(define MENU_DISABLED 3)
|
|
47
|
+
|
|
42
48
|
(define SR_MENU 1)
|
|
43
49
|
(define SR_SAVE 2)
|
|
44
50
|
(define SR_RESTORE 3)
|
|
@@ -74,6 +80,8 @@
|
|
|
74
80
|
(define KEY_SPACE 32)
|
|
75
81
|
(define KEY_PERIOD 46)
|
|
76
82
|
(define KEY_ESCAPE 27)
|
|
83
|
+
(define KEY_UP $4800)
|
|
84
|
+
(define KEY_DOWN $5000)
|
|
77
85
|
(define KEY_F5 $3f00)
|
|
78
86
|
(define KEY_F7 $4100)
|
|
79
87
|
(define KEY_I 73)
|