##// END OF EJS Templates
Globals instead of ROOT object
naryl -
r39:7db3bdd1 default
parent child Browse files
Show More
@@ -1,481 +1,481 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='" (href-call call-act title) "' onmouseover='" (inline-call select-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='" (href-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)
23 (defun make-obj (title img selected)
24 (+ "<li onclick='" (inline-call select-obj title img) "'>"
24 (+ "<li onclick='" (inline-call select-obj title img) "'>"
25 "<a class='qsp-obj" (if selected " qsp-obj-selected" "") "'>"
25 "<a class='qsp-obj" (if selected " qsp-obj-selected" "") "'>"
26 (if img (+ "<img src='" img "'>") "")
26 (if img (+ "<img src='" img "'>") "")
27 title
27 title
28 "</a>"))
28 "</a>"))
29
29
30 (defun make-menu-delimiter ()
30 (defun make-menu-delimiter ()
31 "<hr>")
31 "<hr>")
32
32
33 (defun report-error (text)
33 (defun report-error (text)
34 (alert text))
34 (alert text))
35
35
36 (defun start-sleeping ()
36 (defun start-sleeping ()
37 (chain (by-id "qsp") class-list (add "disable")))
37 (chain (by-id "qsp") class-list (add "disable")))
38
38
39 (defun finish-sleeping ()
39 (defun finish-sleeping ()
40 (chain (by-id "qsp") class-list (remove "disable")))
40 (chain (by-id "qsp") class-list (remove "disable")))
41
41
42 (defun sleep (msec)
42 (defun sleep (msec)
43 (with-sleep (resume)
43 (with-sleep (resume)
44 (set-timeout resume msec)))
44 (set-timeout resume msec)))
45
45
46 (defun init-dom ()
46 (defun init-dom ()
47 ;; Save/load buttons
47 ;; Save/load buttons
48 (let ((btn (by-id "qsp-btn-save")))
48 (let ((btn (by-id "qsp-btn-save")))
49 (setf (@ btn onclick) savegame)
49 (setf (@ btn onclick) savegame)
50 (setf (@ btn href) "#"))
50 (setf (@ btn href) "#"))
51 (let ((btn (by-id "qsp-btn-open")))
51 (let ((btn (by-id "qsp-btn-open")))
52 (setf (@ btn onclick) opengame)
52 (setf (@ btn onclick) opengame)
53 (setf (@ btn href) "#"))
53 (setf (@ btn href) "#"))
54 ;; Close image on click
54 ;; Close image on click
55 (setf (@ (by-id "qsp-image-container") onclick)
55 (setf (@ (by-id "qsp-image-container") onclick)
56 show-image)
56 show-image)
57 ;; Enter in input field
57 ;; Enter in input field
58 (setf (@ (get-frame :input) onkeyup)
58 (setf (@ (get-frame :input) onkeyup)
59 on-input-key)
59 on-input-key)
60 ;; Close the dropdown on any click
60 ;; Close the dropdown on any click
61 (setf (@ window onclick)
61 (setf (@ window onclick)
62 (lambda (event)
62 (lambda (event)
63 (setf (@ window mouse)
63 (setf (@ window mouse)
64 (list (@ event page-x)
64 (list (@ event page-x)
65 (@ event page-y)))
65 (@ event page-y)))
66 (finish-menu nil))))
66 (finish-menu nil))))
67
67
68 (defun call-serv-loc (var-name &rest args)
68 (defun call-serv-loc (var-name &rest args)
69 (let ((loc-name (get-global var-name 0)))
69 (let ((loc-name (get-global var-name 0)))
70 (when loc-name
70 (when loc-name
71 (let ((loc (getprop (root locs) loc-name)))
71 (let ((loc (getprop *locs loc-name)))
72 (when loc
72 (when loc
73 (call-loc loc-name args))))))
73 (call-loc loc-name args))))))
74
74
75 (defun filename-game (filename)
75 (defun filename-game (filename)
76 (let ((game-name (chain filename (match "(.*/)?([^.]+)(\\.[a-zA-Z]+)?") 2))))
76 (let ((game-name (chain filename (match "(.*/)?([^.]+)(\\.[a-zA-Z]+)?") 2))))
77 (getprop (root games) game-name))
77 (getprop *games game-name))
78
78
79 (defun run-game (name)
79 (defun run-game (name)
80 (let ((game (filename-game name)))
80 (let ((game (filename-game name)))
81 (setf (root main-game) name)
81 (setf *main-game name)
82 ;; Replace locations with the new game's
82 ;; Replace locations with the new game's
83 (setf (root locs) game)
83 (setf *locs game)
84 (funcall (getprop game
84 (funcall (getprop game
85 (chain *object (keys game) 0))
85 (chain *object (keys game) 0))
86 (list))))
86 (list))))
87
87
88 ;;; Misc
88 ;;; Misc
89
89
90 (defun newline (key)
90 (defun newline (key)
91 (append-id (key-to-id key) "<br>" t))
91 (append-id (key-to-id key) "<br>" t))
92
92
93 (defun clear-id (id)
93 (defun clear-id (id)
94 (setf (inner-html (by-id id)) ""))
94 (setf (inner-html (by-id id)) ""))
95
95
96 (defun escape-html (text)
96 (defun escape-html (text)
97 (chain text
97 (chain text
98 (replace (regex "/&/g") "&amp;")
98 (replace (regex "/&/g") "&amp;")
99 (replace (regex "/</g") "&lt;")
99 (replace (regex "/</g") "&lt;")
100 (replace (regex "/>/g") "&gt;")
100 (replace (regex "/>/g") "&gt;")
101 (replace (regex "/\"/g") "&quot;")
101 (replace (regex "/\"/g") "&quot;")
102 (replace (regex "/'/g") "&apos;")))
102 (replace (regex "/'/g") "&apos;")))
103
103
104 (defun prepare-contents (s &optional force-html)
104 (defun prepare-contents (s &optional force-html)
105 (setf s (chain s (to-string)))
105 (setf s (chain s (to-string)))
106 (if (or force-html (get-global "USEHTML" 0))
106 (if (or force-html (get-global "USEHTML" 0))
107 s
107 s
108 (escape-html s)))
108 (escape-html s)))
109
109
110 (defun get-id (id &optional force-html)
110 (defun get-id (id &optional force-html)
111 (inner-html (by-id id)))
111 (inner-html (by-id id)))
112
112
113 (defun set-id (id contents &optional force-html)
113 (defun set-id (id contents &optional force-html)
114 (setf (inner-html (by-id id)) (prepare-contents contents force-html)))
114 (setf (inner-html (by-id id)) (prepare-contents contents force-html)))
115
115
116 (defun append-id (id contents &optional force-html)
116 (defun append-id (id contents &optional force-html)
117 (when contents
117 (when contents
118 (incf (inner-html (by-id id)) (prepare-contents contents force-html))))
118 (incf (inner-html (by-id id)) (prepare-contents contents force-html))))
119
119
120 (defun on-input-key (ev)
120 (defun on-input-key (ev)
121 (when (= 13 (@ ev key-code))
121 (when (= 13 (@ ev key-code))
122 (chain ev (prevent-default))
122 (chain ev (prevent-default))
123 (call-serv-loc "$USERCOM")))
123 (call-serv-loc "$USERCOM")))
124
124
125 ;;; Function calls
125 ;;; Function calls
126
126
127 (defun init-args (args)
127 (defun init-args (args)
128 (dotimes (i (length args))
128 (dotimes (i (length args))
129 (let ((arg (elt args i)))
129 (let ((arg (elt args i)))
130 (if (numberp arg)
130 (if (numberp arg)
131 (set-var args i :num arg)
131 (set-var args i :num arg)
132 (set-var args i :str arg)))))
132 (set-var args i :str arg)))))
133
133
134 (defun get-result ()
134 (defun get-result ()
135 (or (get-global "$RESULT" 0)
135 (or (get-global "$RESULT" 0)
136 (get-global "RESULT" 0)))
136 (get-global "RESULT" 0)))
137
137
138 (defun call-loc (name args)
138 (defun call-loc (name args)
139 (setf name (chain name (to-upper-case)))
139 (setf name (chain name (to-upper-case)))
140 (with-frame
140 (with-frame
141 (with-call-args args
141 (with-call-args args
142 (funcall (getprop (root locs) name)))))
142 (funcall (getprop *locs name)))))
143
143
144 (defun call-act (title)
144 (defun call-act (title)
145 (with-frame
145 (with-frame
146 (funcall (getprop (root acts) title :act))))
146 (funcall (getprop *acts title :act))))
147
147
148 ;;; Text windows
148 ;;; Text windows
149
149
150 (defun key-to-id (key)
150 (defun key-to-id (key)
151 (case key
151 (case key
152 (:all "qsp")
152 (:all "qsp")
153 (:main "qsp-main")
153 (:main "qsp-main")
154 (:stat "qsp-stat")
154 (:stat "qsp-stat")
155 (:objs "qsp-objs")
155 (:objs "qsp-objs")
156 (:acts "qsp-acts")
156 (:acts "qsp-acts")
157 (:input "qsp-input")
157 (:input "qsp-input")
158 (:image "qsp-image")
158 (:image "qsp-image")
159 (:dropdown "qsp-dropdown")
159 (:dropdown "qsp-dropdown")
160 (t (report-error "Internal error!"))))
160 (t (report-error "Internal error!"))))
161
161
162 (defun get-frame (key)
162 (defun get-frame (key)
163 (by-id (key-to-id key)))
163 (by-id (key-to-id key)))
164
164
165 (defun add-text (key text)
165 (defun add-text (key text)
166 (append-id (key-to-id key) text))
166 (append-id (key-to-id key) text))
167
167
168 (defun get-text (key)
168 (defun get-text (key)
169 (get-id (key-to-id key)))
169 (get-id (key-to-id key)))
170
170
171 (defun clear-text (key)
171 (defun clear-text (key)
172 (clear-id (key-to-id key)))
172 (clear-id (key-to-id key)))
173
173
174 (defun enable-frame (key enable)
174 (defun enable-frame (key enable)
175 (let ((obj (get-frame key)))
175 (let ((obj (get-frame key)))
176 (setf (@ obj style display) (if enable "block" "none"))
176 (setf (@ obj style display) (if enable "block" "none"))
177 (void)))
177 (void)))
178
178
179 ;;; Actions
179 ;;; Actions
180
180
181 (defun add-act (title img act)
181 (defun add-act (title img act)
182 (setf (getprop (root acts) title)
182 (setf (getprop *acts title)
183 (create :title title :img img :act act :selected nil))
183 (create :title title :img img :act act :selected nil))
184 (update-acts))
184 (update-acts))
185
185
186 (defun del-act (title)
186 (defun del-act (title)
187 (delete (getprop (root acts) title))
187 (delete (getprop *acts title))
188 (update-acts))
188 (update-acts))
189
189
190 (defun clear-act ()
190 (defun clear-act ()
191 (setf (root acts) (create))
191 (setf *acts (create))
192 (update-acts))
192 (update-acts))
193
193
194 (defun update-acts ()
194 (defun update-acts ()
195 (clear-id "qsp-acts")
195 (clear-id "qsp-acts")
196 (let ((elt (by-id "qsp-acts")))
196 (let ((elt (by-id "qsp-acts")))
197 (for-in (title (root acts))
197 (for-in (title *acts)
198 (let ((obj (getprop (root acts) title)))
198 (let ((obj (getprop *acts title)))
199 (incf (inner-html elt) (make-act-html title (getprop obj :img)))))))
199 (incf (inner-html elt) (make-act-html title (getprop obj :img)))))))
200
200
201 (defun select-act (title)
201 (defun select-act (title)
202 (loop :for (k v) :of (root acts)
202 (loop :for (k v) :of *acts
203 :do (setf (getprop v :selected) nil))
203 :do (setf (getprop v :selected) nil))
204 (setf (getprop (root acts) title :selected) t)
204 (setf (getprop *acts title :selected) t)
205 (call-serv-loc "$ONACTSEL"))
205 (call-serv-loc "$ONACTSEL"))
206
206
207 ;;; "Syntax"
207 ;;; "Syntax"
208
208
209 (defun qspfor (name index from to step body)
209 (defun qspfor (name index from to step body)
210 (for ((i from))
210 (for ((i from))
211 ((< i to))
211 ((< i to))
212 ((incf i step))
212 ((incf i step))
213 (set-var name index :num i)
213 (set-var name index :num i)
214 (unless (await (funcall body))
214 (unless (await (funcall body))
215 (return-from qspfor))))
215 (return-from qspfor))))
216
216
217 ;;; Variables
217 ;;; Variables
218
218
219 (defun new-var (slot &rest indexes)
219 (defun new-var (slot &rest indexes)
220 (let ((v (list)))
220 (let ((v (list)))
221 (dolist (index indexes)
221 (dolist (index indexes)
222 (setf (elt v index) (if (eq #\$ (elt slot 0)) "" 0)))
222 (setf (elt v index) (if (eq #\$ (elt slot 0)) "" 0)))
223 (setf (@ v :indexes) (create))
223 (setf (@ v :indexes) (create))
224 v))
224 v))
225
225
226 (defun set-str-element (slot index value)
226 (defun set-str-element (slot index value)
227 (if (in index (getprop slot :indexes))
227 (if (in index (getprop slot :indexes))
228 (setf (elt (getprop slot)
228 (setf (elt (getprop slot)
229 (getprop slot :indexes index))
229 (getprop slot :indexes index))
230 value)
230 value)
231 (progn
231 (progn
232 (chain slot (push value))
232 (chain slot (push value))
233 (setf (elt slot index)
233 (setf (elt slot index)
234 (length slot)))))
234 (length slot)))))
235
235
236 (defun set-any-element (slot index value)
236 (defun set-any-element (slot index value)
237 (if (numberp index)
237 (if (numberp index)
238 (setf (elt slot index) value)
238 (setf (elt slot index) value)
239 (set-str-element slot index value)))
239 (set-str-element slot index value)))
240
240
241 (defun get-element (slot index)
241 (defun get-element (slot index)
242 (if (numberp index)
242 (if (numberp index)
243 (elt slot index)
243 (elt slot index)
244 (elt slot (getprop slot :indexes index))))
244 (elt slot (getprop slot :indexes index))))
245
245
246 (defun get-global (name index)
246 (defun get-global (name index)
247 (elt (getprop (root vars) name) index))
247 (elt (getprop *globals name) index))
248
248
249 (defun kill-var (store name &optional index)
249 (defun kill-var (store name &optional index)
250 (setf name (chain name (to-upper-case)))
250 (setf name (chain name (to-upper-case)))
251 (if (and index (not (= 0 index)))
251 (if (and index (not (= 0 index)))
252 (chain (getprop (root vars) name) (kill index))
252 (chain (getprop *vars name) (kill index))
253 (delete (getprop (root vars) name)))
253 (delete (getprop *vars name)))
254 (void))
254 (void))
255
255
256 (defun array-size (name)
256 (defun array-size (name)
257 (@ (var-ref name) :values length))
257 (@ (var-ref name) :values length))
258
258
259 ;;; Locals
259 ;;; Locals
260
260
261 (defun push-local-frame ()
261 (defun push-local-frame ()
262 (chain (root locals) (push (create)))
262 (chain *locals (push (create)))
263 (void))
263 (void))
264
264
265 (defun pop-local-frame ()
265 (defun pop-local-frame ()
266 (chain (root locals) (pop))
266 (chain *locals (pop))
267 (void))
267 (void))
268
268
269 (defun current-local-frame ()
269 (defun current-local-frame ()
270 (elt (root locals) (1- (length (root locals)))))
270 (elt *locals (1- (length *locals))))
271
271
272 ;;; Objects
272 ;;; Objects
273
273
274 (defun select-obj (title img)
274 (defun select-obj (title img)
275 (loop :for (k v) :of (root objs)
275 (loop :for (k v) :of *objs
276 :do (setf (getprop v :selected) nil))
276 :do (setf (getprop v :selected) nil))
277 (setf (getprop (root objs) title :selected) t)
277 (setf (getprop *objs title :selected) t)
278 (call-serv-loc "$ONOBJSEL" title img))
278 (call-serv-loc "$ONOBJSEL" title img))
279
279
280 (defun update-objs ()
280 (defun update-objs ()
281 (let ((elt (by-id "qsp-objs")))
281 (let ((elt (by-id "qsp-objs")))
282 (setf (inner-html elt) "<ul>")
282 (setf (inner-html elt) "<ul>")
283 (loop :for (name obj) :of (root objs)
283 (loop :for (name obj) :of *objs
284 :do (incf (inner-html elt)
284 :do (incf (inner-html elt)
285 (make-obj name (@ obj :img) (@ obj :selected))))
285 (make-obj name (@ obj :img) (@ obj :selected))))
286 (incf (inner-html elt) "</ul>")))
286 (incf (inner-html elt) "</ul>")))
287
287
288 ;;; Menu
288 ;;; Menu
289
289
290 (defun open-menu (menu-data)
290 (defun open-menu (menu-data)
291 (let ((elt (get-frame :dropdown))
291 (let ((elt (get-frame :dropdown))
292 (i 0))
292 (i 0))
293 (loop :for item :in menu-data
293 (loop :for item :in menu-data
294 :do (incf i)
294 :do (incf i)
295 :do (incf (inner-html elt)
295 :do (incf (inner-html elt)
296 (if (eq item :delimiter)
296 (if (eq item :delimiter)
297 (make-menu-delimiter i)
297 (make-menu-delimiter i)
298 (make-menu-item-html i
298 (make-menu-item-html i
299 (@ item :text)
299 (@ item :text)
300 (@ item :icon)
300 (@ item :icon)
301 (@ item :loc)))))
301 (@ item :loc)))))
302 (let ((mouse (@ window mouse)))
302 (let ((mouse (@ window mouse)))
303 (setf (@ elt style left) (+ (elt mouse 0) "px"))
303 (setf (@ elt style left) (+ (elt mouse 0) "px"))
304 (setf (@ elt style top) (+ (elt mouse 1) "px"))
304 (setf (@ elt style top) (+ (elt mouse 1) "px"))
305 ;; Make sure it's inside the viewport
305 ;; Make sure it's inside the viewport
306 (when (> (@ document body inner-width)
306 (when (> (@ document body inner-width)
307 (+ (elt mouse 0) (@ elt inner-width)))
307 (+ (elt mouse 0) (@ elt inner-width)))
308 (incf (@ elt style left) (@ elt inner-width)))
308 (incf (@ elt style left) (@ elt inner-width)))
309 (when (> (@ document body inner-height)
309 (when (> (@ document body inner-height)
310 (+ (elt mouse 0) (@ elt inner-height)))
310 (+ (elt mouse 0) (@ elt inner-height)))
311 (incf (@ elt style top) (@ elt inner-height))))
311 (incf (@ elt style top) (@ elt inner-height))))
312 (setf (@ elt style display) "block")))
312 (setf (@ elt style display) "block")))
313
313
314 (defun finish-menu (loc)
314 (defun finish-menu (loc)
315 (when (root menu-resume)
315 (when *menu-resume
316 (let ((elt (get-frame :dropdown)))
316 (let ((elt (get-frame :dropdown)))
317 (setf (inner-html elt) "")
317 (setf (inner-html elt) "")
318 (setf (@ elt style display) "none")
318 (setf (@ elt style display) "none")
319 (funcall (root menu-resume))
319 (funcall *menu-resume)
320 (setf (root menu-resume) nil))
320 (setf *menu-resume nil))
321 (when loc
321 (when loc
322 (call-loc loc)))
322 (call-loc loc)))
323 (void))
323 (void))
324
324
325 (defun menu (menu-data)
325 (defun menu (menu-data)
326 (with-sleep (resume)
326 (with-sleep (resume)
327 (open-menu menu-data)
327 (open-menu menu-data)
328 (setf (root menu-resume) resume))
328 (setf *menu-resume resume))
329 (void))
329 (void))
330
330
331 ;;; Content
331 ;;; Content
332
332
333 (defun clean-audio ()
333 (defun clean-audio ()
334 (loop :for k :in (chain *object (keys (root playing)))
334 (loop :for k :in (chain *object (keys *playing))
335 :for v := (getprop (root playing) k)
335 :for v := (getprop *playing k)
336 :do (when (@ v ended)
336 :do (when (@ v ended)
337 (delete (@ (root playing) k)))))
337 (delete (@ *playing k)))))
338
338
339 (defun show-image (path)
339 (defun show-image (path)
340 (let ((img (get-frame :image)))
340 (let ((img (get-frame :image)))
341 (cond (path
341 (cond (path
342 (setf (@ img src) path)
342 (setf (@ img src) path)
343 (setf (@ img style display) "flex"))
343 (setf (@ img style display) "flex"))
344 (t
344 (t
345 (setf (@ img src) "")
345 (setf (@ img src) "")
346 (setf (@ img style display) "hidden")))))
346 (setf (@ img style display) "hidden")))))
347
347
348 (defun show-inline-images (frame-name images)
348 (defun show-inline-images (frame-name images)
349 (let ((frame (get-frame frame-name))
349 (let ((frame (get-frame frame-name))
350 (text ""))
350 (text ""))
351 (incf text "<div style='position:relative; display: inline-block'>")
351 (incf text "<div style='position:relative; display: inline-block'>")
352 (incf text (+ "<img src='" (@ images 0) "'>"))
352 (incf text (+ "<img src='" (@ images 0) "'>"))
353 (loop :for image :in (chain images (slice 1))
353 (loop :for image :in (chain images (slice 1))
354 :do (incf text
354 :do (incf text
355 (+ "<img style='position:absolute' src='" image "'>")))
355 (+ "<img style='position:absolute' src='" image "'>")))
356 (incf text "</div>")
356 (incf text "</div>")
357 (incf (inner-html frame) text)))
357 (incf (inner-html frame) text)))
358
358
359 (defun rgb-string (rgb)
359 (defun rgb-string (rgb)
360 (let ((red (ps::>> rgb 16))
360 (let ((red (ps::>> rgb 16))
361 (green (logand (ps::>> rgb 8) 255))
361 (green (logand (ps::>> rgb 8) 255))
362 (blue (logand rgb 255)))
362 (blue (logand rgb 255)))
363 (flet ((rgb-to-hex (comp)
363 (flet ((rgb-to-hex (comp)
364 (let ((hex (chain (*number comp) (to-string 16))))
364 (let ((hex (chain (*number comp) (to-string 16))))
365 (if (< (length hex) 2)
365 (if (< (length hex) 2)
366 (+ "0" hex)
366 (+ "0" hex)
367 hex))))
367 hex))))
368 (+ "#" (rgb-to-hex red) (rgb-to-hex green) (rgb-to-hex red)))))
368 (+ "#" (rgb-to-hex red) (rgb-to-hex green) (rgb-to-hex red)))))
369
369
370 ;;; Saves
370 ;;; Saves
371
371
372 (defun opengame ()
372 (defun opengame ()
373 (let ((element (chain document (create-element :input))))
373 (let ((element (chain document (create-element :input))))
374 (chain element (set-attribute :type :file))
374 (chain element (set-attribute :type :file))
375 (chain element (set-attribute :id :qsp-opengame))
375 (chain element (set-attribute :id :qsp-opengame))
376 (chain element (set-attribute :tabindex -1))
376 (chain element (set-attribute :tabindex -1))
377 (chain element (set-attribute "aria-hidden" t))
377 (chain element (set-attribute "aria-hidden" t))
378 (setf (@ element style display) :block)
378 (setf (@ element style display) :block)
379 (setf (@ element style visibility) :hidden)
379 (setf (@ element style visibility) :hidden)
380 (setf (@ element style position) :fixed)
380 (setf (@ element style position) :fixed)
381 (setf (@ element onchange)
381 (setf (@ element onchange)
382 (lambda (event)
382 (lambda (event)
383 (let* ((file (@ event target files 0))
383 (let* ((file (@ event target files 0))
384 (reader (new (*file-reader))))
384 (reader (new (*file-reader))))
385 (setf (@ reader onload)
385 (setf (@ reader onload)
386 (lambda (ev)
386 (lambda (ev)
387 (block nil
387 (block nil
388 (let ((target (@ ev current-target)))
388 (let ((target (@ ev current-target)))
389 (unless (@ target result)
389 (unless (@ target result)
390 (return))
390 (return))
391 (base64-to-state (@ target result))
391 (base64-to-state (@ target result))
392 (unstash-state)))))
392 (unstash-state)))))
393 (chain reader (read-as-text file)))))
393 (chain reader (read-as-text file)))))
394 (chain document body (append-child element))
394 (chain document body (append-child element))
395 (chain element (click))
395 (chain element (click))
396 (chain document body (remove-child element))))
396 (chain document body (remove-child element))))
397
397
398 (defun savegame ()
398 (defun savegame ()
399 (let ((element (chain document (create-element :a))))
399 (let ((element (chain document (create-element :a))))
400 (chain element (set-attribute :href (+ "data:text/plain;charset=utf-8," (state-to-base64))))
400 (chain element (set-attribute :href (+ "data:text/plain;charset=utf-8," (state-to-base64))))
401 (chain element (set-attribute :download "savegame.sav"))
401 (chain element (set-attribute :download "savegame.sav"))
402 (setf (@ element style display) :none)
402 (setf (@ element style display) :none)
403 (chain document body (append-child element))
403 (chain document body (append-child element))
404 (chain element (click))
404 (chain element (click))
405 (chain document body (remove-child element))))
405 (chain document body (remove-child element))))
406
406
407 (defun stash-state (args)
407 (defun stash-state (args)
408 (call-serv-loc "$ONGSAVE")
408 (call-serv-loc "$ONGSAVE")
409 (setf (root state-stash)
409 (setf *state-stash
410 (chain *j-s-o-n (stringify
410 (chain *j-s-o-n (stringify
411 (create :vars (root vars)
411 (create :vars *vars
412 :objs (root objs)
412 :objs *objs
413 :loc-args args
413 :loc-args args
414 :msecs (- (chain *date (now)) (root started-at))
414 :msecs (- (chain *date (now)) *started-at)
415 :timer-interval (root timer-interval)
415 :timer-interval *timer-interval
416 :main-html (inner-html
416 :main-html (inner-html
417 (get-frame :main))
417 (get-frame :main))
418 :stat-html (inner-html
418 :stat-html (inner-html
419 (get-frame :stat))
419 (get-frame :stat))
420 :next-location (root current-location)))))
420 :next-location *current-location))))
421 (void))
421 (void))
422
422
423 (defun unstash-state ()
423 (defun unstash-state ()
424 (let ((data (chain *j-s-o-n (parse (root state-stash)))))
424 (let ((data (chain *j-s-o-n (parse *state-stash))))
425 (clear-act)
425 (clear-act)
426 (setf (root vars) (@ data :vars))
426 (setf *vars (@ data :vars))
427 (loop :for k :in (chain *object (keys (root vars)))
427 (loop :for k :in (chain *object (keys *vars))
428 :do (chain *object (set-prototype-of (getprop (root vars) k)
428 :do (chain *object (set-prototype-of (getprop *vars k)
429 (@ *var prototype))))
429 (@ *var prototype))))
430 (setf (root started-at) (- (chain *date (now)) (@ data :msecs)))
430 (setf *started-at (- (chain *date (now)) (@ data :msecs)))
431 (setf (root objs) (@ data :objs))
431 (setf *objs (@ data :objs))
432 (setf (root current-location) (@ data :next-location))
432 (setf *current-location (@ data :next-location))
433 (setf (inner-html (get-frame :main))
433 (setf (inner-html (get-frame :main))
434 (@ data :main-html))
434 (@ data :main-html))
435 (setf (inner-html (get-frame :stat))
435 (setf (inner-html (get-frame :stat))
436 (@ data :stat-html))
436 (@ data :stat-html))
437 (update-objs)
437 (update-objs)
438 (set-timer (@ data :timer-interval))
438 (set-timer (@ data :timer-interval))
439 (call-serv-loc "$ONGLOAD")
439 (call-serv-loc "$ONGLOAD")
440 (call-loc (root current-location) (@ data :loc-args))
440 (call-loc *current-location (@ data :loc-args))
441 (void)))
441 (void)))
442
442
443 (defun state-to-base64 ()
443 (defun state-to-base64 ()
444 (btoa (encode-u-r-i-component (root state-stash))))
444 (btoa (encode-u-r-i-component *state-stash)))
445
445
446 (defun base64-to-state (data)
446 (defun base64-to-state (data)
447 (setf (root state-stash) (decode-u-r-i-component (atob data))))
447 (setf *state-stash (decode-u-r-i-component (atob data))))
448
448
449 ;;; Timers
449 ;;; Timers
450
450
451 (defun set-timer (interval)
451 (defun set-timer (interval)
452 (setf (root timer-interval) interval)
452 (setf *timer-interval interval)
453 (clear-interval (root timer-obj))
453 (clear-interval *timer-obj)
454 (setf (root timer-obj)
454 (setf *timer-obj
455 (set-interval
455 (set-interval
456 (lambda ()
456 (lambda ()
457 (call-serv-loc "$COUNTER"))
457 (call-serv-loc "$COUNTER"))
458 interval)))
458 interval)))
459
459
460 ;;; Special variables
460 ;;; Special variables
461
461
462 (defvar serv-vars (create))
462 (defvar serv-vars (create))
463
463
464 (define-serv-var backimage (:str path)
464 (define-serv-var backimage (:str path)
465 (setf (@ (get-frame :main) style background-image) path))
465 (setf (@ (get-frame :main) style background-image) path))
466
466
467 (define-serv-var bcolor (:num color)
467 (define-serv-var bcolor (:num color)
468 (setf (@ (get-frame :all) style background-color) (rgb-string color)))
468 (setf (@ (get-frame :all) style background-color) (rgb-string color)))
469
469
470 (define-serv-var fcolor (:num color)
470 (define-serv-var fcolor (:num color)
471 (setf (@ (get-frame :all) style color) (rgb-string color)))
471 (setf (@ (get-frame :all) style color) (rgb-string color)))
472
472
473 (define-serv-var lcolor (:num color)
473 (define-serv-var lcolor (:num color)
474 (setf (@ (get-frame :style) inner-text)
474 (setf (@ (get-frame :style) inner-text)
475 (+ "a { color: " (rgb-string color) ";}")))
475 (+ "a { color: " (rgb-string color) ";}")))
476
476
477 (define-serv-var fsize (:num size)
477 (define-serv-var fsize (:num size)
478 (setf (@ (get-frame :all) style font-size) size))
478 (setf (@ (get-frame :all) style font-size) size))
479
479
480 (define-serv-var fname (:str font-name)
480 (define-serv-var fname (:str font-name)
481 (setf (@ (get-frame :all) style font-family) (+ font-name ",serif")))
481 (setf (@ (get-frame :all) style font-family) (+ font-name ",serif")))
@@ -1,174 +1,174 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 `(in ,name (root objs)))
20 `(in ,name objs))
21
21
22 (defpsmacro loc (name)
22 (defpsmacro loc (name)
23 `(in ,name (root locs)))
23 `(in ,name locs))
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 `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 objs))
127
127
128 (defpsmacro getobj (index)
128 (defpsmacro getobj (index)
129 `(or (elt (root objs) ,index) ""))
129 `(or (elt 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 (@ 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 (defpsmacro img (&rest images)
143 (defpsmacro img (&rest images)
144 `(api-call show-inline-images :stat (list ,@images)))
144 `(api-call show-inline-images :stat (list ,@images)))
145
145
146 (defpsmacro *img (&rest images)
146 (defpsmacro *img (&rest images)
147 `(api-call show-inline-images :main (list ,@images)))
147 `(api-call show-inline-images :main (list ,@images)))
148
148
149 ;;; 19input
149 ;;; 19input
150
150
151 (defpsmacro showinput (enable)
151 (defpsmacro showinput (enable)
152 `(api-call enable-frame :input ,enable))
152 `(api-call enable-frame :input ,enable))
153
153
154 ;;; 20time
154 ;;; 20time
155
155
156 (defpsmacro wait (msec)
156 (defpsmacro wait (msec)
157 `(await (api-call sleep ,msec)))
157 `(await (api-call sleep ,msec)))
158
158
159 (defpsmacro settimer (interval)
159 (defpsmacro settimer (interval)
160 `(api-call set-timer ,interval))
160 `(api-call set-timer ,interval))
161
161
162 ;;; 21local
162 ;;; 21local
163
163
164 ;;; 22for
164 ;;; 22for
165
165
166 ;;; misc
166 ;;; misc
167
167
168 (defpsmacro opengame (&optional filename)
168 (defpsmacro opengame (&optional filename)
169 (declare (ignore filename))
169 (declare (ignore filename))
170 `(api-call opengame))
170 `(api-call opengame))
171
171
172 (defpsmacro savegame (&optional filename)
172 (defpsmacro savegame (&optional filename)
173 (declare (ignore filename))
173 (declare (ignore filename))
174 `(api-call savegame))
174 `(api-call savegame))
@@ -1,314 +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 *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 *current-location args)
21 (api:call-serv-loc "ONNEWLOC")
21 (api:call-serv-loc "ONNEWLOC")
22 (void))
22 (void))
23
23
24 ;;; 2var
24 ;;; 2var
25
25
26 ;;; 3expr
26 ;;; 3expr
27
27
28 ;;; 4code
28 ;;; 4code
29
29
30 (defun rand (a &optional (b 1))
30 (defun rand (a &optional (b 1))
31 (let ((min (min a b))
31 (let ((min (min a b))
32 (max (max a b)))
32 (max (max a b)))
33 (+ min (chain *math (random (- max min))))))
33 (+ min (chain *math (random (- max min))))))
34
34
35 ;;; 5arrays
35 ;;; 5arrays
36
36
37 (defun copyarr (to from start count)
37 (defun copyarr (to from start count)
38 (multiple-value-bind (to-name to-slot)
38 (multiple-value-bind (to-name to-slot)
39 (api:var-real-name to)
39 (api:var-real-name to)
40 (multiple-value-bind (from-name from-slot)
40 (multiple-value-bind (from-name from-slot)
41 (api:var-real-name from)
41 (api:var-real-name from)
42 (for ((i start))
42 (for ((i start))
43 ((< i (min (api:array-size from-name)
43 ((< i (min (api:array-size from-name)
44 (+ start count))))
44 (+ start count))))
45 ((incf i))
45 ((incf i))
46 (api:set-var to-name (+ start i) to-slot
46 (api:set-var to-name (+ start i) to-slot
47 (api:get-var from-name (+ start i) from-slot))))))
47 (api:get-var from-name (+ start i) from-slot))))))
48
48
49 (defun arrpos (name value &optional (start 0))
49 (defun arrpos (name value &optional (start 0))
50 (multiple-value-bind (real-name slot)
50 (multiple-value-bind (real-name slot)
51 (api:var-real-name name)
51 (api:var-real-name name)
52 (for ((i start)) ((< i (api:array-size name))) ((incf i))
52 (for ((i start)) ((< i (api:array-size name))) ((incf i))
53 (when (eq (api:get-var real-name i slot) value)
53 (when (eq (api:get-var real-name i slot) value)
54 (return-from arrpos i))))
54 (return-from arrpos i))))
55 -1)
55 -1)
56
56
57 (defun arrcomp (name pattern &optional (start 0))
57 (defun arrcomp (name pattern &optional (start 0))
58 (multiple-value-bind (real-name slot)
58 (multiple-value-bind (real-name slot)
59 (api:var-real-name name)
59 (api:var-real-name name)
60 (for ((i start)) ((< i (api:array-size name))) ((incf i))
60 (for ((i start)) ((< i (api:array-size name))) ((incf i))
61 (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)
62 (return-from arrcomp i))))
62 (return-from arrcomp i))))
63 -1)
63 -1)
64
64
65 ;;; 6str
65 ;;; 6str
66
66
67 (defun instr (s subs &optional (start 1))
67 (defun instr (s subs &optional (start 1))
68 (+ start (chain s (substring (- start 1)) (search subs))))
68 (+ start (chain s (substring (- start 1)) (search subs))))
69
69
70 (defun isnum (s)
70 (defun isnum (s)
71 (if (is-na-n s)
71 (if (is-na-n s)
72 0
72 0
73 -1))
73 -1))
74
74
75 (defun strcomp (s pattern)
75 (defun strcomp (s pattern)
76 (if (chain s (match pattern))
76 (if (chain s (match pattern))
77 -1
77 -1
78 0))
78 0))
79
79
80 (defun strfind (s pattern group)
80 (defun strfind (s pattern group)
81 (let* ((re (new (*reg-exp pattern)))
81 (let* ((re (new (*reg-exp pattern)))
82 (match (chain re (exec s))))
82 (match (chain re (exec s))))
83 (chain match (group group))))
83 (chain match (group group))))
84
84
85 (defun strpos (s pattern &optional (group 0))
85 (defun strpos (s pattern &optional (group 0))
86 (let* ((re (new (*reg-exp pattern)))
86 (let* ((re (new (*reg-exp pattern)))
87 (match (chain re (exec s)))
87 (match (chain re (exec s)))
88 (found (chain match (group group))))
88 (found (chain match (group group))))
89 (if found
89 (if found
90 (chain s (search found))
90 (chain s (search found))
91 0)))
91 0)))
92
92
93 ;;; 7if
93 ;;; 7if
94
94
95 ;; 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
96 ;; arguments
96 ;; arguments
97 (defun iif (cond-expr then-expr else-expr)
97 (defun iif (cond-expr then-expr else-expr)
98 (if cond-expr then-expr else-expr))
98 (if cond-expr then-expr else-expr))
99
99
100 ;;; 8sub
100 ;;; 8sub
101
101
102 (defun gosub (target &rest args)
102 (defun gosub (target &rest args)
103 (api:call-loc target args)
103 (api:call-loc target args)
104 (void))
104 (void))
105
105
106 (defun func (target &rest args)
106 (defun func (target &rest args)
107 (api:call-loc target args))
107 (api:call-loc target args))
108
108
109 ;;; 9loops
109 ;;; 9loops
110
110
111 ;;; 10dynamic
111 ;;; 10dynamic
112
112
113 (defun dynamic (block &rest args)
113 (defun dynamic (block &rest args)
114 (when (stringp block)
114 (when (stringp block)
115 (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."))
116 (api:with-call-args args
116 (api:with-call-args args
117 (funcall block args))
117 (funcall block args))
118 (void))
118 (void))
119
119
120 (defun dyneval (block &rest args)
120 (defun dyneval (block &rest args)
121 (when (stringp block)
121 (when (stringp block)
122 (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."))
123 (api:with-call-args args
123 (api:with-call-args args
124 (funcall block args)))
124 (funcall block args)))
125
125
126 ;;; 11main
126 ;;; 11main
127
127
128 (defun main-p (s)
128 (defun main-p (s)
129 (api:add-text :main s)
129 (api:add-text :main s)
130 (void))
130 (void))
131
131
132 (defun main-pl (s)
132 (defun main-pl (s)
133 (api:add-text :main s)
133 (api:add-text :main s)
134 (api:newline :main)
134 (api:newline :main)
135 (void))
135 (void))
136
136
137 (defun main-nl (s)
137 (defun main-nl (s)
138 (api:newline :main)
138 (api:newline :main)
139 (api:add-text :main s)
139 (api:add-text :main s)
140 (void))
140 (void))
141
141
142 (defun maintxt (s)
142 (defun maintxt (s)
143 (api:get-text :main)
143 (api:get-text :main)
144 (void))
144 (void))
145
145
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 *acts))
190 (lambda ()
190 (lambda ()
191 (setf (root acts) acts)
191 (setf *acts acts)
192 (void))))
192 (void))))
193
193
194 ;;; 15objs
194 ;;; 15objs
195
195
196 (defun addobj (name img)
196 (defun addobj (name img)
197 (setf img (or img ""))
197 (setf img (or img ""))
198 (setf (getprop (root objs) name)
198 (setf (getprop *objs name)
199 (create :name name :img img :selected nil))
199 (create :name name :img img :selected nil))
200 (api:update-objs)
200 (api:update-objs)
201 (api-call call-serv-loc "ONOBJADD" name img)
201 (api-call call-serv-loc "ONOBJADD" name img)
202 (void))
202 (void))
203
203
204 (defun delobj (name)
204 (defun delobj (name)
205 (delete (getprop (root objs) name))
205 (delete (getprop *objs name))
206 (api-call call-serv-loc "ONOBJDEL" name)
206 (api-call call-serv-loc "ONOBJDEL" name)
207 (void))
207 (void))
208
208
209 (defun killobj (&optional (num nil))
209 (defun killobj (&optional (num nil))
210 (if (eq nil num)
210 (if (eq nil num)
211 (setf (root objs) (create))
211 (setf *objs (create))
212 (delobj (elt (chain *object (keys (root objs))) num)))
212 (delobj (elt (chain *object (keys *objs)) num)))
213 (api:update-objs)
213 (api:update-objs)
214 (void))
214 (void))
215
215
216 (defun selobj ()
216 (defun selobj ()
217 (loop :for (k v) :of (root objs)
217 (loop :for (k v) :of *objs
218 :do (when (@ v :selected)
218 :do (when (@ v :selected)
219 (return-from selobj (@ v :name)))))
219 (return-from selobj (@ v :name)))))
220
220
221 ;;; 16menu
221 ;;; 16menu
222
222
223 (defun menu (menu-name)
223 (defun menu (menu-name)
224 (let ((menu-data (list)))
224 (let ((menu-data (list)))
225 (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)
226 :for item := (@ item-obj :str)
226 :for item := (@ item-obj :str)
227 :do (cond ((string= item "")
227 :do (cond ((string= item "")
228 (break))
228 (break))
229 ((string= item "-:-")
229 ((string= item "-:-")
230 (chain menu-data (push :delimiter)))
230 (chain menu-data (push :delimiter)))
231 (t
231 (t
232 (let* ((tokens (chain item (split ":"))))
232 (let* ((tokens (chain item (split ":"))))
233 (when (= (length tokens) 2)
233 (when (= (length tokens) 2)
234 (chain tokens (push "")))
234 (chain tokens (push "")))
235 (let* ((text (chain tokens (splice 0 (- (length tokens) 2)) (join ":")))
235 (let* ((text (chain tokens (splice 0 (- (length tokens) 2)) (join ":")))
236 (loc (getprop tokens (- (length tokens) 2)))
236 (loc (getprop tokens (- (length tokens) 2)))
237 (icon (getprop tokens (- (length tokens) 1))))
237 (icon (getprop tokens (- (length tokens) 1))))
238 (chain menu-data
238 (chain menu-data
239 (push (create :text text
239 (push (create :text text
240 :loc loc
240 :loc loc
241 :icon icon))))))))
241 :icon icon))))))))
242 (api:menu menu-data)
242 (api:menu menu-data)
243 (void)))
243 (void)))
244
244
245 ;;; 17sound
245 ;;; 17sound
246
246
247 (defun play (filename &optional (volume 100))
247 (defun play (filename &optional (volume 100))
248 (let ((audio (new (*audio filename))))
248 (let ((audio (new (*audio filename))))
249 (setf (getprop (root playing) filename) audio)
249 (setf (getprop *playing filename) audio)
250 (setf (@ audio volume) (* volume 0.01))
250 (setf (@ audio volume) (* volume 0.01))
251 (chain audio (play))))
251 (chain audio (play))))
252
252
253 (defun close (filename)
253 (defun close (filename)
254 (funcall (root playing filename) stop)
254 (funcall (getprop *playing filename) stop)
255 (delete (root playing filename))
255 (delete (getprop *playing filename))
256 (void))
256 (void))
257
257
258 (defun closeall ()
258 (defun closeall ()
259 (loop :for k :in (chain *object (keys (root playing)))
259 (loop :for k :in (chain *object (keys *playing))
260 :for v := (getprop (root playing) k)
260 :for v := (getprop *playing k)
261 :do (funcall v stop))
261 :do (funcall v stop))
262 (setf (root playing) (create)))
262 (setf *playing (create)))
263
263
264 ;;; 18img
264 ;;; 18img
265
265
266 (defun refint ()
266 (defun refint ()
267 ;; "Force interface update" Uh... what exactly do we do here?
267 ;; "Force interface update" Uh... what exactly do we do here?
268 ;(api:report-error "REFINT is not supported")
268 ;(api:report-error "REFINT is not supported")
269 )
269 )
270
270
271 ;;; 19input
271 ;;; 19input
272
272
273 (defun usertxt ()
273 (defun usertxt ()
274 (let ((input (by-id "qsp-input")))
274 (let ((input (by-id "qsp-input")))
275 (@ input value)))
275 (@ input value)))
276
276
277 (defun cmdclear ()
277 (defun cmdclear ()
278 (let ((input (by-id "qsp-input")))
278 (let ((input (by-id "qsp-input")))
279 (setf (@ input value) "")))
279 (setf (@ input value) "")))
280
280
281 (defun input (text)
281 (defun input (text)
282 (chain window (prompt text)))
282 (chain window (prompt text)))
283
283
284 ;;; 20time
284 ;;; 20time
285
285
286 (defun msecscount ()
286 (defun msecscount ()
287 (- (chain *date (now)) (root started-at)))
287 (- (chain *date (now)) *started-at))
288
288
289 ;;; 21local
289 ;;; 21local
290
290
291 ;;; 22for
291 ;;; 22for
292
292
293 ;;; misc
293 ;;; misc
294
294
295 (defun rgb (red green blue)
295 (defun rgb (red green blue)
296 (+ (<< red 16)
296 (+ (<< red 16)
297 (<< green 8)
297 (<< green 8)
298 blue))
298 blue))
299
299
300 (defun openqst (name)
300 (defun openqst (name)
301 (api-call run-game name))
301 (api-call run-game name))
302
302
303 (defun addqst (name)
303 (defun addqst (name)
304 (let ((game (api-call filename-game name)))
304 (let ((game (api-call filename-game name)))
305 ;; Add the game's locations
305 ;; Add the game's locations
306 (chain *object (assign (root locs)
306 (chain *object (assign *locs
307 (getprop (root games) name)))))
307 (getprop *games name)))))
308
308
309 (defun killqst ()
309 (defun killqst ()
310 ;; Delete all locations not from the current main game
310 ;; Delete all locations not from the current main game
311 (loop :for (k v) :in (root games)
311 (loop :for (k v) :in *games
312 :do (unless (string= k (root main-game))
312 :do (unless (string= k *main-game)
313 (delete (getprop (root locs) k)))))
313 (delete (getprop *locs k)))))
314
314
@@ -1,15 +1,12 b''
1
1
2 (in-package sugar-qsp.main)
2 (in-package sugar-qsp.main)
3
3
4
4
5 (defpsmacro by-id (id)
5 (defpsmacro by-id (id)
6 `(chain document (get-element-by-id ,id)))
6 `(chain document (get-element-by-id ,id)))
7
7
8 (defmacro+ps api-call (name &rest args)
8 (defmacro+ps api-call (name &rest args)
9 `(,(intern (string-upcase name) "API") ,@args))
9 `(,(intern (string-upcase name) "API") ,@args))
10
10
11 (defpsmacro root (&rest path)
12 `(@ data ,@path))
13
14 (defpsmacro in (key obj)
11 (defpsmacro in (key obj)
15 `(chain ,obj (has-own-property ,key)))
12 `(chain ,obj (has-own-property ,key)))
@@ -1,51 +1,48 b''
1
1
2 (in-package sugar-qsp.main)
2 (in-package sugar-qsp.main)
3
3
4 (setf (root)
4 ;;; Game session state (saved in savegames)
5 (create
5 ;; Variables
6 ;;; Game session state (saved in savegames)
6 (var *globals (create))
7 ;; Variables
7 ;; Inventory (objects)
8 vars (create)
8 (var *objs (create))
9 ;; Inventory (objects)
9 (var *current-location nil)
10 objs (create)
10 ;; Game time
11 current-location nil
11 (var *started-at (chain *date (now)))
12 ;; Game time
12 ;; Timers
13 started-at (chain *date (now))
13 (var *timer-interval 500)
14 ;; Timers
14 (var *timer-obj nil)
15 timer-interval 500
15 ;; Games
16 timer-obj nil
16 (var *loaded-games (list))
17 ;; Games
18 loaded-games (list)
19
17
20 ;;; Transient state
18 ;;; Transient state
21 ;; ACTions
19 ;; ACTions
22 acts (create)
20 (var *acts (create))
23 ;; Savegame data
21 ;; Savegame data
24 state-stash (create)
22 (var *state-stash (create))
25 ;; List of audio files being played
23 ;; List of audio files being played
26 playing (create)
24 (var *playing (create))
27 ;; Local variables stack (starts with an empty frame)
25 ;; Local variables stack (starts with an empty frame)
28 locals (list)
26 (var *locals (list))
29
27
30 ;;; Game data
28 ;;; Game data
31 ;; Games (filename -> [locations])
29 ;; Games (filename -> [locations])
32 games (list)
30 (var *games (list))
33 ;; The main (non library) game. Updated by openqst
31 ;; The main (non library) game. Updated by openqst
34 main-game nil
32 (var *main-game nil)
35 ;; Active locations
33 ;; Active locations
36 locs (create)))
34 (var *locs (create))
37
35
38 ;; Launch the game from the first location
36 ;; Launch the game from the first location
39 (setf (@ window onload)
37 (setf (@ window onload)
40 (lambda ()
38 (lambda ()
41 (#.(intern "INIT-DOM" "SUGAR-QSP.API"))
39 (#.(intern "INIT-DOM" "SUGAR-QSP.API"))
42 ;; For MSECCOUNT
40 ;; For MSECCOUNT
43 (setf (root started-at) (chain *date (now)))
41 (setf *started-at (chain *date (now)))
44 ;; For $COUNTER and SETTIMER
42 ;; For $COUNTER and SETTIMER
45 (#.(intern "SET-TIMER" "SUGAR-QSP.API")
43 (#.(intern "SET-TIMER" "SUGAR-QSP.API")
46 (root timer-interval))
44 *timer-interval)
47 ;; Start the first game
45 ;; Start the first game
48 (#.(intern "RUN-GAME" "SUGAR-QSP.API")
46 (#.(intern "RUN-GAME" "SUGAR-QSP.API")
49 (chain *object (keys (root games)) 0))
47 (chain *object (keys *games) 0))
50 (values)))
48 (values)))
51
@@ -1,104 +1,108 b''
1
1
2 (in-package cl-user)
2 (in-package cl-user)
3
3
4 (defpackage :sugar-qsp.js)
4 (defpackage :sugar-qsp.js)
5
5
6 (defpackage :sugar-qsp.main
6 (defpackage :sugar-qsp.main
7 (:use :cl :ps :sugar-qsp.js)
7 (:use :cl :ps :sugar-qsp.js)
8 (:export #:api-call #:by-id
8 (:export #:api-call #:by-id
9 #:root #:in
9 #:in
10 #:vars #:objs #:current-location
10
11 #:started-at #:timer-interval #:timer-obj
11 #:*globals #:*objs #:*current-location
12 #:state-stash #:playing #:locals
12 #:*started-at #:*timer-interval #:*timer-obj #:*loaded-games
13 #:acts #:locs #:games))
13
14 #:*acts #:*state-stash #:*playing #:*locals
15
16 #:*games #:*main-game #:*locs
17 ))
14
18
15 (defpackage :code-walker
19 (defpackage :code-walker
16 (:use :cl)
20 (:use :cl)
17 (:export #:deftransform
21 (:export #:deftransform
18 #:deftransform-stop
22 #:deftransform-stop
19 #:walk
23 #:walk
20 #:whole
24 #:whole
21 #:walk-continue))
25 #:walk-continue))
22
26
23 ;;; API functions
27 ;;; API functions
24 (defpackage :sugar-qsp.api
28 (defpackage :sugar-qsp.api
25 (:use :cl :ps :sugar-qsp.main :sugar-qsp.js)
29 (:use :cl :ps :sugar-qsp.main :sugar-qsp.js)
26 (:export #:with-frame #:with-call-args
30 (:export #:with-frame #:with-call-args
27 #:stash-state
31 #:stash-state
28
32
29 #:report-error #:sleep #:init-dom #:call-serv-loc
33 #:report-error #:sleep #:init-dom #:call-serv-loc
30 #:newline #:clear-id #:prepare-contents #:get-id #:set-id #:append-id
34 #:newline #:clear-id #:prepare-contents #:get-id #:set-id #:append-id
31 #:init-args #:get-result #:call-loc #:call-act
35 #:init-args #:get-result #:call-loc #:call-act
32 #:get-frame #:add-text #:get-text #:clear-text #:enable-frame
36 #:get-frame #:add-text #:get-text #:clear-text #:enable-frame
33 #:add-act #:del-act #:clear-act #:update-acts
37 #:add-act #:del-act #:clear-act #:update-acts
34 #:set-str-element #:set-any-element
38 #:set-str-element #:set-any-element
35 #:*var #:new-value #:index-num #:get #:set #:kill
39 #:*var #:new-value #:index-num #:get #:set #:kill
36 #:var-real-name #:ensure-var #:var-ref #:get-var #:set-var
40 #:var-real-name #:ensure-var #:var-ref #:get-var #:set-var
37 #:get-array #:set-array #:kill-var #:array-size
41 #:get-array #:set-array #:kill-var #:array-size
38 #:push-local-frame #:pop-local-frame #:current-local-frame #:new-local
42 #:push-local-frame #:pop-local-frame #:current-local-frame #:new-local
39 #:update-objs
43 #:update-objs
40 #:menu
44 #:menu
41 #:clean-audio
45 #:clean-audio
42 #:show-image
46 #:show-image
43 #:opengame #:savegame
47 #:opengame #:savegame
44 ))
48 ))
45
49
46 ;;; QSP library functions and macros
50 ;;; QSP library functions and macros
47 (defpackage :sugar-qsp.lib
51 (defpackage :sugar-qsp.lib
48 (:use :cl :ps :sugar-qsp.main :sugar-qsp.js)
52 (:use :cl :ps :sugar-qsp.main :sugar-qsp.js)
49 (:local-nicknames (#:api :sugar-qsp.api)
53 (:local-nicknames (#:api :sugar-qsp.api)
50 (#:walker :code-walker))
54 (#:walker :code-walker))
51 (:export #:str #:exec #:qspblock #:qspfor #:game #:location
55 (:export #:str #:exec #:qspblock #:qspfor #:game #:location
52 #:qspcond #:qspvar #:set #:local #:jump
56 #:qspcond #:qspvar #:set #:local #:jump
53
57
54 #:killvar #:killall
58 #:killvar #:killall
55 #:obj #:loc #:no
59 #:obj #:loc #:no
56 #:qspver #:curloc
60 #:qspver #:curloc
57 #:rnd #:qspmax #:qspmin
61 #:rnd #:qspmax #:qspmin
58 #:arrsize #:len
62 #:arrsize #:len
59 #:mid #:ucase #:lcase #:trim #:replace #:val #:qspstr
63 #:mid #:ucase #:lcase #:trim #:replace #:val #:qspstr
60 #:exit #:desc
64 #:exit #:desc
61 #:showstat #:msg
65 #:showstat #:msg
62 #:showacts #:delact #:cla
66 #:showacts #:delact #:cla
63 #:showobjs #:countobj #:getobj
67 #:showobjs #:countobj #:getobj
64 #:isplay
68 #:isplay
65 #:view
69 #:view
66 #:showinput
70 #:showinput
67 #:wait #:settimer
71 #:wait #:settimer
68 #:local
72 #:local
69 #:opengame #:savegame
73 #:opengame #:savegame
70
74
71 #:goto #:xgoto
75 #:goto #:xgoto
72 #:rand
76 #:rand
73 #:copyarr #:arrpos #:arrcomp
77 #:copyarr #:arrpos #:arrcomp
74 #:instr #:isnum #:strcomp #:strfind #:strpos
78 #:instr #:isnum #:strcomp #:strfind #:strpos
75 #:iif
79 #:iif
76 #:gosub #:func
80 #:gosub #:func
77 #:dynamic #:dyneval
81 #:dynamic #:dyneval
78 #:main-p #:main-pl #:main-nl #:maintxt #:desc #:main-clear
82 #:main-p #:main-pl #:main-nl #:maintxt #:desc #:main-clear
79 #:stat-p #:stat-pl #:stat-nl #:stattxt #:stat-clear #:cls
83 #:stat-p #:stat-pl #:stat-nl #:stattxt #:stat-clear #:cls
80 #:curacts
84 #:curacts
81 #:addobj #:delobj #:killobj
85 #:addobj #:delobj #:killobj
82 #:menu
86 #:menu
83 #:play #:close #:closeall
87 #:play #:close #:closeall
84 #:refint
88 #:refint
85 #:usertxt #:cmdclear #:input
89 #:usertxt #:cmdclear #:input
86 #:msecscount
90 #:msecscount
87 #:rgb
91 #:rgb
88 #:openqst #:addqst #:killqst
92 #:openqst #:addqst #:killqst
89 ))
93 ))
90
94
91 (setf (ps:ps-package-prefix "SUGAR-QSP.MAIN") "qsp_")
95 (setf (ps:ps-package-prefix "SUGAR-QSP.MAIN") "qsp_")
92 (setf (ps:ps-package-prefix "SUGAR-QSP.API") "qsp_api_")
96 (setf (ps:ps-package-prefix "SUGAR-QSP.API") "qsp_api_")
93 (setf (ps:ps-package-prefix "SUGAR-QSP.LIB") "qsp_lib_")
97 (setf (ps:ps-package-prefix "SUGAR-QSP.LIB") "qsp_lib_")
94
98
95 ;;; The compiler
99 ;;; The compiler
96 (defpackage :sugar-qsp
100 (defpackage :sugar-qsp
97 (:use :cl)
101 (:use :cl)
98 (:local-nicknames (#:p #:esrap)
102 (:local-nicknames (#:p #:esrap)
99 (#:lib :sugar-qsp.lib)
103 (#:lib :sugar-qsp.lib)
100 (#:api :sugar-qsp.api)
104 (#:api :sugar-qsp.api)
101 (#:main :sugar-qsp.main)
105 (#:main :sugar-qsp.main)
102 (#:walker :code-walker))
106 (#:walker :code-walker))
103 (:export #:parse-file #:entry-point))
107 (:export #:parse-file #:entry-point))
104
108
@@ -1,372 +1,372 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 ;;;; Block type | Has own locals | Has labels | async
8 ;;;; Block type | Has own locals | Has labels | async
9 ;;; Location | TRUE | TRUE | TRUE
9 ;;; Location | TRUE | TRUE | TRUE
10 ;;; Act | TRUE | TRUE | TRUE
10 ;;; Act | TRUE | TRUE | TRUE
11 ;;; {} | TRUE | TRUE | TRUE
11 ;;; {} | TRUE | TRUE | TRUE
12 ;;; IF | FALSE | TRUE | TRUE
12 ;;; IF | FALSE | TRUE | TRUE
13 ;;; FOR | FALSE | TRUE | TRUE
13 ;;; FOR | FALSE | TRUE | TRUE
14 ;;;
14 ;;;
15
15
16 ;;; Utils
16 ;;; Utils
17
17
18 ;;; Common
18 ;;; Common
19
19
20 (defpsmacro label-block (() &body body)
20 (defpsmacro label-block (() &body body)
21 (let ((has-labels (some #'keywordp body)))
21 (let ((has-labels (some #'keywordp body)))
22 `(block nil
22 `(block nil
23 ,@(when has-labels
23 ,@(when has-labels
24 '((var _labels (list))))
24 '((var _labels (list))))
25 (tagbody
25 (tagbody
26 ,@body
26 ,@body
27 (void)))))
27 (void)))))
28
28
29 (defpsmacro str (&rest forms)
29 (defpsmacro str (&rest forms)
30 (cond ((zerop (length forms))
30 (cond ((zerop (length forms))
31 "")
31 "")
32 ((and (= 1 (length forms))
32 ((and (= 1 (length forms))
33 (stringp (first forms)))
33 (stringp (first forms)))
34 (first forms))
34 (first forms))
35 (t
35 (t
36 `(& ,@forms))))
36 `(& ,@forms))))
37
37
38 (defpsmacro locals-block (&body body)
38 (defpsmacro locals-block (&body body)
39 "Includes labels too (through qsp-lambda)"
39 "Includes labels too (through qsp-lambda)"
40 (let ((*locals* nil))
40 (let ((*locals* nil))
41 (walker:walk 'locals body)
41 (walker:walk 'locals body)
42 `(qsp-lambda
42 `(qsp-lambda
43 (create-locals ,*locals*)
43 (create-locals ,*locals*)
44 ,@(walker:walk 'apply-vars body))))
44 ,@(walker:walk 'apply-vars body))))
45
45
46 ;;; 1loc
46 ;;; 1loc
47
47
48 (defparameter *service-variables*
48 (defparameter *service-variables*
49 '((usehtml 0)
49 '((usehtml 0)
50 (result 0)
50 (result 0)
51 ($result 0)
51 ($result 0)
52 ($ongload 0)
52 ($ongload 0)
53 ($ongsave 0)
53 ($ongsave 0)
54 ($onobjadd 0)
54 ($onobjadd 0)
55 ($onobjdel 0)
55 ($onobjdel 0)
56 ($onobjsel 0)
56 ($onobjsel 0)
57 ($onnewloc 0)
57 ($onnewloc 0)
58 ($onactsel 0)
58 ($onactsel 0)
59 ($counter 0)
59 ($counter 0)
60 ($usercom 0)))
60 ($usercom 0)))
61
61
62 (defpsmacro game ((name) &body body)
62 (defpsmacro game ((name) &body body)
63 (setf body (walker:walk 'for-transform body))
63 (setf body (walker:walk 'for-transform body))
64 (setf *globals* *service-variables*)
64 (setf *globals* *service-variables*)
65 (walker:walk 'globals body)
65 (walker:walk 'globals body)
66 `(progn
66 `(progn
67 ;; Game object
67 ;; Game object
68 (setf (root games ,name)
68 (setf (@ *games ,name)
69 (create))
69 (create))
70 ;; Global variables from this game
70 ;; Global variables from this game
71 (create-globals ,*globals*)
71 (create-globals ,*globals*)
72 ;; Locations
72 ;; Locations
73 ,@(loop :for location :in body
73 ,@(loop :for location :in body
74 :collect `(setf (root games ,name ,(caadr location))
74 :collect `(setf (@ *games ,name ,(caadr location))
75 ,location))))
75 ,location))))
76
76
77 (defpsmacro location ((name) &body body)
77 (defpsmacro location ((name) &body body)
78 (declare (ignore name))
78 (declare (ignore name))
79 "Name is used by the game macro above"
79 "Name is used by the game macro above"
80 `(locals-block ,@body))
80 `(locals-block ,@body))
81
81
82 (defpsmacro goto% (target &rest args)
82 (defpsmacro goto% (target &rest args)
83 `(progn
83 `(progn
84 (goto ,target ,args)
84 (goto ,target ,args)
85 (exit)))
85 (exit)))
86
86
87 (defpsmacro xgoto% (target &rest args)
87 (defpsmacro xgoto% (target &rest args)
88 `(progn
88 `(progn
89 (xgoto ,target ,args)
89 (xgoto ,target ,args)
90 (exit)))
90 (exit)))
91
91
92 ;;; 2var
92 ;;; 2var
93
93
94 (defvar *globals* nil)
94 (defvar *globals* nil)
95 (defvar *locals* nil)
95 (defvar *locals* nil)
96
96
97 (defpsmacro create-globals (globals)
97 (defpsmacro create-globals (globals)
98 (flet ((indexes (name)
98 (flet ((indexes (name)
99 (remove nil
99 (remove nil
100 (remove-if #'listp
100 (remove-if #'listp
101 (mapcar #'second
101 (mapcar #'second
102 (remove name globals
102 (remove name globals
103 :key #'first
103 :key #'first
104 :test-not #'eq))))))
104 :test-not #'eq))))))
105 (let ((names (remove-duplicates (mapcar #'first globals))))
105 (let ((names (remove-duplicates (mapcar #'first globals))))
106 `(chain *object
106 `(chain *object
107 (assign (root vars)
107 (assign *globals
108 (create
108 (create
109 ,@(loop :for sym :in names
109 ,@(loop :for sym :in names
110 :for indexes := (indexes sym)
110 :for indexes := (indexes sym)
111 :for name := (string-upcase sym)
111 :for name := (string-upcase sym)
112 :append `(,name
112 :append `(,name
113 (api-call new-var ,name ,@indexes)))))))))
113 (api-call new-var ,name ,@indexes)))))))))
114
114
115 (walker:deftransform globals qspvar (&rest var)
115 (walker:deftransform globals qspvar (&rest var)
116 (pushnew var *globals* :test #'equal)
116 (pushnew var *globals* :test #'equal)
117 (walker:walk-continue))
117 (walker:walk-continue))
118
118
119 (walker:deftransform globals local (var &rest expr)
119 (walker:deftransform globals local (var &rest expr)
120 (declare (ignore var))
120 (declare (ignore var))
121 (walker:walk 'globals expr))
121 (walker:walk 'globals expr))
122
122
123 (defpsmacro create-locals (locals)
123 (defpsmacro create-locals (locals)
124 (when locals
124 (when locals
125 `(progn
125 `(progn
126 (var locals (create
126 (var locals (create
127 ,@(loop :for (sym index) :in locals
127 ,@(loop :for (sym index) :in locals
128 :for name := (string-upcase sym)
128 :for name := (string-upcase sym)
129 :append `(,name (api-call new-var ,name))))))))
129 :append `(,name (api-call new-var ,name))))))))
130
130
131 ;; locations, blocks, and acts all have their own locals namespace
131 ;; locations, blocks, and acts all have their own locals namespace
132 (walker:deftransform-stop locals qspblock)
132 (walker:deftransform-stop locals qspblock)
133 (walker:deftransform-stop locals act)
133 (walker:deftransform-stop locals act)
134
134
135 (walker:deftransform locals local (var &optional expr)
135 (walker:deftransform locals local (var &optional expr)
136 (declare (ignore expr))
136 (declare (ignore expr))
137 (pushnew (rest var) *locals* :test #'equal)
137 (pushnew (rest var) *locals* :test #'equal)
138 nil)
138 nil)
139
139
140 ;; index types:
140 ;; index types:
141 ;; literal number
141 ;; literal number
142 ;; literal string
142 ;; literal string
143 ;; variable number
143 ;; variable number
144 ;; variable string
144 ;; variable string
145 ;; expression (may be possible to determine if it's a string or a number)
145 ;; expression (may be possible to determine if it's a string or a number)
146
146
147 (defun $-var-p (sym)
147 (defun $-var-p (sym)
148 (char= #\$ (elt (string-upcase (symbol-name sym)) 0)))
148 (char= #\$ (elt (string-upcase (symbol-name sym)) 0)))
149
149
150 (defun literal-string-p (form)
150 (defun literal-string-p (form)
151 (and (listp form)
151 (and (listp form)
152 (= 2 (length form))
152 (= 2 (length form))
153 (eq 'str (first form))
153 (eq 'str (first form))
154 (stringp (second form))))
154 (stringp (second form))))
155
155
156 (defun variable-number-p (form)
156 (defun variable-number-p (form)
157 (and (listp form)
157 (and (listp form)
158 (eq 'qspvar (first form))
158 (eq 'qspvar (first form))
159 (not ($-var-p (second form)))))
159 (not ($-var-p (second form)))))
160
160
161 (defun variable-string-p (form)
161 (defun variable-string-p (form)
162 (and (listp form)
162 (and (listp form)
163 (eq 'qspvar (first form))
163 (eq 'qspvar (first form))
164 ($-var-p (second form))))
164 ($-var-p (second form))))
165
165
166 (walker:deftransform apply-vars set (var expr)
166 (walker:deftransform apply-vars set (var expr)
167 (destructuring-bind (qspvar name index)
167 (destructuring-bind (qspvar name index)
168 var
168 var
169 (declare (ignore qspvar))
169 (declare (ignore qspvar))
170 (let ((slot `(getprop
170 (let ((slot `(getprop
171 ,(if (member name *locals* :key #'first)
171 ,(if (member name *locals* :key #'first)
172 'locals '(root vars))
172 'locals '*globals)
173 ,(string-upcase name))))
173 ,(string-upcase name))))
174 (cond
174 (cond
175 ((null index)
175 ((null index)
176 `(chain (elt ,slot) (push ,expr)))
176 `(chain (elt ,slot) (push ,expr)))
177 ((or (numberp index)
177 ((or (numberp index)
178 (variable-number-p index))
178 (variable-number-p index))
179 `(setf (elt ,slot ,index)
179 `(setf (elt ,slot ,index)
180 ,(walker:walk 'apply-vars expr)))
180 ,(walker:walk 'apply-vars expr)))
181 ((or (literal-string-p index)
181 ((or (literal-string-p index)
182 (variable-string-p index))
182 (variable-string-p index))
183 `(api:set-str-element ,slot ,(walker:walk 'apply-vars index)
183 `(api:set-str-element ,slot ,(walker:walk 'apply-vars index)
184 ,(walker:walk-continue expr)))
184 ,(walker:walk-continue expr)))
185 (t
185 (t
186 `(api:set-any-element ,slot ,(walker:walk 'apply-vars index)
186 `(api:set-any-element ,slot ,(walker:walk 'apply-vars index)
187 ,(walker:walk-continue expr)))))))
187 ,(walker:walk-continue expr)))))))
188
188
189 (walker:deftransform apply-vars local (var &optional expr)
189 (walker:deftransform apply-vars local (var &optional expr)
190 (when expr
190 (when expr
191 (walker:walk 'apply-vars (list 'set var expr))))
191 (walker:walk 'apply-vars (list 'set var expr))))
192
192
193 (walker:deftransform apply-vars qspvar (name index)
193 (walker:deftransform apply-vars qspvar (name index)
194 (let ((slot `(getprop
194 (let ((slot `(getprop
195 ,(if (member name *locals* :key #'first) 'locals '(root vars))
195 ,(if (member name *locals* :key #'first) 'locals '*globals)
196 ,(string-upcase name))))
196 ,(string-upcase name))))
197 (cond
197 (cond
198 ((null index)
198 ((null index)
199 `(elt ,slot (1- (length ,slot))))
199 `(elt ,slot (1- (length ,slot))))
200 ((or (numberp index)
200 ((or (numberp index)
201 (variable-number-p index))
201 (variable-number-p index))
202 `(elt ,slot ,(walker:walk-continue index)))
202 `(elt ,slot ,(walker:walk-continue index)))
203 ((or (literal-string-p index)
203 ((or (literal-string-p index)
204 (variable-string-p index))
204 (variable-string-p index))
205 `(elt ,slot (@ ,slot :indexes ,(walker:walk-continue index))))
205 `(elt ,slot (@ ,slot :indexes ,(walker:walk-continue index))))
206 (t
206 (t
207 `(get-element ,slot ,(walker:walk-continue index))))))
207 `(get-element ,slot ,(walker:walk-continue index))))))
208
208
209 (walker:deftransform apply-vars qspblock (&rest block)
209 (walker:deftransform apply-vars qspblock (&rest block)
210 (declare (ignore block))
210 (declare (ignore block))
211 (walker:whole))
211 (walker:whole))
212 (walker:deftransform apply-vars act (&rest block)
212 (walker:deftransform apply-vars act (&rest block)
213 (declare (ignore block))
213 (declare (ignore block))
214 (walker:whole))
214 (walker:whole))
215 (walker:deftransform apply-vars qspfor (var from to step body)
215 (walker:deftransform apply-vars qspfor (var from to step body)
216 (list* 'qspfor var (mapcar #'walker:walk-continue (list from to step body))))
216 (list* 'qspfor var (mapcar #'walker:walk-continue (list from to step body))))
217
217
218 ;;; 3expr
218 ;;; 3expr
219
219
220 (defpsmacro <> (op1 op2)
220 (defpsmacro <> (op1 op2)
221 `(not (equal ,op1 ,op2)))
221 `(not (equal ,op1 ,op2)))
222
222
223 (defpsmacro ! (op1 op2)
223 (defpsmacro ! (op1 op2)
224 `(not (equal ,op1 ,op2)))
224 `(not (equal ,op1 ,op2)))
225
225
226 ;;; 4code
226 ;;; 4code
227
227
228 (defpsmacro exec (&body body)
228 (defpsmacro exec (&body body)
229 (format nil "javascript: ~{~A~^~%~}" (mapcar #'ps* body)))
229 (format nil "javascript: ~{~A~^~%~}" (mapcar #'ps* body)))
230
230
231 ;;; 5arrays
231 ;;; 5arrays
232
232
233 ;;; 6str
233 ;;; 6str
234
234
235 (defpsmacro & (&rest args)
235 (defpsmacro & (&rest args)
236 `(chain "" (concat ,@args)))
236 `(chain "" (concat ,@args)))
237
237
238 ;;; 7if
238 ;;; 7if
239
239
240 (defpsmacro qspcond (&rest clauses)
240 (defpsmacro qspcond (&rest clauses)
241 `(cond ,@(loop :for clause :in clauses
241 `(cond ,@(loop :for clause :in clauses
242 :collect (list (first clause)
242 :collect (list (first clause)
243 `(tagbody
243 `(tagbody
244 ,@(rest clause))))))
244 ,@(rest clause))))))
245
245
246 ;;; 8sub
246 ;;; 8sub
247
247
248 ;;; 9loops
248 ;;; 9loops
249 ;;; Yep, that's a huge kludge since Javascript doesn't support arbitrary labels
249 ;;; Yep, that's a huge kludge since Javascript doesn't support arbitrary labels
250
250
251 (defpsmacro jump (target)
251 (defpsmacro jump (target)
252 `(return-from label-body ,(string-upcase (second target))))
252 `(return-from label-body ,(string-upcase (second target))))
253
253
254 (defpsmacro tagbody (&body body)
254 (defpsmacro tagbody (&body body)
255 (let ((create-locals (if (eq (caar body) 'create-locals)
255 (let ((create-locals (if (eq (caar body) 'create-locals)
256 (list (car body))))
256 (list (car body))))
257 (void (if (equal (car (last body)) '(void))
257 (void (if (equal (car (last body)) '(void))
258 '((void)))))
258 '((void)))))
259 (when create-locals
259 (when create-locals
260 (setf body (cdr body)))
260 (setf body (cdr body)))
261 (when void
261 (when void
262 (setf body (butlast body)))
262 (setf body (butlast body)))
263 (let ((funcs (list nil "_nil")))
263 (let ((funcs (list nil "_nil")))
264 (dolist (form body)
264 (dolist (form body)
265 (cond ((keywordp form)
265 (cond ((keywordp form)
266 (setf (first funcs) (reverse (first funcs)))
266 (setf (first funcs) (reverse (first funcs)))
267 (push (string-upcase form) funcs)
267 (push (string-upcase form) funcs)
268 (push nil funcs))
268 (push nil funcs))
269 (t
269 (t
270 (push form (first funcs)))))
270 (push form (first funcs)))))
271 (setf (first funcs) (reverse (first funcs)))
271 (setf (first funcs) (reverse (first funcs)))
272 (setf funcs (reverse funcs))
272 (setf funcs (reverse funcs))
273 `(progn
273 `(progn
274 ,@create-locals
274 ,@create-locals
275 ,(if (= 2 (length funcs))
275 ,(if (= 2 (length funcs))
276 `(progn
276 `(progn
277 ,@body)
277 ,@body)
278 `(progn
278 `(progn
279 (tagbody-blocks ,funcs)
279 (tagbody-blocks ,funcs)
280 (loop
280 (loop
281 :for _nextblock
281 :for _nextblock
282 := :_nil
282 := :_nil
283 :then (await (funcall (getprop _labels _nextblock)))
283 :then (await (funcall (getprop _labels _nextblock)))
284 :while _nextblock)))
284 :while _nextblock)))
285 ,@void))))
285 ,@void))))
286
286
287 (defvar *current-label*)
287 (defvar *current-label*)
288 (defvar *has-jump-back*)
288 (defvar *has-jump-back*)
289 (walker:deftransform optimize-jump jump (target)
289 (walker:deftransform optimize-jump jump (target)
290 (cond ((string= (string-upcase (second target)) *current-label*)
290 (cond ((string= (string-upcase (second target)) *current-label*)
291 (setf *has-jump-back* t)
291 (setf *has-jump-back* t)
292 '(continue))
292 '(continue))
293 (t
293 (t
294 (walker:walk-continue))))
294 (walker:walk-continue))))
295
295
296 (defpsmacro tagbody-blocks (funcs)
296 (defpsmacro tagbody-blocks (funcs)
297 `(setf ,@(loop :for (label code . rest-labels) :on funcs :by #'cddr
297 `(setf ,@(loop :for (label code . rest-labels) :on funcs :by #'cddr
298 :append `((@ _labels ,label)
298 :append `((@ _labels ,label)
299 (async-lambda ()
299 (async-lambda ()
300 (block label-body
300 (block label-body
301 (tagbody-block-body ,label ,code
301 (tagbody-block-body ,label ,code
302 ,(first rest-labels))))))))
302 ,(first rest-labels))))))))
303
303
304 (defpsmacro tagbody-block-body (label code next-label)
304 (defpsmacro tagbody-block-body (label code next-label)
305 (let ((*current-label* label)
305 (let ((*current-label* label)
306 (*has-jump-back* nil))
306 (*has-jump-back* nil))
307 (let ((code (walker:walk 'optimize-jump code)))
307 (let ((code (walker:walk 'optimize-jump code)))
308 (if *has-jump-back*
308 (if *has-jump-back*
309 `(progn
309 `(progn
310 (loop :do (progn
310 (loop :do (progn
311 ,@code
311 ,@code
312 (break)))
312 (break)))
313 ,@(if next-label
313 ,@(if next-label
314 (list next-label)
314 (list next-label)
315 nil))
315 nil))
316 `(progn
316 `(progn
317 ,@code
317 ,@code
318 ,@(if next-label
318 ,@(if next-label
319 (list next-label)
319 (list next-label)
320 nil))))))
320 nil))))))
321
321
322 (defpsmacro exit ()
322 (defpsmacro exit ()
323 '(return-from nil (values)))
323 '(return-from nil (values)))
324
324
325 ;;; 10dynamic
325 ;;; 10dynamic
326
326
327 (defpsmacro qspblock (&body body)
327 (defpsmacro qspblock (&body body)
328 `(locals-block
328 `(locals-block
329 ,@body))
329 ,@body))
330
330
331 (defpsmacro qsp-lambda (&body body)
331 (defpsmacro qsp-lambda (&body body)
332 `(async-lambda (args)
332 `(async-lambda (args)
333 (label-block ()
333 (label-block ()
334 ,@body)))
334 ,@body)))
335
335
336 ;;; 11main
336 ;;; 11main
337
337
338 (defpsmacro act (name img &body body)
338 (defpsmacro act (name img &body body)
339 `(api-call add-act ,name ,img
339 `(api-call add-act ,name ,img
340 (locals-block
340 (locals-block
341 ,@body)))
341 ,@body)))
342
342
343 ;;; 12aux
343 ;;; 12aux
344
344
345 ;;; 13diag
345 ;;; 13diag
346
346
347 ;;; 14act
347 ;;; 14act
348
348
349 ;;; 15objs
349 ;;; 15objs
350
350
351 ;;; 16menu
351 ;;; 16menu
352
352
353 ;;; 17sound
353 ;;; 17sound
354
354
355 ;;; 18img
355 ;;; 18img
356
356
357 ;;; 19input
357 ;;; 19input
358
358
359 ;;; 20time
359 ;;; 20time
360
360
361 ;;; 21local
361 ;;; 21local
362
362
363 ;;; 22for
363 ;;; 22for
364
364
365 ;; Transform because it creates a (set ...) hence it has to be processed
365 ;; Transform because it creates a (set ...) hence it has to be processed
366 ;; before the apply-vars transform. And macros are processed *after* all
366 ;; before the apply-vars transform. And macros are processed *after* all
367 ;; the transforms
367 ;; the transforms
368 (walker:deftransform for-transform qspfor (var from to step &rest body)
368 (walker:deftransform for-transform qspfor (var from to step &rest body)
369 `(loop :for i :from ,from :to ,to :by ,step
369 `(loop :for i :from ,from :to ,to :by ,step
370 :do (set ,var i)
370 :do (set ,var i)
371 :do (block nil
371 :do (block nil
372 ,@(walker:walk-continue body))))
372 ,@(walker:walk-continue body))))
General Comments 0
You need to be logged in to leave comments. Login now