##// END OF EJS Templates
Special variables and locations
naryl -
r32:f0801da6 default
parent child Browse files
Show More
@@ -1,16 +1,17 b''
1
1
2 * Special locations
2 * Special locations
3 * Special variables
3 * Special variables
4 * IMG
4 * CLI build for Linux
5 * CLI build for Linux
5 * CLI build for Windows
6 * CLI build for Windows
6
7
7 * Reporting error lines in the parser
8 * Reporting error lines in the parser
8 * Report duplicate label (in the parser)
9 * Report duplicate label (in the parser)
9 * reporting error lines at runtime (by storing them in every form in the parser
10 * reporting error lines at runtime (by storing them in every form in the parser
10 * Report JUMP with missing label (in tagbody)
11 * Report JUMP with missing label (in tagbody)
11
12
12 * Build Istreblenie
13 * Build Istreblenie
13 * Build Цветохимия
14 * Build Цветохимия
14 * Windows GUI (for the compiler)
15 * Windows GUI (for the compiler)
15 * Save-load game in slots
16 * Save-load game in slots
16 * Resizable frames
17 * Resizable frames
@@ -1,23 +1,26 b''
1
1
2 <div id="qsp">
2 <div id="qsp">
3 <div class="qsp-col qsp-col1">
3 <div class="qsp-col qsp-col1">
4 <div id="qsp-main" class="qsp-frame">&nbsp;</div>
4 <div id="qsp-main" class="qsp-frame">&nbsp;</div>
5 <div id="qsp-acts" class="qsp-frame">&nbsp;</div>
5 <div id="qsp-acts" class="qsp-frame">&nbsp;</div>
6 <input id="qsp-input" class="qsp-frame">
6 <input id="qsp-input" class="qsp-frame">
7 </div>
7 </div>
8 <div class="qsp-col qsp-col2">
8 <div class="qsp-col qsp-col2">
9 <div id="qsp-stat" class="qsp-frame">&nbsp;</div>
9 <div id="qsp-stat" class="qsp-frame">&nbsp;</div>
10 <div id="qsp-objs" class="qsp-frame">&nbsp;</div>
10 <div id="qsp-objs" class="qsp-frame">&nbsp;</div>
11 </div>
11 </div>
12 <div class="qsp-col qsp-col3">
12 <div class="qsp-col qsp-col3">
13 <a id="qsp-btn-save"><img></a>
13 <a id="qsp-btn-save"><img></a>
14 <a id="qsp-btn-open"><img></a>
14 <a id="qsp-btn-open"><img></a>
15 </div>
15 </div>
16 </div>
16 </div>
17
17
18 <div id="qsp-dropdown">
18 <div id="qsp-dropdown">
19 </div>
19 </div>
20
20
21 <div id="qsp-image-container" class="center-on-screen">
21 <div id="qsp-image-container" class="center-on-screen">
22 <img id="qsp-image">
22 <img id="qsp-image">
23 </div>
23 </div>
24
25 <style id="qsp-style">
26 </style>
@@ -1,129 +1,132 b''
1
1
2 .qsp-frame {
2 .qsp-frame {
3 border: 1px solid black;
3 border: 1px solid black;
4 overflow: auto;
4 overflow: auto;
5 padding: 5px;
5 padding: 5px;
6 box-sizing: border-box;
6 box-sizing: border-box;
7 }
7 }
8
8
9 #qsp {
9 #qsp {
10 position: absolute;
10 position: absolute;
11 display: flex;
11 display: flex;
12 flex-flow: row;
12 flex-flow: row;
13 top: 0;
13 top: 0;
14 left: 0;
14 left: 0;
15 width: 100%;
15 width: 100%;
16 height: 100%;
16 height: 100%;
17 }
17 }
18
18
19 .qsp-col {
19 .qsp-col {
20 display: flex;
20 display: flex;
21 flex-flow: column;
21 flex-flow: column;
22 }
22 }
23
23
24 .qsp-col1 {
24 .qsp-col1 {
25 flex: 7 7 70px;
25 flex: 7 7 70px;
26 }
26 }
27
27
28 .qsp-col2 {
28 .qsp-col2 {
29 flex: 3 3 30px;
29 flex: 3 3 30px;
30 }
30 }
31
31
32 .qsp-col3 {
32 .qsp-col3 {
33 flex: 0 0 40px;
33 flex: 0 0 40px;
34 }
34 }
35
35
36 #qsp-main {
36 #qsp-main {
37 flex: 6 6 60px;
37 flex: 6 6 60px;
38 background-repeat: no-repeat;
39 background-position: right top;
40 background-attachment: fixed;
38 }
41 }
39
42
40 #qsp-acts {
43 #qsp-acts {
41 flex: 4 4 40px;
44 flex: 4 4 40px;
42 }
45 }
43
46
44 #qsp-input {
47 #qsp-input {
45 }
48 }
46
49
47 #qsp-stat {
50 #qsp-stat {
48 flex: 5 5 50px;
51 flex: 5 5 50px;
49 }
52 }
50
53
51 #qsp-objs {
54 #qsp-objs {
52 flex: 5 5 50px;
55 flex: 5 5 50px;
53 }
56 }
54
57
55 .qsp-act {
58 .qsp-act {
56 display: block;
59 display: block;
57 padding: 2px;
60 padding: 2px;
58 font-size: large;
61 font-size: large;
59 }
62 }
60
63
61 .qsp-act:hover {
64 .qsp-act:hover {
62 outline: #9E9E9E outset 3px
65 outline: #9E9E9E outset 3px
63 }
66 }
64
67
65 /* Dropdown */
68 /* Dropdown */
66
69
67 #qsp-dropdown {
70 #qsp-dropdown {
68 display: none;
71 display: none;
69 position: absolute;
72 position: absolute;
70 background-color: #f1f1f1;
73 background-color: #f1f1f1;
71 min-width: 160px;
74 min-width: 160px;
72 overflow: auto;
75 overflow: auto;
73 box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
76 box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
74 z-index: 1;
77 z-index: 1;
75 margin: auto;
78 margin: auto;
76 }
79 }
77
80
78 #qsp-dropdown a {
81 #qsp-dropdown a {
79 color: black;
82 color: black;
80 padding: 12px 16px;
83 padding: 12px 16px;
81 text-decoration: none;
84 text-decoration: none;
82 display: block;
85 display: block;
83 }
86 }
84
87
85 #qsp-dropdown a:hover {
88 #qsp-dropdown a:hover {
86 background-color: #ddd;
89 background-color: #ddd;
87 }
90 }
88
91
89 /* Buttons */
92 /* Buttons */
90
93
91 .qsp-col3 a, .qsp-col3 img {
94 .qsp-col3 a, .qsp-col3 img {
92 width: 50px;
95 width: 50px;
93 height: 50px;
96 height: 50px;
94 }
97 }
95
98
96 #qsp-btn-save img {
99 #qsp-btn-save img {
97 background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAACSklEQVRoge3ZPWgUQRjG8V/iRRFU/GoEQdSohSgWWqQSooVgK9iJFiKCnYV2BkFQsBRBQQwWVsHKIoWxEOzEwmhhogbRMhhFicTvYm+JCUlmZzabRLN/OPaWeZ+ZeW7feXf2lpqampqamnRaImKP4hA2VjCP27hbpoNGwbib2IPreB+IPYY7M7SvxWYM4QNO4QqWyQxVRgdeYnnB+K5A+wUcbB7z+O14hxPx08toLRDTgfv4mjrIJFrwwMS0HsABXMTxlE6LpNYqfE7pPJIBdOKhLM1uxIiLrpG5YtC4GSLMVGGkLdD+GpfxAuvxaVL7oCzN+jCG7iKDVmHkKS5hSSBuJ3bg6hRt+Zrpa553z8bEuoQrUVXk1exwKLBI1ZpPBnAL+0KBqanVim1Ykaifji+yNfIrVphipB1n8BgjCfqZ2IrTuIZXMcIUIydxFj8TtEW4JysW52JEKWtkVHUm4EdzjChSrkgLlmJXghb6m8ep9MN4K25XjvTF3sCaElrT6McS+0w2Mirb+JWhrH4CC/0+UpjUK7Ia5/86f4IeHMHeEvPJ+4km1chHE43k9KROpCyLPrViym8/vjW/b5Jt3acjL7/RzEX5bRg3sjKg+2fK7/PmZ9aZzdTqxwYzp06IBZFaDeHUCbFgUquy1Anx35TfRWXkd+WzCBOcQxEjQ7JH0PmiHW9CQUWM9Mr+Y+osO6ME8nF7Q4FFn8T2y14VDMt2vsFfqCRbZBvTdbLXFI9CgphHyjbsVu4+EcMInuH7HI1XU1NTU7OI+QMFe2N82rtssgAAAABJRU5ErkJggg==');
100 background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAACSklEQVRoge3ZPWgUQRjG8V/iRRFU/GoEQdSohSgWWqQSooVgK9iJFiKCnYV2BkFQsBRBQQwWVsHKIoWxEOzEwmhhogbRMhhFicTvYm+JCUlmZzabRLN/OPaWeZ+ZeW7feXf2lpqampqamnRaImKP4hA2VjCP27hbpoNGwbib2IPreB+IPYY7M7SvxWYM4QNO4QqWyQxVRgdeYnnB+K5A+wUcbB7z+O14hxPx08toLRDTgfv4mjrIJFrwwMS0HsABXMTxlE6LpNYqfE7pPJIBdOKhLM1uxIiLrpG5YtC4GSLMVGGkLdD+GpfxAuvxaVL7oCzN+jCG7iKDVmHkKS5hSSBuJ3bg6hRt+Zrpa553z8bEuoQrUVXk1exwKLBI1ZpPBnAL+0KBqanVim1Ykaifji+yNfIrVphipB1n8BgjCfqZ2IrTuIZXMcIUIydxFj8TtEW4JysW52JEKWtkVHUm4EdzjChSrkgLlmJXghb6m8ep9MN4K25XjvTF3sCaElrT6McS+0w2Mirb+JWhrH4CC/0+UpjUK7Ia5/86f4IeHMHeEvPJ+4km1chHE43k9KROpCyLPrViym8/vjW/b5Jt3acjL7/RzEX5bRg3sjKg+2fK7/PmZ9aZzdTqxwYzp06IBZFaDeHUCbFgUquy1Anx35TfRWXkd+WzCBOcQxEjQ7JH0PmiHW9CQUWM9Mr+Y+osO6ME8nF7Q4FFn8T2y14VDMt2vsFfqCRbZBvTdbLXFI9CgphHyjbsVu4+EcMInuH7HI1XU1NTU7OI+QMFe2N82rtssgAAAABJRU5ErkJggg==');
98 }
101 }
99
102
100 #qsp-btn-open img {
103 #qsp-btn-open img {
101 background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAACCklEQVRoge3Yz6sNYRzH8deVexNxSaEoroWFUuomOceSPVnIwsbSxs6Psrgphf9AsrZR7kJWsroUlrZKKZRSl4USGouZk9Npzp1n5pm5x4/nXdNzpvP9Pp/v95nv82OGRCKRSCQS/w8zuIn3yGpe37CEQ6sedQk38BA7G/jO4BQ+YEebQZUxVfH/OxzGVSxX2D4o2mO4jmt4jpNFe6d5mPFkRbvQ0H9h6OqUtR33/xXr0celGn4/sYjXoQ5dJ3ILB7AOW2r4bcIj7GsrkEFpXWyrwwbaf15nXWqv6SqK1abuHDmPjV0EMobhBWIZt8cZVu0j2ZDNHF7gblRozdiO49g1zqDOEzmKJ7gcGVQTzmLDSgZ1Eunh2dD9aewpsXtctH3cwzn5ALysoVWlXZvhleMV5ovfU8J363mciAliRLsRg0Q244vfT3A/zgT2cQHbImIY1S4ldPk9Ii+NH8V9H08DfbfiY6BtiHYpoYmMBr4bbwN9YzfVoEELnew9+blpwBv5u0oI9wPtQrUbkWFaXqOzsZ01IFg7pLQOyp/A58igmhCsHZJInYndNsHa/0wiVWTy9/a5NjprQGvag0Qmwd462iGltdQ8lihqlVVIIn/9/CAvrajDWgTRB8VhMt1/aSljVr4RToc6hJTWioe1jujJD4rfQx2qRvuTyX1JuTIh3UQikUgkEhPnF+1xZ9hHnLjAAAAAAElFTkSuQmCC');
104 background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAACCklEQVRoge3Yz6sNYRzH8deVexNxSaEoroWFUuomOceSPVnIwsbSxs6Psrgphf9AsrZR7kJWsroUlrZKKZRSl4USGouZk9Npzp1n5pm5x4/nXdNzpvP9Pp/v95nv82OGRCKRSCQS/w8zuIn3yGpe37CEQ6sedQk38BA7G/jO4BQ+YEebQZUxVfH/OxzGVSxX2D4o2mO4jmt4jpNFe6d5mPFkRbvQ0H9h6OqUtR33/xXr0celGn4/sYjXoQ5dJ3ILB7AOW2r4bcIj7GsrkEFpXWyrwwbaf15nXWqv6SqK1abuHDmPjV0EMobhBWIZt8cZVu0j2ZDNHF7gblRozdiO49g1zqDOEzmKJ7gcGVQTzmLDSgZ1Eunh2dD9aewpsXtctH3cwzn5ALysoVWlXZvhleMV5ovfU8J363mciAliRLsRg0Q244vfT3A/zgT2cQHbImIY1S4ldPk9Ii+NH8V9H08DfbfiY6BtiHYpoYmMBr4bbwN9YzfVoEELnew9+blpwBv5u0oI9wPtQrUbkWFaXqOzsZ01IFg7pLQOyp/A58igmhCsHZJInYndNsHa/0wiVWTy9/a5NjprQGvag0Qmwd462iGltdQ8lihqlVVIIn/9/CAvrajDWgTRB8VhMt1/aSljVr4RToc6hJTWioe1jujJD4rfQx2qRvuTyX1JuTIh3UQikUgkEhPnF+1xZ9hHnLjAAAAAAElFTkSuQmCC');
102 }
105 }
103
106
104 .center-on-screen {
107 .center-on-screen {
105 position: absolute;
108 position: absolute;
106 top: 0;
109 top: 0;
107 left: 0;
110 left: 0;
108 height: 100%;
111 height: 100%;
109 width: 100%;
112 width: 100%;
110 pointer-events: none;
113 pointer-events: none;
111 display: flex;
114 display: flex;
112 justify-content: center;
115 justify-content: center;
113 align-items: center;
116 align-items: center;
114 }
117 }
115
118
116 .center-on-screen > * {
119 .center-on-screen > * {
117 pointer-events: auto;
120 pointer-events: auto;
118 }
121 }
119
122
120 #qsp-image-container {
123 #qsp-image-container {
121 display: none;
124 display: none;
122 }
125 }
123
126
124 /* misc */
127 /* misc */
125
128
126 .disable a {
129 .disable a {
127 pointer-events: none;
130 pointer-events: none;
128 cursor: default;
131 cursor: default;
129 }
132 }
@@ -1,34 +1,46 b''
1
1
2 (in-package sugar-qsp.api)
2 (in-package sugar-qsp.api)
3
3
4 (defpsmacro with-call-args (args &body body)
4 (defpsmacro with-call-args (args &body body)
5 `(progn
5 `(progn
6 (init-args ,args)
6 (init-args ,args)
7 ,@body
7 ,@body
8 (get-result)))
8 (get-result)))
9
9
10 (defpsmacro with-frame (&body body)
10 (defpsmacro with-frame (&body body)
11 `(progn
11 `(progn
12 (push-local-frame)
12 (push-local-frame)
13 (unwind-protect
13 (unwind-protect
14 ,@body
14 ,@body
15 (pop-local-frame))))
15 (pop-local-frame))))
16
16
17 (defpsmacro href-call (func &rest args)
18 `(+ "javascript:" (inline-call ,func ,@args)))
19
17 (defpsmacro inline-call (func &rest args)
20 (defpsmacro inline-call (func &rest args)
18 `(+ (ps-inline ,func)
21 `(+ ,func
19 "(\""
22 "(\""
20 ,(first args)
23 ,(first args)
21 ,@(loop :for arg :in (cdr args)
24 ,@(loop :for arg :in (cdr args)
22 :collect "\", \""
25 :collect "\", \""
23 :collect arg)
26 :collect arg)
24 "\");"))
27 "\");"))
25
28
26 (defpsmacro with-sleep ((resume-func) &body body)
29 (defpsmacro with-sleep ((resume-func) &body body)
27 `(new (*promise
30 `(new (*promise
28 (lambda (resolve)
31 (lambda (resolve)
29 (start-sleeping)
32 (start-sleeping)
30 (let ((,resume-func (lambda ()
33 (let ((,resume-func (lambda ()
31 (finish-sleeping)
34 (finish-sleeping)
32 (resolve)))))
35 (resolve)))))
33 ,@body))))
36 ,@body))))
34
37
38 (defvar serv-vars (create))
39
40 (defpsmacro define-serv-var (name (slot value &optional index) &body body)
41 (setf name (string-upcase (symbol-name name)))
42 `(setf (getprop serv-vars name)
43 (create :name ,name
44 :slot ,slot
45 :body (lambda (,value ,@(when index (list index)))
46 ,@body))))
@@ -1,469 +1,528 b''
1
1
2 (in-package sugar-qsp.api)
2 (in-package sugar-qsp.api)
3
3
4 ;;; API deals with DOM manipulation and some bookkeeping for the
4 ;;; API deals with DOM manipulation and some bookkeeping for the
5 ;;; intrinsics, namely variables
5 ;;; intrinsics, namely variables
6 ;;; API is an implementation detail and has no QSP documentation. It
6 ;;; API is an implementation detail and has no QSP documentation. It
7 ;;; doesn't call intrinsics
7 ;;; doesn't call intrinsics
8
8
9 ;;; Utils
9 ;;; Utils
10
10
11 (defun make-act-html (title img)
11 (defun make-act-html (title img)
12 (+ "<a class='qsp-act' href='" (inline-call call-act title) "'>"
12 (+ "<a class='qsp-act' href='" (href-call call-act title) "' onmouseover='" (inline-call select-act title) "'>"
13 (if img (+ "<img src='" img "'>") "")
13 (if img (+ "<img src='" img "'>") "")
14 title
14 title
15 "</a>"))
15 "</a>"))
16
16
17 (defun make-menu-item-html (num title img loc)
17 (defun make-menu-item-html (num title img loc)
18 (+ "<a href='" (inline-call finish-menu loc) "'>"
18 (+ "<a href='" (href-call finish-menu loc) "'>"
19 (if img (+ "<img src='" img "'>") "")
19 (if img (+ "<img src='" img "'>") "")
20 title
20 title
21 "</a>"))
21 "</a>"))
22
22
23 (defun make-obj (title img selected)
24 (+ "<li>"
25 "<a href='" (href-call select-obj title img) "'"
26 "class='qsp-obj" (if selected " qsp-obj-selected" "") "'>"
27 (if img (+ "<img src='" img "'>") "")
28 obj
29 "</a>"))
30
23 (defun make-menu-delimiter ()
31 (defun make-menu-delimiter ()
24 "<hr>")
32 "<hr>")
25
33
26 (defun report-error (text)
34 (defun report-error (text)
27 (alert text))
35 (alert text))
28
36
29 (defun start-sleeping ()
37 (defun start-sleeping ()
30 (chain (by-id "qsp") class-list (add "disable")))
38 (chain (by-id "qsp") class-list (add "disable")))
31
39
32 (defun finish-sleeping ()
40 (defun finish-sleeping ()
33 (chain (by-id "qsp") class-list (remove "disable")))
41 (chain (by-id "qsp") class-list (remove "disable")))
34
42
35 (defun sleep (msec)
43 (defun sleep (msec)
36 (with-sleep (resume)
44 (with-sleep (resume)
37 (set-timeout resume msec)))
45 (set-timeout resume msec)))
38
46
39 (defun init-dom ()
47 (defun init-dom ()
40 ;; Save/load buttons
48 ;; Save/load buttons
41 (let ((btn (by-id "qsp-btn-save")))
49 (let ((btn (by-id "qsp-btn-save")))
42 (setf (@ btn onclick) savegame)
50 (setf (@ btn onclick) savegame)
43 (setf (@ btn href) "#"))
51 (setf (@ btn href) "#"))
44 (let ((btn (by-id "qsp-btn-open")))
52 (let ((btn (by-id "qsp-btn-open")))
45 (setf (@ btn onclick) opengame)
53 (setf (@ btn onclick) opengame)
46 (setf (@ btn href) "#"))
54 (setf (@ btn href) "#"))
47 ;; Close image on click
55 ;; Close image on click
48 (setf (@ (by-id "qsp-image-container") onclick)
56 (setf (@ (by-id "qsp-image-container") onclick)
49 (show-image nil))
57 show-image)
58 (setf (@ (get-frame :input) onkeyup)
59 on-input-key)
50 ;; Close the dropdown on any click
60 ;; Close the dropdown on any click
51 (setf (@ window onclick)
61 (setf (@ window onclick)
52 (lambda (event)
62 (lambda (event)
53 (setf (@ window mouse)
63 (setf (@ window mouse)
54 (list (@ event page-x)
64 (list (@ event page-x)
55 (@ event page-y)))
65 (@ event page-y)))
56 (finish-menu nil))))
66 (finish-menu nil))))
57
67
58 (defun call-serv-loc (var-name &rest args)
68 (defun call-serv-loc (var-name &rest args)
59 (let ((loc-name (get-var var-name 0 :str)))
69 (let ((loc-name (get-var var-name 0 :str)))
60 (when loc-name
70 (when loc-name
61 (let ((loc (getprop (root locs) loc-name)))
71 (let ((loc (getprop (root locs) loc-name)))
62 (when loc
72 (when loc
63 (funcall loc args))))))
73 (call-loc loc-name args))))))
64
74
65 (defun filename-game (filename)
75 (defun filename-game (filename)
66 (let ((game-name (chain filename (match "(.*/)?([^.]+)(\\.[a-zA-Z]+)?") 2))))
76 (let ((game-name (chain filename (match "(.*/)?([^.]+)(\\.[a-zA-Z]+)?") 2))))
67 (getprop (root games) game-name))
77 (getprop (root games) game-name))
68
78
69 (defun run-game (name)
79 (defun run-game (name)
70 (let ((game (filename-game name)))
80 (let ((game (filename-game name)))
71 (setf (root main-game) name)
81 (setf (root main-game) name)
72 ;; Replace locations with the new game's
82 ;; Replace locations with the new game's
73 (setf (root locs) game)
83 (setf (root locs) game)
74 (funcall (getprop game
84 (funcall (getprop game
75 (chain *object (keys game) 0))
85 (chain *object (keys game) 0))
76 (list))))
86 (list))))
77
87
78 ;;; Misc
88 ;;; Misc
79
89
80 (defun newline (key)
90 (defun newline (key)
81 (append-id (key-to-id key) "<br>" t))
91 (append-id (key-to-id key) "<br>" t))
82
92
83 (defun clear-id (id)
93 (defun clear-id (id)
84 (setf (inner-html (by-id id)) ""))
94 (setf (inner-html (by-id id)) ""))
85
95
86 (defvar text-escaper (chain document (create-element :textarea)))
96 (defvar text-escaper (chain document (create-element :textarea)))
87
97
88 (defun prepare-contents (s &optional force-html)
98 (defun prepare-contents (s &optional force-html)
89 (if (or force-html (get-var "USEHTML" 0 :num))
99 (if (or force-html (get-var "USEHTML" 0 :num))
90 s
100 s
91 (progn
101 (progn
92 (setf (@ text-escaper text-content) s)
102 (setf (@ text-escaper text-content) s)
93 (inner-html text-escaper))))
103 (inner-html text-escaper))))
94
104
95 (defun get-id (id &optional force-html)
105 (defun get-id (id &optional force-html)
96 (inner-html (by-id id)))
106 (inner-html (by-id id)))
97
107
98 (defun set-id (id contents &optional force-html)
108 (defun set-id (id contents &optional force-html)
99 (setf (inner-html (by-id id)) (prepare-contents contents force-html)))
109 (setf (inner-html (by-id id)) (prepare-contents contents force-html)))
100
110
101 (defun append-id (id contents &optional force-html)
111 (defun append-id (id contents &optional force-html)
102 (when contents
112 (when contents
103 (incf (inner-html (by-id id)) (prepare-contents contents force-html))))
113 (incf (inner-html (by-id id)) (prepare-contents contents force-html))))
104
114
115 (defun on-input-key (ev)
116 (when (= 13 (@ ev key-code))
117 (chain ev (prevent-default))
118 (call-serv-loc "USERCOM")))
119
105 ;;; Function calls
120 ;;; Function calls
106
121
107 (defun init-args (args)
122 (defun init-args (args)
108 (dotimes (i (length args))
123 (dotimes (i (length args))
109 (let ((arg (elt args i)))
124 (let ((arg (elt args i)))
110 (if (numberp arg)
125 (if (numberp arg)
111 (set-var args i :num arg)
126 (set-var args i :num arg)
112 (set-var args i :str arg)))))
127 (set-var args i :str arg)))))
113
128
114 (defun get-result ()
129 (defun get-result ()
115 (if (not (equal "" (get-var "RESULT" 0 :str)))
130 (if (not (equal "" (get-var "RESULT" 0 :str)))
116 (get-var "RESULT" 0 :str)
131 (get-var "RESULT" 0 :str)
117 (get-var "RESULT" 0 :num)))
132 (get-var "RESULT" 0 :num)))
118
133
119 (defun call-loc (name args)
134 (defun call-loc (name args)
120 (setf name (chain name (to-upper-case)))
135 (setf name (chain name (to-upper-case)))
121 (with-frame
136 (with-frame
122 (with-call-args args
137 (with-call-args args
123 (funcall (getprop (root locs) name) args))))
138 (funcall (getprop (root locs) name)))))
124
139
125 (defun call-act (title)
140 (defun call-act (title)
126 (with-frame
141 (with-frame
127 (funcall (getprop (root acts) title 'act))))
142 (funcall (getprop (root acts) title :act))))
128
143
129 ;;; Text windows
144 ;;; Text windows
130
145
131 (defun key-to-id (key)
146 (defun key-to-id (key)
132 (case key
147 (case key
148 (:all "qsp")
133 (:main "qsp-main")
149 (:main "qsp-main")
134 (:stat "qsp-stat")
150 (:stat "qsp-stat")
135 (:objs "qsp-objs")
151 (:objs "qsp-objs")
136 (:acts "qsp-acts")
152 (:acts "qsp-acts")
137 (:input "qsp-input")
153 (:input "qsp-input")
138 (:image "qsp-image")
154 (:image "qsp-image")
139 (:dropdown "qsp-dropdown")
155 (:dropdown "qsp-dropdown")
140 (t (report-error "Internal error!"))))
156 (t (report-error "Internal error!"))))
141
157
142 (defun get-frame (key)
158 (defun get-frame (key)
143 (by-id (key-to-id key)))
159 (by-id (key-to-id key)))
144
160
145 (defun add-text (key text)
161 (defun add-text (key text)
146 (append-id (key-to-id key) text))
162 (append-id (key-to-id key) text))
147
163
148 (defun get-text (key)
164 (defun get-text (key)
149 (get-id (key-to-id key)))
165 (get-id (key-to-id key)))
150
166
151 (defun clear-text (key)
167 (defun clear-text (key)
152 (clear-id (key-to-id key)))
168 (clear-id (key-to-id key)))
153
169
154 (defun enable-frame (key enable)
170 (defun enable-frame (key enable)
155 (let ((obj (get-frame key)))
171 (let ((obj (get-frame key)))
156 (setf (@ obj style display) (if enable "block" "none"))
172 (setf (@ obj style display) (if enable "block" "none"))
157 (void)))
173 (void)))
158
174
159 ;;; Actions
175 ;;; Actions
160
176
161 (defun add-act (title img act)
177 (defun add-act (title img act)
162 (setf (getprop (root acts) title)
178 (setf (getprop (root acts) title)
163 (create img img act act))
179 (create :title title :img img :act act :selected nil))
164 (update-acts))
180 (update-acts))
165
181
166 (defun del-act (title)
182 (defun del-act (title)
167 (delete (getprop (root acts) title))
183 (delete (getprop (root acts) title))
168 (update-acts))
184 (update-acts))
169
185
170 (defun clear-act ()
186 (defun clear-act ()
171 (setf (root acts) (create))
187 (setf (root acts) (create))
172 (clear-id "qsp-acts"))
188 (update-acts))
173
189
174 (defun update-acts ()
190 (defun update-acts ()
175 (clear-id "qsp-acts")
191 (clear-id "qsp-acts")
176 (let ((elt (by-id "qsp-acts")))
192 (let ((elt (by-id "qsp-acts")))
177 (for-in (title (root acts))
193 (for-in (title (root acts))
178 (let ((obj (getprop (root acts) title)))
194 (let ((obj (getprop (root acts) title)))
179 (incf (inner-html elt) (make-act-html title (getprop obj :img)))))))
195 (incf (inner-html elt) (make-act-html title (getprop obj :img)))))))
180
196
197 (defun select-act (title)
198 (loop :for (k v) :of (root acts)
199 (setf (getprop v :selected) nil))
200 (setf (getprop (root acts) title :selected) t)
201 (call-serv-loc "ONACTSEL"))
181
202
182 ;;; "Syntax"
203 ;;; "Syntax"
183
204
184 (defun qspfor (name index from to step body)
205 (defun qspfor (name index from to step body)
185 (for ((i from))
206 (for ((i from))
186 ((< i to))
207 ((< i to))
187 ((incf i step))
208 ((incf i step))
188 (set-var name index :num i)
209 (set-var name index :num i)
189 (unless (funcall body)
210 (unless (funcall body)
190 (return-from qspfor))))
211 (return-from qspfor))))
191
212
192 ;;; Variable class
213 ;;; Variable class
193
214
194 (defun *var (name)
215 (defun *var (name)
195 ;; From strings to numbers
216 ;; From strings to numbers
196 (setf (@ this indexes) (create))
217 (setf (@ this :indexes) (create))
197 ;; From numbers to {num: 0, str: ""} objects
218 ;; From numbers to {num: 0, str: ""} objects
198 (setf (@ this values) (list))
219 (setf (@ this :values) (list))
199 (void))
220 (void))
200
221
201 (defun new-value ()
222 (defun new-value ()
202 (create :num 0 :str ""))
223 (create :num 0 :str ""))
203
224
204 (setf (@ *var prototype index-num)
225 (setf (@ *var prototype index-num)
205 (lambda (index)
226 (lambda (index)
206 (let ((num-index
227 (let ((num-index
207 (if (stringp index)
228 (if (stringp index)
208 (if (in index (@ this indexes))
229 (if (in index (@ this :indexes))
209 (getprop (@ this indexes) index)
230 (getprop (@ this :indexes) index)
210 (let ((n (length (@ this values))))
231 (let ((n (length (@ this :values))))
211 (setf (getprop (@ this indexes) index) n)
232 (setf (getprop (@ this :indexes) index) n)
212 n))
233 n))
213 index)))
234 index)))
214 (unless (in num-index (@ this values))
235 (unless (in num-index (@ this :values))
215 (setf (elt (@ this values) num-index) (new-value)))
236 (setf (elt (@ this :values) num-index) (new-value)))
216 num-index)))
237 num-index)))
217
238
218 (setf (@ *var prototype get)
239 (setf (@ *var prototype get)
219 (lambda (index slot)
240 (lambda (index slot)
220 (unless (or index (= 0 index))
241 (unless (or index (= 0 index))
221 (setf index (1- (length (@ this values)))))
242 (setf index (1- (length (@ this :values)))))
222 (getprop (@ this values) (chain this (index-num index)) slot)))
243 (getprop (@ this :values) (chain this (index-num index)) slot)))
223
244
224 (setf (@ *var prototype set)
245 (setf (@ *var prototype set)
225 (lambda (index slot value)
246 (lambda (index slot value)
226 (unless (or index (= 0 index))
247 (unless (or index (= 0 index))
227 (setf index (length (@ this values))))
248 (setf index (length (@ this :values))))
228 (case slot
249 (case slot
229 (:num (setf value (chain *number (parse-int value))))
250 (:num (setf value (chain *number (parse-int value))))
230 (:str (setf value (chain value (to-string)))))
251 (:str (setf value (chain value (to-string)))))
231 (setf (getprop (@ this values)
252 (setf (getprop (@ this :values)
232 (chain this (index-num index))
253 (chain this (index-num index))
233 slot) value)
254 slot) value)
234 (void)))
255 (void)))
235
256
236 (setf (@ *var prototype kill)
257 (setf (@ *var prototype kill)
237 (lambda (index)
258 (lambda (index)
238 (setf (elt (@ this values) (chain this (index-num index)))
259 (setf (elt (@ this :values) (chain this (index-num index)))
239 (new-value))
260 (new-value))
240 (delete (getprop 'this 'indexes index))))
261 (delete (getprop 'this :indexes index))))
241
262
242 ;;; Variables
263 ;;; Variables
243
264
244 (defun var-real-name (name)
265 (defun var-real-name (name)
245 (if (= (@ name 0) #\$)
266 (if (= (@ name 0) #\$)
246 (values (chain name (substr 1)) :str)
267 (values (chain name (substr 1)) :str)
247 (values name :num)))
268 (values name :num)))
248
269
249 (defun ensure-var (name)
270 (defun ensure-var (name)
250 (setf name (chain name (to-upper-case)))
271 (setf name (chain name (to-upper-case)))
251 (let ((store (var-ref name)))
272 (let ((store (var-ref name)))
252 (unless store
273 (unless store
253 (setf store (new (*var name)))
274 (setf store (new (*var name)))
254 (setf (getprop (root vars) name) store))
275 (setf (getprop (root vars) name) store))
255 store))
276 store))
256
277
257 (defun var-ref (name)
278 (defun var-ref (name)
258 (let ((local-store (current-local-frame)))
279 (let ((local-store (current-local-frame)))
259 (cond ((and local-store (in name local-store))
280 (cond ((and local-store (in name local-store))
260 (getprop local-store name))
281 (getprop local-store name))
261 ((in name (root vars))
282 ((in name (root vars))
262 (getprop (root vars) name))
283 (getprop (root vars) name))
263 (t nil))))
284 (t nil))))
264
285
265 (defun get-var (name index slot)
286 (defun get-var (name index slot)
266 (chain (ensure-var name) (get index slot)))
287 (chain (ensure-var name) (get index slot)))
267
288
268 (defun set-var (name index slot value)
289 (defun set-var (name index slot value)
269 (chain (ensure-var name) (set index slot value))
290 (chain (ensure-var name) (set index slot value))
291 (let ((serv-var (getprop serv-vars name)))
292 (when serv-var
293 (funcall (@ serv-var :func)
294 (get-var name index (@ serv-var :slot))
295 index)))
270 (void))
296 (void))
271
297
272 (defun get-array (name)
298 (defun get-array (name)
273 (setf name (chain name (to-upper-case)))
299 (setf name (chain name (to-upper-case)))
274 (var-ref name))
300 (ensure-var name))
275
301
276 (defun set-array (name value)
302 (defun set-array (name value)
277 (setf name (chain name (to-upper-case)))
303 (setf name (chain name (to-upper-case)))
278 (let ((store (var-ref name)))
304 (let ((store (ensure-var name)))
279 (setf (@ store values) (@ value values))
305 (setf (@ store :values) (@ value :values))
280 (setf (@ store indexes) (@ value indexes)))
306 (setf (@ store :indexes) (@ value :indexes)))
281 (void))
307 (void))
282
308
283 (defun kill-var (name &optional index)
309 (defun kill-var (name &optional index)
284 (setf name (chain name (to-upper-case)))
310 (setf name (chain name (to-upper-case)))
285 (if (and index (not (= 0 index)))
311 (if (and index (not (= 0 index)))
286 (chain (getprop (root vars) name) (kill index))
312 (chain (getprop (root vars) name) (kill index))
287 (delete (getprop (root vars) name)))
313 (delete (getprop (root vars) name)))
288 (void))
314 (void))
289
315
290 (defun array-size (name)
316 (defun array-size (name)
291 (@ (var-ref name) values length))
317 (@ (var-ref name) :values length))
292
318
293 ;;; Locals
319 ;;; Locals
294
320
295 (defun push-local-frame ()
321 (defun push-local-frame ()
296 (chain (root locals) (push (create)))
322 (chain (root locals) (push (create)))
297 (void))
323 (void))
298
324
299 (defun pop-local-frame ()
325 (defun pop-local-frame ()
300 (chain (root locals) (pop))
326 (chain (root locals) (pop))
301 (void))
327 (void))
302
328
303 (defun current-local-frame ()
329 (defun current-local-frame ()
304 (elt (root locals) (1- (length (root locals)))))
330 (elt (root locals) (1- (length (root locals)))))
305
331
306 (defun new-local (name)
332 (defun new-local (name)
307 (let ((frame (current-local-frame)))
333 (let ((frame (current-local-frame)))
308 (unless (in name frame)
334 (unless (in name frame)
309 (setf (getprop frame name) (create)))
335 (setf (getprop frame name) (create)))
310 (void)))
336 (void)))
311
337
312 ;;; Objects
338 ;;; Objects
313
339
340 (defun select-obj (title img)
341 (loop :for (k v) :of (root objs)
342 (setf (getprop v :selected) nil))
343 (setf (getprop (root objs) title :selected) t)
344 (call-serv-loc "ONOBJSEL" title img))
345
314 (defun update-objs ()
346 (defun update-objs ()
315 (let ((elt (by-id "qsp-objs")))
347 (let ((elt (by-id "qsp-objs")))
316 (setf (inner-html elt) "<ul>")
348 (setf (inner-html elt) "<ul>")
317 (loop :for obj :in (root objs)
349 (loop :for obj :in (root objs)
318 :do (incf (inner-html elt) (+ "<li>" obj)))
350 :do (incf (inner-html elt)
351 (make-obj obj)))
319 (incf (inner-html elt) "</ul>")))
352 (incf (inner-html elt) "</ul>")))
320
353
321 ;;; Menu
354 ;;; Menu
322
355
323 (defun open-menu (menu-data)
356 (defun open-menu (menu-data)
324 (let ((elt (get-frame :dropdown))
357 (let ((elt (get-frame :dropdown))
325 (i 0))
358 (i 0))
326 (loop :for item :in menu-data
359 (loop :for item :in menu-data
327 :do (incf i)
360 :do (incf i)
328 :do (incf (inner-html elt)
361 :do (incf (inner-html elt)
329 (if (eq item :delimiter)
362 (if (eq item :delimiter)
330 (make-menu-delimiter i)
363 (make-menu-delimiter i)
331 (make-menu-item-html i
364 (make-menu-item-html i
332 (@ item :text)
365 (@ item :text)
333 (@ item :icon)
366 (@ item :icon)
334 (@ item :loc)))))
367 (@ item :loc)))))
335 (let ((mouse (@ window mouse)))
368 (let ((mouse (@ window mouse)))
336 (setf (@ elt style left) (+ (elt mouse 0) "px"))
369 (setf (@ elt style left) (+ (elt mouse 0) "px"))
337 (setf (@ elt style top) (+ (elt mouse 1) "px"))
370 (setf (@ elt style top) (+ (elt mouse 1) "px"))
338 ;; Make sure it's inside the viewport
371 ;; Make sure it's inside the viewport
339 (when (> (@ document body inner-width)
372 (when (> (@ document body inner-width)
340 (+ (elt mouse 0) (@ elt inner-width)))
373 (+ (elt mouse 0) (@ elt inner-width)))
341 (incf (@ elt style left) (@ elt inner-width)))
374 (incf (@ elt style left) (@ elt inner-width)))
342 (when (> (@ document body inner-height)
375 (when (> (@ document body inner-height)
343 (+ (elt mouse 0) (@ elt inner-height)))
376 (+ (elt mouse 0) (@ elt inner-height)))
344 (incf (@ elt style top) (@ elt inner-height))))
377 (incf (@ elt style top) (@ elt inner-height))))
345 (setf (@ elt style display) "block")))
378 (setf (@ elt style display) "block")))
346
379
347 (defun finish-menu (loc)
380 (defun finish-menu (loc)
348 (when (root menu-resume)
381 (when (root menu-resume)
349 (let ((elt (get-frame :dropdown)))
382 (let ((elt (get-frame :dropdown)))
350 (setf (inner-html elt) "")
383 (setf (inner-html elt) "")
351 (setf (@ elt style display) "none")
384 (setf (@ elt style display) "none")
352 (funcall (root menu-resume))
385 (funcall (root menu-resume))
353 (setf (root menu-resume) nil))
386 (setf (root menu-resume) nil))
354 (when loc
387 (when loc
355 (call-loc loc)))
388 (call-loc loc)))
356 (void))
389 (void))
357
390
358 (defun menu (menu-data)
391 (defun menu (menu-data)
359 (with-sleep (resume)
392 (with-sleep (resume)
360 (open-menu menu-data)
393 (open-menu menu-data)
361 (setf (root menu-resume) resume))
394 (setf (root menu-resume) resume))
362 (void))
395 (void))
363
396
364 ;;; Content
397 ;;; Content
365
398
366 (defun clean-audio ()
399 (defun clean-audio ()
367 (loop :for k :in (chain *object (keys (root playing)))
400 (loop :for k :in (chain *object (keys (root playing)))
368 :for v := (getprop (root playing) k)
401 :for v := (getprop (root playing) k)
369 :do (when (@ v ended)
402 :do (when (@ v ended)
370 (delete (@ (root playing) k)))))
403 (delete (@ (root playing) k)))))
371
404
372 (defun show-image (path)
405 (defun show-image (path)
373 (let ((img (get-frame :image)))
406 (let ((img (get-frame :image)))
374 (cond (path
407 (cond (path
375 (setf (@ img src) path)
408 (setf (@ img src) path)
376 (setf (@ img style display) "flex"))
409 (setf (@ img style display) "flex"))
377 (t
410 (t
378 (setf (@ img src) "")
411 (setf (@ img src) "")
379 (setf (@ img style display) "hidden")))))
412 (setf (@ img style display) "hidden")))))
380
413
414 (defun rgb-string (rgb)
415 (let ((red (rgb >> 16))
416 (green (& (rgb >> 8) 255))
417 (blue (& rgb 255)))
418 (flet ((rgb-to-hex (comp)
419 (let ((hex (chain (*number comp) (to-string 16))))
420 (if (< (length hex) 2)
421 (+ "0" hex)
422 hex))))
423 (+ "#" (rgb-to-hex red) (rgb-to-hex green) (rgb-to-hex red)))))
424
381 ;;; Saves
425 ;;; Saves
382
426
383 (defun opengame ()
427 (defun opengame ()
384 (let ((element (chain document (create-element :input))))
428 (let ((element (chain document (create-element :input))))
385 (chain element (set-attribute :type :file))
429 (chain element (set-attribute :type :file))
386 (chain element (set-attribute :id :qsp-opengame))
430 (chain element (set-attribute :id :qsp-opengame))
387 (chain element (set-attribute :tabindex -1))
431 (chain element (set-attribute :tabindex -1))
388 (chain element (set-attribute "aria-hidden" t))
432 (chain element (set-attribute "aria-hidden" t))
389 (setf (@ element style display) :block)
433 (setf (@ element style display) :block)
390 (setf (@ element style visibility) :hidden)
434 (setf (@ element style visibility) :hidden)
391 (setf (@ element style position) :fixed)
435 (setf (@ element style position) :fixed)
392 (setf (@ element onchange)
436 (setf (@ element onchange)
393 (lambda (event)
437 (lambda (event)
394 (let* ((file (@ event target files 0))
438 (let* ((file (@ event target files 0))
395 (reader (new (*file-reader))))
439 (reader (new (*file-reader))))
396 (setf (@ reader onload)
440 (setf (@ reader onload)
397 (lambda (ev)
441 (lambda (ev)
398 (block nil
442 (block nil
399 (let ((target (@ ev current-target)))
443 (let ((target (@ ev current-target)))
400 (unless (@ target result)
444 (unless (@ target result)
401 (return))
445 (return))
402 (base64-to-state (@ target result))
446 (base64-to-state (@ target result))
403 (unstash-state)))))
447 (unstash-state)))))
404 (chain reader (read-as-text file)))))
448 (chain reader (read-as-text file)))))
405 (chain document body (append-child element))
449 (chain document body (append-child element))
406 (chain element (click))
450 (chain element (click))
407 (chain document body (remove-child element))))
451 (chain document body (remove-child element))))
408
452
409 (defun savegame ()
453 (defun savegame ()
410 (let ((element (chain document (create-element :a))))
454 (let ((element (chain document (create-element :a))))
411 (chain element (set-attribute :href (+ "data:text/plain;charset=utf-8," (state-to-base64))))
455 (chain element (set-attribute :href (+ "data:text/plain;charset=utf-8," (state-to-base64))))
412 (chain element (set-attribute :download "savegame.sav"))
456 (chain element (set-attribute :download "savegame.sav"))
413 (setf (@ element style display) :none)
457 (setf (@ element style display) :none)
414 (chain document body (append-child element))
458 (chain document body (append-child element))
415 (chain element (click))
459 (chain element (click))
416 (chain document body (remove-child element))))
460 (chain document body (remove-child element))))
417
461
418 (defun stash-state (args)
462 (defun stash-state (args)
419 (call-serv-loc "ONGSAVE")
463 (call-serv-loc "ONGSAVE")
420 (setf (root state-stash)
464 (setf (root state-stash)
421 (chain *j-s-o-n (stringify
465 (chain *j-s-o-n (stringify
422 (create :vars (root vars)
466 (create :vars (root vars)
423 :objs (root objs)
467 :objs (root objs)
424 :loc-args args
468 :loc-args args
425 :msecs (- (chain *date (now)) (root started-at))
469 :msecs (- (chain *date (now)) (root started-at))
426 :timer-interval (root timer-interval)
470 :timer-interval (root timer-interval)
427 :main-html (inner-html
471 :main-html (inner-html
428 (get-frame :main))
472 (get-frame :main))
429 :stat-html (inner-html
473 :stat-html (inner-html
430 (get-frame :stat))
474 (get-frame :stat))
431 :next-location (root current-location)))))
475 :next-location (root current-location)))))
432 (void))
476 (void))
433
477
434 (defun unstash-state ()
478 (defun unstash-state ()
435 (let ((data (chain *j-s-o-n (parse (root state-stash)))))
479 (let ((data (chain *j-s-o-n (parse (root state-stash)))))
436 (clear-act)
480 (clear-act)
437 (setf (root vars) (@ data :vars))
481 (setf (root vars) (@ data :vars))
438 (loop :for k :in (chain *object (keys (root vars)))
482 (loop :for k :in (chain *object (keys (root vars)))
439 :do (chain *object (set-prototype-of (getprop (root vars) k)
483 :do (chain *object (set-prototype-of (getprop (root vars) k)
440 (@ *var prototype))))
484 (@ *var prototype))))
441 (setf (root started-at) (- (chain *date (now)) (@ data :msecs)))
485 (setf (root started-at) (- (chain *date (now)) (@ data :msecs)))
442 (setf (root objs) (@ data :objs))
486 (setf (root objs) (@ data :objs))
443 (setf (root current-location) (@ data :next-location))
487 (setf (root current-location) (@ data :next-location))
444 (setf (inner-html (get-frame :main))
488 (setf (inner-html (get-frame :main))
445 (@ data :main-html))
489 (@ data :main-html))
446 (setf (inner-html (get-frame :stat))
490 (setf (inner-html (get-frame :stat))
447 (@ data :stat-html))
491 (@ data :stat-html))
448 (update-objs)
492 (update-objs)
449 (set-timer (@ data :timer-interval))
493 (set-timer (@ data :timer-interval))
450 (call-serv-loc "ONGLOAD")
494 (call-serv-loc "ONGLOAD")
451 (call-loc (root current-location) (@ data :loc-args))
495 (call-loc (root current-location) (@ data :loc-args))
452 (void)))
496 (void)))
453
497
454 (defun state-to-base64 ()
498 (defun state-to-base64 ()
455 (btoa (encode-u-r-i-component (root state-stash))))
499 (btoa (encode-u-r-i-component (root state-stash))))
456
500
457 (defun base64-to-state (data)
501 (defun base64-to-state (data)
458 (setf (root state-stash) (decode-u-r-i-component (atob data))))
502 (setf (root state-stash) (decode-u-r-i-component (atob data))))
459
503
460 ;;; Timers
504 ;;; Timers
461
505
462 (defun set-timer (interval)
506 (defun set-timer (interval)
463 (setf (root timer-interval) interval)
507 (setf (root timer-interval) interval)
464 (clear-interval (root timer-obj))
508 (clear-interval (root timer-obj))
465 (setf (root timer-obj)
509 (setf (root timer-obj)
466 (set-interval
510 (set-interval
467 (lambda ()
511 (lambda ()
468 (call-serv-loc "COUNTER"))
512 (call-serv-loc "COUNTER"))
469 interval)))
513 interval)))
514
515 ;;; Special variables
516
517 (define-serv-var backimage (:str path)
518 (setf (@ (get-frame :main) style background-image) path))
519
520 (define-serv-var bcolor (:num color)
521 (setf (@ (get-frame :all) style background-color) (rgb-string color)))
522
523 (define-serv-var fcolor (:num color)
524 (setf (@ (get-frame :all) style color) (rgb-string color)))
525
526 (define-serv-var lcolor (:num color)
527 (setf (@ (get-frame :style) inner-text)
528 (+ "a { color: " (rgb-string color) ";}")))
@@ -1,174 +1,168 b''
1
1
2 (in-package sugar-qsp.lib)
2 (in-package sugar-qsp.lib)
3
3
4 ;;;; Macros implementing some intrinsics where it makes sense
4 ;;;; Macros implementing some intrinsics where it makes sense
5 ;;;; E.g. an equivalent JS function exists, or it's a direct API call
5 ;;;; E.g. an equivalent JS function exists, or it's a direct API call
6
6
7 ;;; 1loc
7 ;;; 1loc
8
8
9 ;;; 2var
9 ;;; 2var
10
10
11 (defpsmacro killvar (varname &optional index)
11 (defpsmacro killvar (varname &optional index)
12 `(api-call kill-var ,varname ,index))
12 `(api-call kill-var ,varname ,index))
13
13
14 (defpsmacro killall ()
14 (defpsmacro killall ()
15 `(api-call kill-all))
15 `(api-call kill-all))
16
16
17 ;;; 3expr
17 ;;; 3expr
18
18
19 (defpsmacro obj (name)
19 (defpsmacro obj (name)
20 `(funcall (root objs includes) ,name))
20 `(funcall (root objs includes) ,name))
21
21
22 (defpsmacro loc (name)
22 (defpsmacro loc (name)
23 `(funcall (root locs includes) ,name))
23 `(funcall (root locs includes) ,name))
24
24
25 (defpsmacro no (arg)
25 (defpsmacro no (arg)
26 `(- -1 ,arg))
26 `(- -1 ,arg))
27
27
28 ;;; 4code
28 ;;; 4code
29
29
30 (defpsmacro qspver ()
30 (defpsmacro qspver ()
31 "0.0.1")
31 "0.0.1")
32
32
33 (defpsmacro curloc ()
33 (defpsmacro curloc ()
34 `(root current-location))
34 `(root current-location))
35
35
36 (defpsmacro rnd ()
36 (defpsmacro rnd ()
37 `(funcall rand 1 1000))
37 `(funcall rand 1 1000))
38
38
39 (defpsmacro qspmax (&rest args)
39 (defpsmacro qspmax (&rest args)
40 (if (= 1 (length args))
40 (if (= 1 (length args))
41 `(*math.max.apply nil ,@args)
41 `(*math.max.apply nil ,@args)
42 `(*math.max ,@args)))
42 `(*math.max ,@args)))
43
43
44 (defpsmacro qspmin (&rest args)
44 (defpsmacro qspmin (&rest args)
45 (if (= 1 (length args))
45 (if (= 1 (length args))
46 `(*math.min.apply nil ,@args)
46 `(*math.min.apply nil ,@args)
47 `(*math.min ,@args)))
47 `(*math.min ,@args)))
48
48
49 ;;; 5arrays
49 ;;; 5arrays
50
50
51 (defpsmacro arrsize (name)
51 (defpsmacro arrsize (name)
52 `(api-call array-size ,name))
52 `(api-call array-size ,name))
53
53
54 ;;; 6str
54 ;;; 6str
55
55
56 (defpsmacro len (s)
56 (defpsmacro len (s)
57 `(length ,s))
57 `(length ,s))
58
58
59 (defpsmacro mid (s from &optional count)
59 (defpsmacro mid (s from &optional count)
60 `(chain ,s (substring ,from ,count)))
60 `(chain ,s (substring ,from ,count)))
61
61
62 (defpsmacro ucase (s)
62 (defpsmacro ucase (s)
63 `(chain ,s (to-upper-case)))
63 `(chain ,s (to-upper-case)))
64
64
65 (defpsmacro lcase (s)
65 (defpsmacro lcase (s)
66 `(chain ,s (to-lower-case)))
66 `(chain ,s (to-lower-case)))
67
67
68 (defpsmacro trim (s)
68 (defpsmacro trim (s)
69 `(chain ,s (trim)))
69 `(chain ,s (trim)))
70
70
71 (defpsmacro replace (s from to)
71 (defpsmacro replace (s from to)
72 `(chain ,s (replace ,from ,to)))
72 `(chain ,s (replace ,from ,to)))
73
73
74 (defpsmacro val (s)
74 (defpsmacro val (s)
75 `(parse-int ,s 10))
75 `(parse-int ,s 10))
76
76
77 (defpsmacro qspstr (n)
77 (defpsmacro qspstr (n)
78 `(chain ,n (to-string)))
78 `(chain ,n (to-string)))
79
79
80 ;;; 7if
80 ;;; 7if
81
81
82 ;;; 8sub
82 ;;; 8sub
83
83
84 ;;; 9loops
84 ;;; 9loops
85
85
86 ;; JUMP is in ps-macros.lisp (because it's a part of a huge kludge)
86 ;; JUMP is in ps-macros.lisp (because it's a part of a huge kludge)
87
87
88 (defpsmacro exit ()
88 (defpsmacro exit ()
89 `(return-from nil (values)))
89 `(return-from nil (values)))
90
90
91 ;;; 10dynamic
91 ;;; 10dynamic
92
92
93 ;;; 11main
93 ;;; 11main
94
94
95 (defpsmacro desc (s)
95 (defpsmacro desc (s)
96 (declare (ignore s))
96 (declare (ignore s))
97 "")
97 "")
98
98
99 ;;; 12stat
99 ;;; 12stat
100
100
101 (defpsmacro showstat (enable)
101 (defpsmacro showstat (enable)
102 `(api-call enable-frame :stat ,enable))
102 `(api-call enable-frame :stat ,enable))
103
103
104 ;;; 13diag
104 ;;; 13diag
105
105
106 (defpsmacro msg (text)
106 (defpsmacro msg (text)
107 `(alert ,text))
107 `(alert ,text))
108
108
109 ;;; 14act
109 ;;; 14act
110
110
111 (defpsmacro showacts (enable)
111 (defpsmacro showacts (enable)
112 `(api-call enable-frame :acts ,enable))
112 `(api-call enable-frame :acts ,enable))
113
113
114 (defpsmacro delact (name)
114 (defpsmacro delact (name)
115 `(api-call del-act ,name))
115 `(api-call del-act ,name))
116
116
117 (defpsmacro cla ()
117 (defpsmacro cla ()
118 `(api-call clear-act))
118 `(api-call clear-act))
119
119
120 ;;; 15objs
120 ;;; 15objs
121
121
122 (defpsmacro showobjs (enable)
122 (defpsmacro showobjs (enable)
123 `(api-call enable-frame :objs ,enable))
123 `(api-call enable-frame :objs ,enable))
124
124
125 (defpsmacro countobj ()
125 (defpsmacro countobj ()
126 `(length (root objs)))
126 `(length (root objs)))
127
127
128 (defpsmacro getobj (index)
128 (defpsmacro getobj (index)
129 `(or (elt (root objs) ,index) ""))
129 `(or (elt (root objs) ,index) ""))
130
130
131 ;;; 16menu
131 ;;; 16menu
132
132
133 ;;; 17sound
133 ;;; 17sound
134
134
135 (defpsmacro isplay (filename)
135 (defpsmacro isplay (filename)
136 `(funcall (root playing includes) ,filename))
136 `(funcall (root playing includes) ,filename))
137
137
138 ;;; 18img
138 ;;; 18img
139
139
140 (defpsmacro view (&optional path)
140 (defpsmacro view (&optional path)
141 `(api-call show-image ,path))
141 `(api-call show-image ,path))
142
142
143 ;;; 19input
143 ;;; 19input
144
144
145 (defpsmacro showinput (enable)
145 (defpsmacro showinput (enable)
146 `(api-call enable-frame :input ,enable))
146 `(api-call enable-frame :input ,enable))
147
147
148 ;;; 20time
148 ;;; 20time
149
149
150 (defpsmacro wait (msec)
150 (defpsmacro wait (msec)
151 `(await (api-call sleep ,msec)))
151 `(await (api-call sleep ,msec)))
152
152
153 (defpsmacro settimer (interval)
153 (defpsmacro settimer (interval)
154 `(api-call set-timer ,interval))
154 `(api-call set-timer ,interval))
155
155
156 ;;; 21local
156 ;;; 21local
157
157
158 (defpsmacro local (var &optional expr)
159 `(progn
160 (api-call new-local ,(string (second var)))
161 ,@(when expr
162 `((set ,var ,expr)))))
163
164 ;;; 22for
158 ;;; 22for
165
159
166 ;;; misc
160 ;;; misc
167
161
168 (defpsmacro opengame (&optional filename)
162 (defpsmacro opengame (&optional filename)
169 (declare (ignore filename))
163 (declare (ignore filename))
170 `(api-call opengame))
164 `(api-call opengame))
171
165
172 (defpsmacro savegame (&optional filename)
166 (defpsmacro savegame (&optional filename)
173 (declare (ignore filename))
167 (declare (ignore filename))
174 `(api-call savegame))
168 `(api-call savegame))
@@ -1,310 +1,314 b''
1
1
2 (in-package sugar-qsp.lib)
2 (in-package sugar-qsp.lib)
3
3
4 ;;;; Functions and procedures defined by the QSP language.
4 ;;;; Functions and procedures defined by the QSP language.
5 ;;;; They can call api and deal with locations and other data directly.
5 ;;;; They can call api and deal with locations and other data directly.
6 ;;;; Except vars. Use VAR and SET or GET-VAR and SET-VAR api calls.
6 ;;;; Except vars. Use VAR and SET or GET-VAR and SET-VAR api calls.
7
7
8 ;;; 1loc
8 ;;; 1loc
9
9
10 (defun goto (target args)
10 (defun goto (target args)
11 (api:clear-text :main)
11 (api:clear-text :main)
12 (funcall xgoto target args)
12 (funcall xgoto target args)
13 (void))
13 (void))
14
14
15 (defun xgoto (target args)
15 (defun xgoto (target args)
16 (setf args (or args (list)))
16 (setf args (or args (list)))
17 (api:clear-act)
17 (api:clear-act)
18 (setf (root current-location) (chain target (to-upper-case)))
18 (setf (root current-location) (chain target (to-upper-case)))
19 (api:stash-state args)
19 (api:stash-state args)
20 (api:call-loc (root current-location) args)
20 (api:call-loc (root current-location) args)
21 (api:call-serv-loc "ONNEWLOC")
21 (void))
22 (void))
22
23
23 ;;; 2var
24 ;;; 2var
24
25
25 ;;; 3expr
26 ;;; 3expr
26
27
27 ;;; 4code
28 ;;; 4code
28
29
29 (defun rand (a &optional (b 1))
30 (defun rand (a &optional (b 1))
30 (let ((min (min a b))
31 (let ((min (min a b))
31 (max (max a b)))
32 (max (max a b)))
32 (+ min (chain *math (random (- max min))))))
33 (+ min (chain *math (random (- max min))))))
33
34
34 ;;; 5arrays
35 ;;; 5arrays
35
36
36 (defun copyarr (to from start count)
37 (defun copyarr (to from start count)
37 (multiple-value-bind (to-name to-slot)
38 (multiple-value-bind (to-name to-slot)
38 (api:var-real-name to)
39 (api:var-real-name to)
39 (multiple-value-bind (from-name from-slot)
40 (multiple-value-bind (from-name from-slot)
40 (api:var-real-name from)
41 (api:var-real-name from)
41 (for ((i start))
42 (for ((i start))
42 ((< i (min (api:array-size from-name)
43 ((< i (min (api:array-size from-name)
43 (+ start count))))
44 (+ start count))))
44 ((incf i))
45 ((incf i))
45 (api:set-var to-name (+ start i) to-slot
46 (api:set-var to-name (+ start i) to-slot
46 (api:get-var from-name (+ start i) from-slot))))))
47 (api:get-var from-name (+ start i) from-slot))))))
47
48
48 (defun arrpos (name value &optional (start 0))
49 (defun arrpos (name value &optional (start 0))
49 (multiple-value-bind (real-name slot)
50 (multiple-value-bind (real-name slot)
50 (api:var-real-name name)
51 (api:var-real-name name)
51 (for ((i start)) ((< i (api:array-size name))) ((incf i))
52 (for ((i start)) ((< i (api:array-size name))) ((incf i))
52 (when (eq (api:get-var real-name i slot) value)
53 (when (eq (api:get-var real-name i slot) value)
53 (return-from arrpos i))))
54 (return-from arrpos i))))
54 -1)
55 -1)
55
56
56 (defun arrcomp (name pattern &optional (start 0))
57 (defun arrcomp (name pattern &optional (start 0))
57 (multiple-value-bind (real-name slot)
58 (multiple-value-bind (real-name slot)
58 (api:var-real-name name)
59 (api:var-real-name name)
59 (for ((i start)) ((< i (api:array-size name))) ((incf i))
60 (for ((i start)) ((< i (api:array-size name))) ((incf i))
60 (when (funcall (getprop (api:get-var real-name i slot) 'match) pattern)
61 (when (funcall (getprop (api:get-var real-name i slot) 'match) pattern)
61 (return-from arrcomp i))))
62 (return-from arrcomp i))))
62 -1)
63 -1)
63
64
64 ;;; 6str
65 ;;; 6str
65
66
66 (defun instr (s subs &optional (start 1))
67 (defun instr (s subs &optional (start 1))
67 (+ start (chain s (substring (- start 1)) (search subs))))
68 (+ start (chain s (substring (- start 1)) (search subs))))
68
69
69 (defun isnum (s)
70 (defun isnum (s)
70 (if (is-na-n s)
71 (if (is-na-n s)
71 0
72 0
72 -1))
73 -1))
73
74
74 (defun strcomp (s pattern)
75 (defun strcomp (s pattern)
75 (if (chain s (match pattern))
76 (if (chain s (match pattern))
76 -1
77 -1
77 0))
78 0))
78
79
79 (defun strfind (s pattern group)
80 (defun strfind (s pattern group)
80 (let* ((re (new (*reg-exp pattern)))
81 (let* ((re (new (*reg-exp pattern)))
81 (match (chain re (exec s))))
82 (match (chain re (exec s))))
82 (chain match (group group))))
83 (chain match (group group))))
83
84
84 (defun strpos (s pattern &optional (group 0))
85 (defun strpos (s pattern &optional (group 0))
85 (let* ((re (new (*reg-exp pattern)))
86 (let* ((re (new (*reg-exp pattern)))
86 (match (chain re (exec s)))
87 (match (chain re (exec s)))
87 (found (chain match (group group))))
88 (found (chain match (group group))))
88 (if found
89 (if found
89 (chain s (search found))
90 (chain s (search found))
90 0)))
91 0)))
91
92
92 ;;; 7if
93 ;;; 7if
93
94
94 ;; Has to be a function because it always evaluates all three of its
95 ;; Has to be a function because it always evaluates all three of its
95 ;; arguments
96 ;; arguments
96 (defun iif (cond-expr then-expr else-expr)
97 (defun iif (cond-expr then-expr else-expr)
97 (if cond-expr then-expr else-expr))
98 (if cond-expr then-expr else-expr))
98
99
99 ;;; 8sub
100 ;;; 8sub
100
101
101 (defun gosub (target &rest args)
102 (defun gosub (target &rest args)
102 (api:call-loc target args)
103 (api:call-loc target args)
103 (void))
104 (void))
104
105
105 (defun func (target &rest args)
106 (defun func (target &rest args)
106 (api:call-loc target args))
107 (api:call-loc target args))
107
108
108 ;;; 9loops
109 ;;; 9loops
109
110
110 ;;; 10dynamic
111 ;;; 10dynamic
111
112
112 (defun dynamic (block &rest args)
113 (defun dynamic (block &rest args)
113 (when (stringp block)
114 (when (stringp block)
114 (api:report-error "DYNAMIC can't evaluate arbitrary strings.\\nUse {braces} to create blocks for DYNAMIC."))
115 (api:report-error "DYNAMIC can't evaluate arbitrary strings.\\nUse {braces} to create blocks for DYNAMIC."))
115 (api:with-call-args args
116 (api:with-call-args args
116 (funcall block args))
117 (funcall block args))
117 (void))
118 (void))
118
119
119 (defun dyneval (block &rest args)
120 (defun dyneval (block &rest args)
120 (when (stringp block)
121 (when (stringp block)
121 (api:report-error "DYNEVAL can't evaluate arbitrary strings.\\nUse {braces} to create blocks for DYNEVAL."))
122 (api:report-error "DYNEVAL can't evaluate arbitrary strings.\\nUse {braces} to create blocks for DYNEVAL."))
122 (api:with-call-args args
123 (api:with-call-args args
123 (funcall block args)))
124 (funcall block args)))
124
125
125 ;;; 11main
126 ;;; 11main
126
127
127 (defun main-p (s)
128 (defun main-p (s)
128 (api:add-text :main s)
129 (api:add-text :main s)
129 (void))
130 (void))
130
131
131 (defun main-pl (s)
132 (defun main-pl (s)
132 (api:add-text :main s)
133 (api:add-text :main s)
133 (api:newline :main)
134 (api:newline :main)
134 (void))
135 (void))
135
136
136 (defun main-nl (s)
137 (defun main-nl (s)
137 (api:newline :main)
138 (api:newline :main)
138 (api:add-text :main s)
139 (api:add-text :main s)
139 (void))
140 (void))
140
141
141 (defun maintxt (s)
142 (defun maintxt (s)
142 (api:get-text :main)
143 (api:get-text :main)
143 (void))
144 (void))
144
145
145 ;; For clarity (it leaves a lib.desc() call in JS)
146 (defun desc (s)
146 (defun desc (s)
147 "")
147 "")
148
148
149 (defun main-clear ()
149 (defun main-clear ()
150 (api:clear-text :main)
150 (api:clear-text :main)
151 (void))
151 (void))
152
152
153 ;;; 12stat
153 ;;; 12stat
154
154
155 (defun stat-p (s)
155 (defun stat-p (s)
156 (api:add-text :stat s)
156 (api:add-text :stat s)
157 (void))
157 (void))
158
158
159 (defun stat-pl (s)
159 (defun stat-pl (s)
160 (api:add-text :stat s)
160 (api:add-text :stat s)
161 (api:newline :stat)
161 (api:newline :stat)
162 (void))
162 (void))
163
163
164 (defun stat-nl (s)
164 (defun stat-nl (s)
165 (api:newline :stat)
165 (api:newline :stat)
166 (api:add-text :stat s)
166 (api:add-text :stat s)
167 (void))
167 (void))
168
168
169 (defun stattxt (s)
169 (defun stattxt (s)
170 (api:get-text :stat)
170 (api:get-text :stat)
171 (void))
171 (void))
172
172
173 (defun stat-clear ()
173 (defun stat-clear ()
174 (api:clear-text :stat)
174 (api:clear-text :stat)
175 (void))
175 (void))
176
176
177 (defun cls ()
177 (defun cls ()
178 (stat-clear)
178 (stat-clear)
179 (main-clear)
179 (main-clear)
180 (cla)
180 (cla)
181 (cmdclear)
181 (cmdclear)
182 (void))
182 (void))
183
183
184 ;;; 13diag
184 ;;; 13diag
185
185
186 ;;; 14act
186 ;;; 14act
187
187
188 (defun curacts ()
188 (defun curacts ()
189 (let ((acts (root acts)))
189 (let ((acts (root acts)))
190 (lambda ()
190 (lambda ()
191 (setf (root acts) acts)
191 (setf (root acts) acts)
192 (void))))
192 (void))))
193
193
194 ;;; 15objs
194 ;;; 15objs
195
195
196 (defun addobj (name)
196 (defun addobj (name img)
197 (chain (root objs) (push name))
197 (setf img (or img ""))
198 (setf (getprop (root objs) name)
199 (create :name name :img img :selected nil))
198 (api:update-objs)
200 (api:update-objs)
201 (api-call call-serv-loc "ONOBJADD" name img)
199 (void))
202 (void))
200
203
201 (defun delobj (name)
204 (defun delobj (name)
202 (let ((index (chain (root objs) (index-of name))))
205 (delete (getprop (root objs) name))
203 (when (> index -1)
206 (api-call call-serv-loc "ONOBJDEL" name)
204 (killobj (1+ index))))
205 (void))
207 (void))
206
208
207 (defun killobj (&optional (num nil))
209 (defun killobj (&optional (num nil))
208 (if (eq nil num)
210 (if (eq nil num)
209 (setf (root objs) (list))
211 (setf (root objs) (create))
210 (chain (root objs) (splice (1- num) 1)))
212 (delobj (elt (chain *object (keys (root objs))) num)))
211 (api:update-objs)
213 (api:update-objs)
212 (void))
214 (void))
213
215
216 (defun selobj ()
217 (loop :for (k v) :of (root objs)
218 :do (when (@ v :selected)
219 (return-from selobj (@ v :name)))))
220
214 ;;; 16menu
221 ;;; 16menu
215
222
216 (defun menu (menu-name)
223 (defun menu (menu-name)
217 (let ((menu-data (list)))
224 (let ((menu-data (list)))
218 (loop :for item-obj :in (@ (api:get-array (api:var-real-name menu-name)) values)
225 (loop :for item-obj :in (@ (api:get-array (api:var-real-name menu-name)) values)
219 :for item := (@ item-obj :str)
226 :for item := (@ item-obj :str)
220 :do (cond ((string= item "")
227 :do (cond ((string= item "")
221 (break))
228 (break))
222 ((string= item "-:-")
229 ((string= item "-:-")
223 (chain menu-data (push :delimiter)))
230 (chain menu-data (push :delimiter)))
224 (t
231 (t
225 (let* ((tokens (chain item (split ":"))))
232 (let* ((tokens (chain item (split ":"))))
226 (when (= (length tokens) 2)
233 (when (= (length tokens) 2)
227 (chain tokens (push "")))
234 (chain tokens (push "")))
228 (let* ((text (chain tokens (splice 0 (- (length tokens) 2)) (join ":")))
235 (let* ((text (chain tokens (splice 0 (- (length tokens) 2)) (join ":")))
229 (loc (getprop tokens (- (length tokens) 2)))
236 (loc (getprop tokens (- (length tokens) 2)))
230 (icon (getprop tokens (- (length tokens) 1))))
237 (icon (getprop tokens (- (length tokens) 1))))
231 (chain menu-data
238 (chain menu-data
232 (push (create :text text
239 (push (create :text text
233 :loc loc
240 :loc loc
234 :icon icon))))))))
241 :icon icon))))))))
235 (api:menu menu-data)
242 (api:menu menu-data)
236 (void)))
243 (void)))
237
244
238 ;;; 17sound
245 ;;; 17sound
239
246
240 (defun play (filename &optional (volume 100))
247 (defun play (filename &optional (volume 100))
241 (let ((audio (new (*audio filename))))
248 (let ((audio (new (*audio filename))))
242 (setf (getprop (root playing) filename) audio)
249 (setf (getprop (root playing) filename) audio)
243 (setf (@ audio volume) (* volume 0.01))
250 (setf (@ audio volume) (* volume 0.01))
244 (chain audio (play))))
251 (chain audio (play))))
245
252
246 (defun close (filename)
253 (defun close (filename)
247 (funcall (root playing filename) stop)
254 (funcall (root playing filename) stop)
248 (delete (root playing filename))
255 (delete (root playing filename))
249 (void))
256 (void))
250
257
251 (defun closeall ()
258 (defun closeall ()
252 (loop :for k :in (chain *object (keys (root playing)))
259 (loop :for k :in (chain *object (keys (root playing)))
253 :for v := (getprop (root playing) k)
260 :for v := (getprop (root playing) k)
254 :do (funcall v stop))
261 :do (funcall v stop))
255 (setf (root playing) (create)))
262 (setf (root playing) (create)))
256
263
257 ;;; 18img
264 ;;; 18img
258
265
259 (defun refint ()
266 (defun refint ()
260 ;; "Force interface update" Uh... what exactly do we do here?
267 ;; "Force interface update" Uh... what exactly do we do here?
261 (api:report-error "REFINT is not supported")
268 (api:report-error "REFINT is not supported")
262 )
269 )
263
270
264 ;;; 19input
271 ;;; 19input
265
272
266 (defun usertxt ()
273 (defun usertxt ()
267 (let ((input (by-id "qsp-input")))
274 (let ((input (by-id "qsp-input")))
268 (@ input value)))
275 (@ input value)))
269
276
270 (defun cmdclear ()
277 (defun cmdclear ()
271 (let ((input (by-id "qsp-input")))
278 (let ((input (by-id "qsp-input")))
272 (setf (@ input value) "")))
279 (setf (@ input value) "")))
273
280
274 (defun input (text)
281 (defun input (text)
275 (chain window (prompt text)))
282 (chain window (prompt text)))
276
283
277 ;;; 20time
284 ;;; 20time
278
285
279 (defun msecscount ()
286 (defun msecscount ()
280 (- (chain *date (now)) (root started-at)))
287 (- (chain *date (now)) (root started-at)))
281
288
282 ;;; 21local
289 ;;; 21local
283
290
284 ;;; 22for
291 ;;; 22for
285
292
286 ;;; misc
293 ;;; misc
287
294
288 (defun rgb (red green blue)
295 (defun rgb (red green blue)
289 (flet ((rgb-to-hex (comp)
296 (+ (<< red 16)
290 (let ((hex (chain (*number comp) (to-string 16))))
297 (<< green 8)
291 (if (< (length hex) 2)
298 blue))
292 (+ "0" hex)
293 hex))))
294 (+ "#" (rgb-to-hex red) (rgb-to-hex green) (rgb-to-hex red))))
295
299
296 (defun openqst (name)
300 (defun openqst (name)
297 (api-call run-game name))
301 (api-call run-game name))
298
302
299 (defun addqst (name)
303 (defun addqst (name)
300 (let ((game (api-call filename-game name)))
304 (let ((game (api-call filename-game name)))
301 ;; Add the game's locations
305 ;; Add the game's locations
302 (chain *object (assign (root locs)
306 (chain *object (assign (root locs)
303 (getprop (root games) name)))))
307 (getprop (root games) name)))))
304
308
305 (defun killqst ()
309 (defun killqst ()
306 ;; Delete all locations not from the current main game
310 ;; Delete all locations not from the current main game
307 (loop :for (k v) :in (root games)
311 (loop :for (k v) :in (root games)
308 :do (unless (string= k (root main-game))
312 :do (unless (string= k (root main-game))
309 (delete (getprop (root locs) k)))))
313 (delete (getprop (root locs) k)))))
310
314
@@ -1,41 +1,41 b''
1
1
2 (in-package sugar-qsp.js)
2 (in-package sugar-qsp.js)
3
3
4 ;;; Contains symbols from standard JS library to avoid obfuscating
4 ;;; Contains symbols from standard JS library to avoid obfuscating
5 ;;; and/or namespacing them
5 ;;; and/or namespacing them
6
6
7 (cl:defmacro syms (cl:&rest syms)
7 (cl:defmacro syms (cl:&rest syms)
8 `(cl:progn
8 `(cl:progn
9 ,@(cl:loop :for sym :in syms
9 ,@(cl:loop :for sym :in syms
10 :collect `(cl:export ',sym))))
10 :collect `(cl:export ',sym))))
11
11
12 (syms
12 (syms
13 ;; main
13 ;; main
14 window
14 window
15 *object
15 *object assign
16 now
16 now
17 onload
17 onload
18 keys includes
18 keys includes
19 has-own-property
19 has-own-property
20 ;; api
20 ;; api
21 document get-element-by-id
21 document get-element-by-id
22 onclick onchange
22 onclick onchange
23 atob btoa split
23 atob btoa split
24 alert prompt
24 alert prompt
25 set-timeout set-interval clear-interval
25 set-timeout set-interval clear-interval
26 *promise *j-s-o-n
26 *promise *j-s-o-n
27 href parse match
27 href parse match
28 set-prototype-of
28 set-prototype-of
29 body append-child remove-child
29 body append-child remove-child
30 add ; remove (is already in COMMON-LISP)
30 add ; remove (is already in COMMON-LISP)
31 create-element set-attribute class-list
31 create-element set-attribute class-list
32 *file-reader read-as-text
32 *file-reader read-as-text
33 style display src
33 style display src
34 page-x page-y
34 page-x page-y
35 top left
35 top left
36 ;; lib
36 ;; lib
37 *number parse-int
37 *number parse-int
38 to-string to-upper-case concat
38 to-string to-upper-case concat
39 click target current-target files index-of result
39 click target current-target files index-of result
40 decode-u-r-i-component splice
40 decode-u-r-i-component splice
41 )
41 )
@@ -1,51 +1,51 b''
1
1
2 (in-package sugar-qsp.main)
2 (in-package sugar-qsp.main)
3
3
4 (setf (root)
4 (setf (root)
5 (create
5 (create
6 ;;; Game session state (saved in savegames)
6 ;;; Game session state (saved in savegames)
7 ;; Variables
7 ;; Variables
8 vars (create)
8 vars (create)
9 ;; Inventory (objects)
9 ;; Inventory (objects)
10 objs (list)
10 objs (create)
11 current-location nil
11 current-location nil
12 ;; Game time
12 ;; Game time
13 started-at (chain *date (now))
13 started-at (chain *date (now))
14 ;; Timers
14 ;; Timers
15 timer-interval 500
15 timer-interval 500
16 timer-obj nil
16 timer-obj nil
17 ;; Games
17 ;; Games
18 loaded-games (list)
18 loaded-games (list)
19
19
20 ;;; Transient state
20 ;;; Transient state
21 ;; ACTions
21 ;; ACTions
22 acts (create)
22 acts (create)
23 ;; Savegame data
23 ;; Savegame data
24 state-stash (create)
24 state-stash (create)
25 ;; List of audio files being played
25 ;; List of audio files being played
26 playing (create)
26 playing (create)
27 ;; Local variables stack (starts with an empty frame)
27 ;; Local variables stack (starts with an empty frame)
28 locals (list)
28 locals (list)
29
29
30 ;;; Game data
30 ;;; Game data
31 ;; Games (filename -> [locations])
31 ;; Games (filename -> [locations])
32 games (list)
32 games (list)
33 ;; The main (non library) game. Updated by openqst
33 ;; The main (non library) game. Updated by openqst
34 main-game nil
34 main-game nil
35 ;; Active locations
35 ;; Active locations
36 locs (create)))
36 locs (create)))
37
37
38 ;; Launch the game from the first location
38 ;; Launch the game from the first location
39 (setf (@ window onload)
39 (setf (@ window onload)
40 (lambda ()
40 (lambda ()
41 (#.(intern "INIT-DOM" "SUGAR-QSP.API"))
41 (#.(intern "INIT-DOM" "SUGAR-QSP.API"))
42 ;; For MSECCOUNT
42 ;; For MSECCOUNT
43 (setf (root started-at) (chain *date (now)))
43 (setf (root started-at) (chain *date (now)))
44 ;; For $COUNTER and SETTIMER
44 ;; For $COUNTER and SETTIMER
45 (#.(intern "SET-TIMER" "SUGAR-QSP.API")
45 (#.(intern "SET-TIMER" "SUGAR-QSP.API")
46 (root timer-interval))
46 (root timer-interval))
47 ;; Start the first game
47 ;; Start the first game
48 (#.(intern "RUN-GAME" "SUGAR-QSP.API")
48 (#.(intern "RUN-GAME" "SUGAR-QSP.API")
49 (chain *object (keys (root games)) 0))
49 (chain *object (keys (root games)) 0))
50 (values)))
50 (values)))
51
51
@@ -1,172 +1,181 b''
1
1
2 (in-package sugar-qsp.lib)
2 (in-package sugar-qsp.lib)
3
3
4 ;;;; Parenscript macros which make the parser's intermediate
4 ;;;; Parenscript macros which make the parser's intermediate
5 ;;;; representation directly compilable by Parenscript
5 ;;;; representation directly compilable by Parenscript
6 ;;;; Some utility macros for other .ps sources too.
6 ;;;; Some utility macros for other .ps sources too.
7
7
8 ;;; Utils
8 ;;; Utils
9
9
10 ;;; Common
10 ;;; Common
11
11
12 (defpsmacro label-block (() &body body)
12 (defpsmacro label-block (() &body body)
13 (let ((has-labels (some #'keywordp body)))
13 (let ((has-labels (some #'keywordp body)))
14 `(block nil
14 `(block nil
15 ,@(when has-labels
15 ,@(when has-labels
16 '((defvar _labels)))
16 '((defvar _labels)))
17 (tagbody
17 (tagbody
18 ,@body
18 ,@body
19 (void)))))
19 (void)))))
20
20
21 (defpsmacro str (&rest forms)
21 (defpsmacro str (&rest forms)
22 (cond ((zerop (length forms))
22 (cond ((zerop (length forms))
23 "")
23 "")
24 ((and (= 1 (length forms))
24 ((and (= 1 (length forms))
25 (stringp (first forms)))
25 (stringp (first forms)))
26 (first forms))
26 (first forms))
27 (t
27 (t
28 `(& ,@forms))))
28 `(& ,@forms))))
29
29
30 ;;; 1loc
30 ;;; 1loc
31
31
32 (defpsmacro game ((name) &body body)
32 (defpsmacro game ((name) &body body)
33 `(progn
33 `(progn
34 (setf (root games ,name)
34 (setf (root games ,name)
35 (create))
35 (create))
36 ,@(loop :for location :in body
36 ,@(loop :for location :in body
37 :collect `(setf (root games ,name ,(caadr location))
37 :collect `(setf (root games ,name ,(caadr location))
38 ,location))))
38 ,location))))
39
39
40 (defpsmacro location ((name) &body body)
40 (defpsmacro location ((name) &body body)
41 (declare (ignore name))
41 (declare (ignore name))
42 "Name is used by the game macro above"
42 "Name is used by the game macro above"
43 `(async-lambda (args)
43 `(async-lambda ()
44 (label-block ()
44 (label-block ()
45 ,@body)))
45 ,@body)))
46
46
47 (defpsmacro goto% (target &rest args)
47 (defpsmacro goto% (target &rest args)
48 `(progn
48 `(progn
49 (goto ,target ,args)
49 (goto ,target ,args)
50 (exit)))
50 (exit)))
51
51
52 (defpsmacro xgoto% (target &rest args)
52 (defpsmacro xgoto% (target &rest args)
53 `(progn
53 `(progn
54 (xgoto ,target ,args)
54 (xgoto ,target ,args)
55 (exit)))
55 (exit)))
56
56
57 ;;; 2var
57 ;;; 2var
58
58
59 (defpsmacro qspvar (name index slot)
59 (defpsmacro qspvar (name index slot)
60 `(api-call get-var ,(string name) ,index ,slot))
60 `(api-call get-var ,(string name) ,index ,slot))
61
61
62 (defpsmacro set ((var vname vindex vslot) value)
62 (defpsmacro set ((var vname vindex vslot) value)
63 (assert (eq var 'qspvar))
63 (assert (eq var 'qspvar))
64 `(api-call set-var ,(string vname) ,vindex ,vslot ,value))
64 `(api-call set-var ,(string vname) ,vindex ,vslot ,value))
65
65
66 ;;; 3expr
66 ;;; 3expr
67
67
68 (defpsmacro <> (op1 op2)
68 (defpsmacro <> (op1 op2)
69 `(not (equal ,op1 ,op2)))
69 `(not (equal ,op1 ,op2)))
70
70
71 (defpsmacro ! (op1 op2)
71 (defpsmacro ! (op1 op2)
72 `(not (equal ,op1 ,op2)))
72 `(not (equal ,op1 ,op2)))
73
73
74 ;;; 4code
74 ;;; 4code
75
75
76 (defpsmacro exec (&body body)
76 (defpsmacro exec (&body body)
77 (format nil "javascript: ~{~A~^~%~}" (mapcar #'ps* body)))
77 (format nil "javascript: ~{~A~^~%~}" (mapcar #'ps* body)))
78
78
79 ;;; 5arrays
79 ;;; 5arrays
80
80
81 ;;; 6str
81 ;;; 6str
82
82
83 (defpsmacro & (&rest args)
83 (defpsmacro & (&rest args)
84 `(chain "" (concat ,@args)))
84 `(chain "" (concat ,@args)))
85
85
86 ;;; 7if
86 ;;; 7if
87
87
88 (defpsmacro qspcond (&rest clauses)
88 (defpsmacro qspcond (&rest clauses)
89 `(cond ,@(loop :for clause :in clauses
89 `(cond ,@(loop :for clause :in clauses
90 :collect (list (first clause)
90 :collect (list (first clause)
91 `(tagbody
91 `(tagbody
92 ,@(rest clause))))))
92 ,@(rest clause))))))
93
93
94 ;;; 8sub
94 ;;; 8sub
95
95
96 ;;; 9loops
96 ;;; 9loops
97 ;;; Yep, that's a huge kludge since Javascript doesn't support arbitrary labels
97 ;;; Yep, that's a huge kludge since Javascript doesn't support arbitrary labels
98
98
99 (defpsmacro jump (target)
99 (defpsmacro jump (target)
100 `(return-from label-body
100 `(return-from label-body
101 (funcall (getprop _labels ,(string-upcase (second target))))))
101 (funcall (getprop _labels ,(string-upcase (second target))))))
102
102
103 (defpsmacro tagbody (&body body)
103 (defpsmacro tagbody (&body body)
104 (let ((funcs (list nil "_nil")))
104 (let ((funcs (list nil "_nil")))
105 (dolist (form body)
105 (dolist (form body)
106 (cond ((keywordp form)
106 (cond ((keywordp form)
107 (setf (first funcs) (reverse (first funcs)))
107 (setf (first funcs) (reverse (first funcs)))
108 (push (string-upcase form) funcs)
108 (push (string-upcase form) funcs)
109 (push nil funcs))
109 (push nil funcs))
110 (t
110 (t
111 (push form (first funcs)))))
111 (push form (first funcs)))))
112 (setf (first funcs) (reverse (first funcs)))
112 (setf (first funcs) (reverse (first funcs)))
113 (setf funcs (reverse funcs))
113 (setf funcs (reverse funcs))
114 (if (= 2 (length funcs))
114 (if (= 2 (length funcs))
115 `(progn
115 `(progn
116 ,@body)
116 ,@body)
117 `(progn
117 `(progn
118 (setf ,@(loop :for (label code . rest-labels) :on funcs :by #'cddr
118 (setf ,@(loop :for (label code . rest-labels) :on funcs :by #'cddr
119 :append `((@ _labels ,label)
119 :append `((@ _labels ,label)
120 (block label-body
120 (block label-body
121 (block ,(intern label)
121 (block ,(intern label)
122 ,@code
122 ,@code
123 ,@(when rest-labels
123 ,@(when rest-labels
124 `((funcall
124 `((funcall
125 (getprop _labels ,(first rest-labels))))))))))
125 (getprop _labels ,(first rest-labels))))))))))
126 (funcall (getprop _labels "_nil"))))))
126 (funcall (getprop _labels "_nil"))))))
127
127
128 (defpsmacro exit ()
129 '(return-from nil (values)))
130
128 ;;; 10dynamic
131 ;;; 10dynamic
129
132
130 (defpsmacro qspblock (&body body)
133 (defpsmacro qspblock (&body body)
131 `(async-lambda (args)
134 `(async-lambda (args)
132 (label-block ()
135 (label-block ()
133 ,@body)))
136 ,@body)))
134
137
135 ;;; 11main
138 ;;; 11main
136
139
137 (defpsmacro act (name img &body body)
140 (defpsmacro act (name img &body body)
138 `(api-call add-act ,name ,img
141 `(api-call add-act ,name ,img
139 (async-lambda ()
142 (async-lambda ()
140 (label-block ()
143 (label-block ()
141 ,@body))))
144 ,@body))))
142
145
143 ;;; 12aux
146 ;;; 12aux
144
147
145 ;;; 13diag
148 ;;; 13diag
146
149
147 ;;; 14act
150 ;;; 14act
148
151
149 ;;; 15objs
152 ;;; 15objs
150
153
151 ;;; 16menu
154 ;;; 16menu
152
155
153 ;;; 17sound
156 ;;; 17sound
154
157
155 ;;; 18img
158 ;;; 18img
156
159
157 ;;; 19input
160 ;;; 19input
158
161
159 ;;; 20time
162 ;;; 20time
160
163
161 ;;; 21local
164 ;;; 21local
162
165
166 (defpsmacro local (var &optional expr)
167 `(progn
168 (api-call new-local ,(string (second var)))
169 ,@(when expr
170 `((set ,var ,expr)))))
171
163 ;;; 22for
172 ;;; 22for
164
173
165 (defpsmacro qspfor (var from to step &body body)
174 (defpsmacro qspfor (var from to step &body body)
166 `((intern "QSPFOR" "API")
175 `((intern "QSPFOR" "API")
167 ,(string (second var)) ,(third var) ;; name and index
176 ,(string (second var)) ,(third var) ;; name and index
168 ,from ,to ,step
177 ,from ,to ,step
169 (lambda ()
178 (lambda ()
170 (block nil
179 (block nil
171 ,@body
180 ,@body
172 t))))
181 t))))
@@ -1,19 +1,18 b''
1
1
2 (defsystem sugar-qsp
2 (defsystem sugar-qsp
3 :description "QSP compiler to monolithic HTML page"
3 :description "QSP compiler to monolithic HTML page"
4 :depends-on (:alexandria ;; General
4 :depends-on (:alexandria ;; General
5 :esrap ;; Parsing
5 :esrap ;; Parsing
6 :parenscript :flute ;; Codegening
6 :parenscript :flute ;; Codegening
7 )
7 )
8 :pathname "src/"
8 :pathname "src/"
9 :serial t
9 :serial t
10 :components ((:file "package")
10 :components ((:file "package")
11 (:file "patches")
11 (:file "patches")
12 (:file "js-syms")
12 (:file "js-syms")
13 (:file "main-macros")
13 (:file "main-macros")
14 (:file "ps-macros")
14 (:file "ps-macros")
15 (:file "api-macros")
15 (:file "api-macros")
16 (:file "intrinsic-macros")
17 (:file "class")
16 (:file "class")
18 (:file "main")
17 (:file "main")
19 (:file "parser")))
18 (:file "parser")))
General Comments 0
You need to be logged in to leave comments. Login now