##// END OF EJS Templates
Actually fix it
naryl -
r53:a5523508 default
parent child Browse files
Show More
@@ -1,32 +1,28 b''
1 1
2 2 BIN = txt2web
3 3 DIST = $(BIN).tar.xz
4 4
5 5 all: $(BIN)
6 6
7 7 dist: $(DIST)
8 8
9 9 graphs: diagrams.png
10 10
11 11 $(BIN): *.asd src/*.lisp src/*.ps strings/*.sexp
12 12 sbcl --load build.lisp -- $(BIN)
13 13
14 14 %.png: %.dot
15 15 dot $< -T png -o $@
16 16
17 17 $(DIST): $(BIN) extras/*
18 18 tar cfvJ $@ $< extras
19 19
20 upload: $(DIST)
21 curl --upload-file $(DIST) https://transfer.sh/$(DIST)
22 @echo
23
24 20 clean:
25 21 rm -f $(BIN) $(DIST)
26 22
27 23 clean-cache:
28 24 -rm -rf ~/.cache/common-lisp
29 25
30 26 fresh: clean clean-cache all
31 27
32 .PHONY: all graphs upload clean clean-cache fresh
28 .PHONY: all graphs clean clean-cache fresh
@@ -1,531 +1,529 b''
1 1
2 (in-package txt2web)
2 (in-package txt2web.api)
3 3
4 4 ;;; API deals with DOM manipulation and some bookkeeping for the
5 5 ;;; intrinsics, namely variables
6 6 ;;; API is an implementation detail and has no QSP documentation. It
7 7 ;;; doesn't call intrinsics
8 8
9 9 ;;; Utils
10 10
11 11 (defun make-act-html (title img)
12 12 (+ "<a class='qsp-act' href='" (href-call call-act title) "' onmouseover='" (inline-call select-act title) "'>"
13 13 (if img (+ "<img src='" img "'>") "")
14 14 title
15 15 "</a>"))
16 16
17 17 (defun make-menu-item-html (num title img loc)
18 18 (+ "<a href='" (href-call finish-menu loc) "'>"
19 19 (if img (+ "<img src='" img "'>") "")
20 20 title
21 21 "</a>"))
22 22
23 23 (defun make-obj (title img selected)
24 24 (+ "<li onclick='" (inline-call select-obj title img) "'>"
25 25 "<a class='qsp-obj" (if selected " qsp-obj-selected" "") "'>"
26 26 (if img (+ "<img src='" img "'>") "")
27 27 title
28 28 "</a>"))
29 29
30 30 (defun make-menu-delimiter ()
31 31 "<hr>")
32 32
33 33 (defun copy-obj (obj)
34 34 (chain *j-s-o-n (parse (chain *j-s-o-n (stringify obj)))))
35 35
36 36 (defun report-error (text)
37 37 (alert text))
38 38
39 39 (defun start-sleeping ()
40 40 (chain (by-id "qsp") class-list (add "disable")))
41 41
42 42 (defun finish-sleeping ()
43 43 (chain (by-id "qsp") class-list (remove "disable")))
44 44
45 45 (defun sleep (msec)
46 46 (with-sleep (resume)
47 47 (set-timeout resume msec)))
48 48
49 49 (defun init-dom ()
50 50 ;; Save/load buttons
51 51 (let ((btn (by-id "qsp-btn-save")))
52 52 (setf (@ btn onclick) savegame)
53 53 (setf (@ btn href) "#"))
54 54 (let ((btn (by-id "qsp-btn-open")))
55 55 (setf (@ btn onclick) opengame)
56 56 (setf (@ btn href) "#"))
57 57 ;; Close image on click
58 58 (setf (@ (by-id "qsp-image-container") onclick)
59 59 show-image)
60 60 ;; Enter in input field
61 61 (setf (@ (get-frame :input) onkeyup)
62 62 on-input-key)
63 63 ;; Close the dropdown on any click
64 64 (setf (@ window onclick)
65 65 (lambda (event)
66 66 (setf (@ window mouse)
67 67 (list (@ event page-x)
68 68 (@ event page-y)))
69 69 (finish-menu nil))))
70 70
71 71 (defun call-serv-loc (var-name &rest args)
72 72 (let ((loc-name (get-global var-name 0)))
73 73 (when loc-name
74 74 (let ((loc (getprop *locs loc-name)))
75 75 (when loc
76 76 (call-loc loc-name args))))))
77 77
78 78 (defun filename-game (filename)
79 79 (let ((game-name (chain filename (match "(.*/)?([^.]+)(\\.[a-zA-Z]+)?") 2))))
80 80 (getprop *games game-name))
81 81
82 82 (defun run-game (name)
83 83 (let ((game (filename-game name)))
84 84 (setf *main-game name)
85 85 ;; Replace locations with the new game's
86 86 (setf *locs game)
87 87 (funcall (getprop game
88 88 (chain *object (keys game) 0))
89 89 (list))))
90 90
91 91 ;;; Misc
92 92
93 93 (defun newline (key)
94 94 (append-id (key-to-id key) "<br>" t))
95 95
96 96 (defun clear-id (id)
97 97 (setf (inner-html (by-id id)) ""))
98 98
99 99 (defun escape-html (text)
100 100 (chain text
101 101 (replace (regex "/&/g") "&amp;")
102 102 (replace (regex "/</g") "&lt;")
103 103 (replace (regex "/>/g") "&gt;")
104 104 (replace (regex "/\"/g") "&quot;")
105 105 (replace (regex "/'/g") "&apos;")))
106 106
107 107 (defun prepare-contents (s &optional force-html)
108 108 (setf s (chain s (to-string)))
109 109 (if (or force-html (get-global "USEHTML" 0))
110 110 s
111 111 (escape-html s)))
112 112
113 113 (defun get-id (id &optional force-html)
114 114 (inner-html (by-id id)))
115 115
116 116 (defun set-id (id contents &optional force-html)
117 117 (setf (inner-html (by-id id)) (prepare-contents contents force-html)))
118 118
119 119 (defun append-id (id contents &optional force-html)
120 120 (when contents
121 121 (incf (inner-html (by-id id)) (prepare-contents contents force-html))))
122 122
123 123 (defun on-input-key (ev)
124 124 (when (= 13 (@ ev key-code))
125 125 (chain ev (prevent-default))
126 126 (call-serv-loc "$USERCOM")))
127 127
128 128 ;;; Function calls
129 129
130 130 (defun init-args (args)
131 131 (dotimes (i (length args))
132 132 (let ((arg (elt args i)))
133 133 (if (numberp arg)
134 134 (set-var args i :num arg)
135 135 (set-var args i :str arg)))))
136 136
137 137 (defun get-result ()
138 138 (or (get-global "$RESULT" 0)
139 139 (get-global "RESULT" 0)))
140 140
141 141 (defun call-loc (name args)
142 142 (setf name (chain name (to-upper-case)))
143 143 (with-frame
144 144 (with-call-args args
145 145 (funcall (getprop *locs name))))
146 146 (void))
147 147
148 148 (defun call-act (title)
149 149 (with-frame
150 150 (funcall (getprop *acts title :act)))
151 151 (void))
152 152
153 153 ;;; Text windows
154 154
155 155 (defun key-to-id (key)
156 156 (case key
157 157 (:all "qsp")
158 158 (:main "qsp-main")
159 159 (:stat "qsp-stat")
160 160 (:objs "qsp-objs")
161 161 (:acts "qsp-acts")
162 162 (:input "qsp-input")
163 163 (:image "qsp-image")
164 164 (:dropdown "qsp-dropdown")
165 165 (t (report-error "Internal error!"))))
166 166
167 167 (defun get-frame (key)
168 168 (by-id (key-to-id key)))
169 169
170 170 (defun add-text (key text)
171 171 (append-id (key-to-id key) text))
172 172
173 173 (defun get-text (key)
174 174 (get-id (key-to-id key)))
175 175
176 176 (defun clear-text (key)
177 177 (clear-id (key-to-id key)))
178 178
179 179 (defun enable-frame (key enable)
180 180 (let ((obj (get-frame key)))
181 181 (setf (@ obj style display) (if enable "block" "none"))
182 182 (void)))
183 183
184 184 ;;; Actions
185 185
186 186 (defun add-act (title img act)
187 187 (setf (getprop *acts title)
188 188 (create :title title :img img :act act :selected nil))
189 189 (update-acts))
190 190
191 191 (defun del-act (title)
192 192 (delete (getprop *acts title))
193 193 (update-acts))
194 194
195 195 (defun clear-act ()
196 196 (setf *acts (create))
197 197 (update-acts))
198 198
199 199 (defun update-acts ()
200 200 (clear-id "qsp-acts")
201 201 (let ((elt (by-id "qsp-acts")))
202 202 (for-in (title *acts)
203 203 (let ((obj (getprop *acts title)))
204 204 (incf (inner-html elt) (make-act-html title (getprop obj :img)))))))
205 205
206 206 (defun select-act (title)
207 207 (loop :for (k v) :of *acts
208 208 :do (setf (getprop v :selected) nil))
209 209 (setf (getprop *acts title :selected) t)
210 210 (call-serv-loc "$ONACTSEL"))
211 211
212 212 ;;; "Syntax"
213 213
214 214 (defun qspfor (name index from to step body)
215 (ps:for ((i from))
216 ((< i to))
217 ((incf i step))
218 (set-var name index :num i)
219 (unless (await (funcall body))
220 (return-from qspfor))))
215 (loop :for i :from from :to to :by step
216 :do (set-var name index :num i)
217 :do (unless (await (funcall body))
218 (return-from qspfor))))
221 219
222 220 ;;; Variables
223 221
224 222 (defun new-var (slot &rest indexes)
225 223 (let ((v (list)))
226 224 (dolist (index indexes)
227 225 (setf (elt v index) (if (eq #\$ (elt slot 0)) "" 0)))
228 226 (setf (@ v :indexes) (create))
229 227 v))
230 228
231 229 (defun set-str-element (slot index value)
232 230 (if (has index (getprop slot :indexes))
233 231 (setf (elt (getprop slot)
234 232 (getprop slot :indexes index))
235 233 value)
236 234 (progn
237 235 (chain slot (push value))
238 236 (setf (elt slot index)
239 237 (length slot))))
240 238 (void))
241 239
242 240 (defun set-any-element (slot index value)
243 241 (cond ((null index)
244 242 (chain (elt slot) (push value)))
245 243 ((numberp index)
246 244 (setf (elt slot index) value))
247 245 ((stringp index)
248 246 (set-str-element slot index value))
249 247 (t (report-error "INTERNAL ERROR")))
250 248 (void))
251 249
252 250 (defun set-serv-var (name index value)
253 251 (let ((slot (getprop *globals name)))
254 252 (set-any-element slot index value))
255 253 (funcall (getprop serv-vars name :body) value index)
256 254 (void))
257 255
258 256 (defun get-element (slot index)
259 257 (if (numberp index)
260 258 (elt slot index)
261 259 (elt slot (getprop slot :indexes index))))
262 260
263 261 (defun get-global (name index)
264 262 (elt (getprop *globals name) index))
265 263
266 264 (defun kill-var (store name &optional index)
267 265 (setf name (chain name (to-upper-case)))
268 266 (if (and index (not (= 0 index)))
269 267 (chain (getprop *globals name) (kill index))
270 268 (delete (getprop *globals name)))
271 269 (void))
272 270
273 271 (defun array-size (name)
274 272 (@ (var-ref name) :values length))
275 273
276 274 ;;; Locals
277 275
278 276 (defun push-local-frame ()
279 277 (chain *locals (push (create)))
280 278 (void))
281 279
282 280 (defun pop-local-frame ()
283 281 (chain *locals (pop))
284 282 (void))
285 283
286 284 (defun current-local-frame ()
287 285 (elt *locals (1- (length *locals))))
288 286
289 287 ;;; Objects
290 288
291 289 (defun select-obj (title img)
292 290 (loop :for (k v) :of *objs
293 291 :do (setf (getprop v :selected) nil))
294 292 (setf (getprop *objs title :selected) t)
295 293 (call-serv-loc "$ONOBJSEL" title img))
296 294
297 295 (defun update-objs ()
298 296 (let ((elt (by-id "qsp-objs")))
299 297 (setf (inner-html elt) "<ul>")
300 298 (loop :for (name obj) :of *objs
301 299 :do (incf (inner-html elt)
302 300 (make-obj name (@ obj :img) (@ obj :selected))))
303 301 (incf (inner-html elt) "</ul>")))
304 302
305 303 ;;; Menu
306 304
307 305 (defun open-menu (menu-data)
308 306 (let ((elt (get-frame :dropdown))
309 307 (i 0))
310 308 (loop :for item :in menu-data
311 309 :do (incf i)
312 310 :do (incf (inner-html elt)
313 311 (if (eq item :delimiter)
314 312 (make-menu-delimiter i)
315 313 (make-menu-item-html i
316 314 (@ item :text)
317 315 (@ item :icon)
318 316 (@ item :loc)))))
319 317 (let ((mouse (@ window mouse)))
320 318 (setf (@ elt style left) (+ (elt mouse 0) "px"))
321 319 (setf (@ elt style top) (+ (elt mouse 1) "px"))
322 320 ;; Make sure it's inside the viewport
323 321 (when (> (@ document body inner-width)
324 322 (+ (elt mouse 0) (@ elt inner-width)))
325 323 (incf (@ elt style left) (@ elt inner-width)))
326 324 (when (> (@ document body inner-height)
327 325 (+ (elt mouse 0) (@ elt inner-height)))
328 326 (incf (@ elt style top) (@ elt inner-height))))
329 327 (setf (@ elt style display) "block")))
330 328
331 329 (defun finish-menu (loc)
332 330 (when *menu-resume
333 331 (let ((elt (get-frame :dropdown)))
334 332 (setf (inner-html elt) "")
335 333 (setf (@ elt style display) "none")
336 334 (funcall *menu-resume)
337 335 (setf *menu-resume nil))
338 336 (when loc
339 337 (call-loc loc)))
340 338 (void))
341 339
342 340 (defun menu (menu-data)
343 341 (with-sleep (resume)
344 342 (open-menu menu-data)
345 343 (setf *menu-resume resume))
346 344 (void))
347 345
348 346 ;;; Content
349 347
350 348 (defun clean-audio ()
351 349 (loop :for k :in (chain *object (keys *playing))
352 350 :for v := (getprop *playing k)
353 351 :do (when (@ v ended)
354 352 (delete (@ *playing k)))))
355 353
356 354 (defun show-image (path)
357 355 (let ((img (get-frame :image)))
358 356 (cond (path
359 357 (setf (@ img src) path)
360 358 (setf (@ img style display) "flex"))
361 359 (t
362 360 (setf (@ img src) "")
363 361 (setf (@ img style display) "hidden")))))
364 362
365 363 (defun show-inline-images (frame-name images)
366 364 (let ((frame (get-frame frame-name))
367 365 (text ""))
368 366 (incf text "<div style='position:relative; display: inline-block'>")
369 367 (incf text (+ "<img src='" (@ images 0) "'>"))
370 368 (loop :for image :in (chain images (slice 1))
371 369 :do (incf text
372 370 (+ "<img style='position:absolute' src='" image "'>")))
373 371 (incf text "</div>")
374 372 (incf (inner-html frame) text)))
375 373
376 374 (defun rgb-string (rgb)
377 375 (let ((red (ps::>> rgb 16))
378 376 (green (logand (ps::>> rgb 8) 255))
379 377 (blue (logand rgb 255)))
380 378 (flet ((rgb-to-hex (comp)
381 379 (let ((hex (chain (*number comp) (to-string 16))))
382 380 (if (< (length hex) 2)
383 381 (+ "0" hex)
384 382 hex))))
385 383 (+ "#" (rgb-to-hex red) (rgb-to-hex green) (rgb-to-hex blue)))))
386 384
387 385 (defun store-obj (key obj)
388 386 (store-str key (btoa (encode-u-r-i-component (chain *j-s-o-n (stringify obj)))))
389 387 (void))
390 388 (defun store-str (key str)
391 389 (chain local-storage (set-item (+ "qsp_" key) str))
392 390 (void))
393 391
394 392 (defun load-obj (key)
395 393 (chain *j-s-o-n (parse (encode-u-r-i-component (atob (load-str key))))))
396 394 (defun load-str (key)
397 395 (chain local-storage (get-item (+ "qsp_" key))))
398 396
399 397 ;;; Saves
400 398
401 399 (defun slot-savegame (slot comment)
402 400 (let ((saves (load-obj "saves")))
403 401 (setf (@ saves slot) comment)
404 402 (store-obj saves))
405 403 (store-str slot (state-to-base64))
406 404 (void))
407 405
408 406 (defun slot-loadgame (slot)
409 407 (base64-to-state (load-str slot))
410 408 (void))
411 409
412 410 (defun slot-deletegame (slot)
413 411 (let ((saves (load-obj "saves")))
414 412 (setf (@ saves slot) undefined)
415 413 (store-obj saves))
416 414 (store-str slot undefined)
417 415 (void))
418 416
419 417 (defun slot-listgames ()
420 418 (load-obj "saves"))
421 419
422 420 (defun opengame ()
423 421 (let ((element (chain document (create-element :input))))
424 422 (chain element (set-attribute :type :file))
425 423 (chain element (set-attribute :id :qsp-opengame))
426 424 (chain element (set-attribute :tabindex -1))
427 425 (chain element (set-attribute "aria-hidden" t))
428 426 (setf (@ element style display) :block)
429 427 (setf (@ element style visibility) :hidden)
430 428 (setf (@ element style position) :fixed)
431 429 (setf (@ element onchange)
432 430 (lambda (event)
433 431 (let* ((file (@ event target files 0))
434 432 (reader (new (*file-reader))))
435 433 (setf (@ reader onload)
436 434 (lambda (ev)
437 435 (block nil
438 436 (let ((target (@ ev current-target)))
439 437 (unless (@ target result)
440 438 (return))
441 439 (base64-to-state (@ target result))
442 440 (unstash-state)))))
443 441 (chain reader (read-as-text file)))))
444 442 (chain document body (append-child element))
445 443 (chain element (click))
446 444 (chain document body (remove-child element))))
447 445
448 446 (defun savegame ()
449 447 (let ((element (chain document (create-element :a))))
450 448 (chain element (set-attribute :href (+ "data:text/plain;charset=utf-8," (state-to-base64))))
451 449 (chain element (set-attribute :download "savegame.sav"))
452 450 (setf (@ element style display) :none)
453 451 (chain document body (append-child element))
454 452 (chain element (click))
455 453 (chain document body (remove-child element))))
456 454
457 455 (defun stash-state (args)
458 456 (call-serv-loc "$ONGSAVE")
459 457 (setf *state-stash
460 458 (chain *j-s-o-n (stringify
461 459 (create :vars *globals
462 460 :objs *objs
463 461 :loc-args args
464 462 :msecs (- (chain *date (now)) *started-at)
465 463 :timer-interval *timer-interval
466 464 :main-html (inner-html
467 465 (get-frame :main))
468 466 :stat-html (inner-html
469 467 (get-frame :stat))
470 468 :next-location *current-location))))
471 469 (void))
472 470
473 471 (defun unstash-state ()
474 472 (let ((data (chain *j-s-o-n (parse *state-stash))))
475 473 (clear-act)
476 474 (setf *globals (@ data :vars))
477 475 (loop :for k :in (chain *object (keys *globals))
478 476 :do (chain *object (set-prototype-of (getprop *globals k)
479 477 (@ *var prototype))))
480 478 (setf *started-at (- (chain *date (now)) (@ data :msecs)))
481 479 (setf *objs (@ data :objs))
482 480 (setf *current-location (@ data :next-location))
483 481 (setf (inner-html (get-frame :main))
484 482 (@ data :main-html))
485 483 (setf (inner-html (get-frame :stat))
486 484 (@ data :stat-html))
487 485 (update-objs)
488 486 (set-timer (@ data :timer-interval))
489 487 (call-serv-loc "$ONGLOAD")
490 488 (call-loc *current-location (@ data :loc-args))
491 489 (void)))
492 490
493 491 (defun state-to-base64 ()
494 492 (btoa (encode-u-r-i-component *state-stash)))
495 493
496 494 (defun base64-to-state (data)
497 495 (setf *state-stash (decode-u-r-i-component (atob data))))
498 496
499 497 ;;; Timers
500 498
501 499 (defun set-timer (interval)
502 500 (setf *timer-interval interval)
503 501 (clear-interval *timer-obj)
504 502 (setf *timer-obj
505 503 (set-interval
506 504 (lambda ()
507 505 (call-serv-loc "$COUNTER"))
508 506 interval)))
509 507
510 508 ;;; Special variables
511 509
512 510 (defvar serv-vars (create))
513 511
514 512 (define-serv-var $backimage (path)
515 513 (setf (@ (get-frame :main) style background-image) path))
516 514
517 515 (define-serv-var bcolor (color)
518 516 (setf (@ (get-frame :all) style background-color) (rgb-string color)))
519 517
520 518 (define-serv-var fcolor (color)
521 519 (setf (@ (get-frame :all) style color) (rgb-string color)))
522 520
523 521 (define-serv-var lcolor (color)
524 522 (setf (@ (get-frame :style) inner-text)
525 523 (+ "a { color: " (rgb-string color) ";}")))
526 524
527 525 (define-serv-var fsize (size)
528 526 (setf (@ (get-frame :all) style font-size) size))
529 527
530 528 (define-serv-var $fname (font-name)
531 529 (setf (@ (get-frame :all) style font-family) (+ font-name ",serif")))
@@ -1,326 +1,326 b''
1 1
2 (in-package txt2web)
2 (in-package txt2web.lib)
3 3
4 4 ;;;; Functions and procedures defined by the QSP language.
5 5 ;;;; They can call api and deal with locations and other data directly.
6 6 ;;;; Except vars. Use VAR and SET or GET-VAR and SET-VAR api calls.
7 7
8 8 ;;; 1loc
9 9
10 10 (defun goto (target args)
11 11 (api:clear-text :main)
12 12 (funcall xgoto target args)
13 13 (void))
14 14
15 15 (defun xgoto (target args)
16 16 (setf args (or args (list)))
17 17 (api:clear-act)
18 18 (setf *current-location (chain target (to-upper-case)))
19 19 (api:stash-state args)
20 20 (api:call-loc *current-location args)
21 21 (api:call-serv-loc "$ONNEWLOC")
22 22 (void))
23 23
24 24 ;;; 2var
25 25
26 26 ;;; 3expr
27 27
28 28 (defun obj (name)
29 29 (has name *objs))
30 30
31 31 (defun loc (name)
32 32 (has name *locs))
33 33
34 34 ;;; 4code
35 35
36 36 (defun rand (a &optional (b 1))
37 37 (let ((min (min a b))
38 38 (max (max a b)))
39 39 (+ min (chain *math (random (- max min))))))
40 40
41 41 ;;; 5arrays
42 42
43 43 (defun copyarr (to from start count)
44 44 (multiple-value-bind (to-name to-slot)
45 45 (api:var-real-name to)
46 46 (multiple-value-bind (from-name from-slot)
47 47 (api:var-real-name from)
48 (for ((i start))
49 ((< i (min (api:array-size from-name)
50 (+ start count))))
51 ((incf i))
52 (api:set-var to-name (+ start i) to-slot
53 (api:get-var from-name (+ start i) from-slot))))))
48 (loop :for i :from start :to (min (api:array-size from-name)
49 (+ start count))
50 :do (api:set-var to-name (+ start i) to-slot
51 (api:get-var from-name (+ start i) from-slot))))))
54 52
55 53 (defun arrpos (name value &optional (start 0))
56 54 (multiple-value-bind (real-name slot)
57 55 (api:var-real-name name)
58 (for ((i start)) ((< i (api:array-size name))) ((incf i))
59 (when (eq (api:get-var real-name i slot) value)
60 (return-from arrpos i))))
56 (loop :for i :from start :to (api:array-size name)
57 :do (when (eq (api:get-var real-name i slot) value)
58 (return-from arrpos i))))
61 59 -1)
62 60
63 61 (defun arrcomp (name pattern &optional (start 0))
64 62 (multiple-value-bind (real-name slot)
65 63 (api:var-real-name name)
66 (for ((i start)) ((< i (api:array-size name))) ((incf i))
67 (when (funcall (getprop (api:get-var real-name i slot) 'match) pattern)
68 (return-from arrcomp i))))
64 (loop :for i :from start :to (api:array-size name)
65 :do (when (funcall (getprop (api:get-var real-name i slot)
66 'match)
67 pattern)
68 (return-from arrcomp i))))
69 69 -1)
70 70
71 71 ;;; 6str
72 72
73 73 (defun instr (s subs &optional (start 1))
74 74 (+ start (chain s (substring (- start 1)) (search subs))))
75 75
76 76 (defun isnum (s)
77 77 (if (is-na-n s)
78 78 0
79 79 -1))
80 80
81 81 (defun strcomp (s pattern)
82 82 (if (chain s (match pattern))
83 83 -1
84 84 0))
85 85
86 86 (defun strfind (s pattern group)
87 87 (let* ((re (new (*reg-exp pattern)))
88 88 (match (chain re (exec s))))
89 89 (chain match (group group))))
90 90
91 91 (defun strpos (s pattern &optional (group 0))
92 92 (let* ((re (new (*reg-exp pattern)))
93 93 (match (chain re (exec s)))
94 94 (found (chain match (group group))))
95 95 (if found
96 96 (chain s (search found))
97 97 0)))
98 98
99 99 ;;; 7if
100 100
101 101 ;; Has to be a function because it always evaluates all three of its
102 102 ;; arguments
103 103 (defun iif (cond-expr then-expr else-expr)
104 104 (if cond-expr then-expr else-expr))
105 105
106 106 ;;; 8sub
107 107
108 108 (defun gosub (target &rest args)
109 109 (api:call-loc target args)
110 110 (void))
111 111
112 112 (defun func (target &rest args)
113 113 (api:call-loc target args))
114 114
115 115 ;;; 9loops
116 116
117 117 ;;; 10dynamic
118 118
119 119 (defun dynamic (block &rest args)
120 120 (when (stringp block)
121 121 (api:report-error "DYNAMIC can't evaluate arbitrary strings.\\nUse {braces} to create blocks for DYNAMIC."))
122 122 (api:with-call-args args
123 123 (funcall block args))
124 124 (void))
125 125
126 126 (defun dyneval (block &rest args)
127 127 (when (stringp block)
128 128 (api:report-error "DYNEVAL can't evaluate arbitrary strings.\\nUse {braces} to create blocks for DYNEVAL."))
129 129 (api:with-call-args args
130 130 (funcall block args)))
131 131
132 132 ;;; 11main
133 133
134 134 (defun main-p (s)
135 135 (api:add-text :main s)
136 136 (void))
137 137
138 138 (defun main-pl (s)
139 139 (api:add-text :main s)
140 140 (api:newline :main)
141 141 (void))
142 142
143 143 (defun main-nl (s)
144 144 (api:newline :main)
145 145 (api:add-text :main s)
146 146 (void))
147 147
148 148 (defun maintxt (s)
149 149 (api:get-text :main)
150 150 (void))
151 151
152 152 (defun desc (s)
153 153 "")
154 154
155 155 (defun main-clear ()
156 156 (api:clear-text :main)
157 157 (void))
158 158
159 159 ;;; 12stat
160 160
161 161 (defun stat-p (s)
162 162 (api:add-text :stat s)
163 163 (void))
164 164
165 165 (defun stat-pl (s)
166 166 (api:add-text :stat s)
167 167 (api:newline :stat)
168 168 (void))
169 169
170 170 (defun stat-nl (s)
171 171 (api:newline :stat)
172 172 (api:add-text :stat s)
173 173 (void))
174 174
175 175 (defun stattxt (s)
176 176 (api:get-text :stat)
177 177 (void))
178 178
179 179 (defun stat-clear ()
180 180 (api:clear-text :stat)
181 181 (void))
182 182
183 183 (defun cls ()
184 184 (stat-clear)
185 185 (main-clear)
186 186 (cla)
187 187 (cmdclear)
188 188 (void))
189 189
190 190 ;;; 13diag
191 191
192 192 ;;; 14act
193 193
194 194 (defun selact ()
195 195 (loop :for (k v) :of *acts
196 196 :do (when (@ v :selected)
197 197 (return-from selact (@ v :name)))))
198 198
199 199 (defun curacts ()
200 200 (let ((acts (api-call copy-obj *acts)))
201 201 (lambda ()
202 202 (setf *acts acts)
203 203 (void))))
204 204
205 205 ;;; 15objs
206 206
207 207 (defun addobj (name img)
208 208 (setf img (or img ""))
209 209 (setf (getprop *objs name)
210 210 (create :name name :img img :selected nil))
211 211 (api:update-objs)
212 212 (api-call call-serv-loc "$ONOBJADD" name img)
213 213 (void))
214 214
215 215 (defun delobj (name)
216 216 (delete (getprop *objs name))
217 217 (api:update-objs)
218 218 (api-call call-serv-loc "$ONOBJDEL" name)
219 219 (void))
220 220
221 221 (defun killobj (&optional (num nil))
222 222 (if (eq nil num)
223 223 (setf *objs (create))
224 224 (delobj (elt (chain *object (keys *objs)) num)))
225 225 (api:update-objs)
226 226 (void))
227 227
228 228 (defun selobj ()
229 229 (loop :for (k v) :of *objs
230 230 :do (when (@ v :selected)
231 231 (return-from selobj (@ v :name)))))
232 232
233 233 ;;; 16menu
234 234
235 235 (defun menu (menu-name)
236 236 (let ((menu-data (list)))
237 237 (loop :for item-obj :in (@ (api:get-array (api:var-real-name menu-name)) values)
238 238 :for item := (@ item-obj :str)
239 239 :do (cond ((string= item "")
240 240 (break))
241 241 ((string= item "-:-")
242 242 (chain menu-data (push :delimiter)))
243 243 (t
244 244 (let* ((tokens (chain item (split ":"))))
245 245 (when (= (length tokens) 2)
246 246 (chain tokens (push "")))
247 247 (let* ((text (chain tokens (splice 0 (- (length tokens) 2)) (join ":")))
248 248 (loc (getprop tokens (- (length tokens) 2)))
249 249 (icon (getprop tokens (- (length tokens) 1))))
250 250 (chain menu-data
251 251 (push (create :text text
252 252 :loc loc
253 253 :icon icon))))))))
254 254 (api:menu menu-data)
255 255 (void)))
256 256
257 257 ;;; 17sound
258 258
259 259 (defun play (filename &optional (volume 100))
260 260 (let ((audio (new (*audio filename))))
261 261 (setf (getprop *playing filename) audio)
262 262 (setf (@ audio volume) (* volume 0.01))
263 263 (chain audio (play))))
264 264
265 265 (defun close (filename)
266 266 (funcall (getprop *playing filename) stop)
267 267 (delete (getprop *playing filename))
268 268 (void))
269 269
270 270 (defun closeall ()
271 271 (loop :for k :in (chain *object (keys *playing))
272 272 :for v := (getprop *playing k)
273 273 :do (funcall v stop))
274 274 (setf *playing (create)))
275 275
276 276 ;;; 18img
277 277
278 278 (defun refint ()
279 279 ;; "Force interface update" Uh... what exactly do we do here?
280 280 ;(api:report-error "REFINT is not supported")
281 281 )
282 282
283 283 ;;; 19input
284 284
285 285 (defun usertxt ()
286 286 (let ((input (by-id "qsp-input")))
287 287 (@ input value)))
288 288
289 289 (defun cmdclear ()
290 290 (let ((input (by-id "qsp-input")))
291 291 (setf (@ input value) "")))
292 292
293 293 (defun input (text)
294 294 (chain window (prompt text)))
295 295
296 296 ;;; 20time
297 297
298 298 (defun msecscount ()
299 299 (- (chain *date (now)) *started-at))
300 300
301 301 ;;; 21local
302 302
303 303 ;;; 22for
304 304
305 305 ;;; misc
306 306
307 307 (defun rgb (red green blue)
308 308 (+ (<< red 16)
309 309 (<< green 8)
310 310 blue))
311 311
312 312 (defun openqst (name)
313 313 (api-call run-game name))
314 314
315 315 (defun addqst (name)
316 316 (let ((game (api-call filename-game name)))
317 317 ;; Add the game's locations
318 318 (chain *object (assign *locs
319 319 (getprop *games name)))))
320 320
321 321 (defun killqst ()
322 322 ;; Delete all locations not from the current main game
323 323 (loop :for (k v) :in *games
324 324 :do (unless (string= k *main-game)
325 325 (delete (getprop *locs k)))))
326 326
General Comments 0
You need to be logged in to leave comments. Login now