Show More
@@ -1,5 +1,4 b'' | |||||
1 |
|
1 | |||
2 | * MENU with async/await |
|
|||
3 | * Special locations |
|
2 | * Special locations | |
4 | * Special variables |
|
3 | * Special variables | |
5 | * CLI build for Linux |
|
4 | * CLI build for Linux | |
@@ -11,6 +10,7 b'' | |||||
11 | * Report JUMP with missing label (in tagbody) |
|
10 | * Report JUMP with missing label (in tagbody) | |
12 |
|
11 | |||
13 | * Build Istreblenie |
|
12 | * Build Istreblenie | |
|
13 | * Build Цветохимия | |||
14 | * Windows GUI (for the compiler) |
|
14 | * Windows GUI (for the compiler) | |
15 | * Save-load game in slots |
|
15 | * Save-load game in slots | |
16 | * Resizable frames |
|
16 | * Resizable frames |
@@ -1,13 +1,11 b'' | |||||
1 | ql alexandria |
|
1 | ql alexandria | |
2 | ql esrap |
|
2 | ql esrap | |
3 | ql parenscript |
|
3 | ql parenscript | |
4 | ql cl-uglify-js |
|
|||
5 | ql flute |
|
4 | ql flute | |
6 |
|
5 | |||
7 | ql cl-ppcre |
|
6 | ql cl-ppcre | |
8 | ql anaphora |
|
7 | ql anaphora | |
9 | ql named-readtables |
|
8 | ql named-readtables | |
10 | ql parse-js |
|
|||
11 | ql cl-unicode |
|
9 | ql cl-unicode | |
12 | ql flexi-streams |
|
10 | ql flexi-streams | |
13 | ql trivial-gray-streams |
|
11 | ql trivial-gray-streams |
@@ -62,6 +62,19 b'' | |||||
62 | (when loc |
|
62 | (when loc | |
63 | (funcall loc args)))))) |
|
63 | (funcall loc args)))))) | |
64 |
|
64 | |||
|
65 | (defun filename-game (filename) | |||
|
66 | (let ((game-name (chain filename (match "(.*/)?([^.]+)(\\.[a-zA-Z]+)?") 2)))) | |||
|
67 | (getprop (root games) game-name)) | |||
|
68 | ||||
|
69 | (defun run-game (name) | |||
|
70 | (let ((game (filename-game name))) | |||
|
71 | (setf (root main-game) name) | |||
|
72 | ;; Replace locations with the new game's | |||
|
73 | (setf (root locs) game) | |||
|
74 | (funcall (getprop game | |||
|
75 | (chain *object (keys game) 0)) | |||
|
76 | (list)))) | |||
|
77 | ||||
65 | ;;; Misc |
|
78 | ;;; Misc | |
66 |
|
79 | |||
67 | (defun newline (key) |
|
80 | (defun newline (key) |
@@ -13,10 +13,11 b'' | |||||
13 | (void)) |
|
13 | (void)) | |
14 |
|
14 | |||
15 | (defun xgoto (target args) |
|
15 | (defun xgoto (target args) | |
|
16 | (setf args (or args (list))) | |||
16 | (api:clear-act) |
|
17 | (api:clear-act) | |
17 | (setf (root current-location) (chain target (to-upper-case))) |
|
18 | (setf (root current-location) (chain target (to-upper-case))) | |
18 | (api:stash-state args) |
|
19 | (api:stash-state args) | |
19 |
(api:call-loc (root current-location) |
|
20 | (api:call-loc (root current-location) args) | |
20 | (void)) |
|
21 | (void)) | |
21 |
|
22 | |||
22 | ;;; 2var |
|
23 | ;;; 2var | |
@@ -292,11 +293,18 b'' | |||||
292 | hex)))) |
|
293 | hex)))) | |
293 | (+ "#" (rgb-to-hex red) (rgb-to-hex green) (rgb-to-hex red)))) |
|
294 | (+ "#" (rgb-to-hex red) (rgb-to-hex green) (rgb-to-hex red)))) | |
294 |
|
295 | |||
295 | (defun openqst () |
|
296 | (defun openqst (name) | |
296 | (api:report-error "OPENQST is not supported.")) |
|
297 | (api-call run-game name)) | |
297 |
|
298 | |||
298 | (defun addqst () |
|
299 | (defun addqst (name) | |
299 | (api:report-error "ADDQST is not supported. Bundle the library with the main game.")) |
|
300 | (let ((game (api-call filename-game name))) | |
|
301 | ;; Add the game's locations | |||
|
302 | (chain *object (assign (root locs) | |||
|
303 | (getprop (root games) name))))) | |||
300 |
|
304 | |||
301 | (defun killqst () |
|
305 | (defun killqst () | |
302 | (api:report-error "KILLQST is not supported.")) |
|
306 | ;; Delete all locations not from the current main game | |
|
307 | (loop :for (k v) :in (root games) | |||
|
308 | :do (unless (string= k (root main-game)) | |||
|
309 | (delete (getprop (root locs) k))))) | |||
|
310 |
@@ -24,7 +24,7 b'' | |||||
24 | alert prompt |
|
24 | alert prompt | |
25 | set-timeout set-interval clear-interval |
|
25 | set-timeout set-interval clear-interval | |
26 | *promise *j-s-o-n |
|
26 | *promise *j-s-o-n | |
27 | href parse |
|
27 | href parse match | |
28 | set-prototype-of |
|
28 | set-prototype-of | |
29 | body append-child remove-child |
|
29 | body append-child remove-child | |
30 | add ; remove (is already in COMMON-LISP) |
|
30 | add ; remove (is already in COMMON-LISP) |
@@ -11,8 +11,8 b'' | |||||
11 | (values)) |
|
11 | (values)) | |
12 |
|
12 | |||
13 | (defun parse-opts (args) |
|
13 | (defun parse-opts (args) | |
14 | (let ((mode :source) |
|
14 | (let ((mode :sources) | |
15 | (data (list :source nil :target nil :js nil :css nil :body nil :compile nil :beautify nil))) |
|
15 | (data (list :sources nil :target nil :js nil :css nil :body nil :compile nil :beautify nil))) | |
16 | (loop :for arg :in args |
|
16 | (loop :for arg :in args | |
17 | :do (alexandria:switch (arg :test #'string=) |
|
17 | :do (alexandria:switch (arg :test #'string=) | |
18 | ("-o" (setf mode :target)) |
|
18 | ("-o" (setf mode :target)) | |
@@ -22,9 +22,9 b'' | |||||
22 | ("-c" (setf (getf data :compile) t)) |
|
22 | ("-c" (setf (getf data :compile) t)) | |
23 | ("--beautify" (setf (getf data :beautify) t)) |
|
23 | ("--beautify" (setf (getf data :beautify) t)) | |
24 | (t (push arg (getf data mode))))) |
|
24 | (t (push arg (getf data mode))))) | |
25 |
(unless ( |
|
25 | (unless (< 0 (length (getf data :sources))) | |
26 | (print-usage) |
|
26 | (print-usage) | |
27 |
(report-error "There should be |
|
27 | (report-error "There should be at least one source")) | |
28 | (unless (> 1 (length (getf data :target))) |
|
28 | (unless (> 1 (length (getf data :target))) | |
29 | (print-usage) |
|
29 | (print-usage) | |
30 | (report-error "There should be no more than one target")) |
|
30 | (report-error "There should be no more than one target")) | |
@@ -33,12 +33,12 b'' | |||||
33 | (report-error "There should be no more than one body")) |
|
33 | (report-error "There should be no more than one body")) | |
34 | (unless (getf data :target) |
|
34 | (unless (getf data :target) | |
35 | (setf (getf data :target) |
|
35 | (setf (getf data :target) | |
36 | (let* ((source (first (getf data :source))) |
|
36 | (let* ((sources (first (getf data :sources))) | |
37 | (tokens (uiop:split-string source :separator ".")) |
|
37 | (tokens (uiop:split-string sources :separator ".")) | |
38 | (target (format nil "~{~A~^.~}.html" |
|
38 | (target (format nil "~{~A~^.~}.html" | |
39 | (butlast tokens)))) |
|
39 | (butlast tokens)))) | |
40 | (list target)))) |
|
40 | (list target)))) | |
41 |
(list :source |
|
41 | (list :sources (getf data :sources) | |
42 | :target (first (getf data :target)) |
|
42 | :target (first (getf data :target)) | |
43 | :js (getf data :js) |
|
43 | :js (getf data :js) | |
44 | :css (getf data :css) |
|
44 | :css (getf data :css) | |
@@ -102,12 +102,25 b'' | |||||
102 | :stream out |
|
102 | :stream out | |
103 | :pretty nil)))) |
|
103 | :pretty nil)))) | |
104 |
|
104 | |||
105 | (defmethod initialize-instance ((compiler compiler) &key source ((:js js-files)) ((:css css-files)) ((:body body-file)) compile &allow-other-keys) |
|
105 | (defun filename-game (filename) | |
|
106 | (let ((filename (alexandria:lastcar (uiop:split-string filename :separator "/")))) | |||
|
107 | (format nil "~{~A~^.~}" (butlast (uiop:split-string filename :separator "."))))) | |||
|
108 | ||||
|
109 | (defmethod initialize-instance ((compiler compiler) &key sources ((:js js-files)) ((:css css-files)) ((:body body-file)) compile &allow-other-keys) | |||
106 | (call-next-method) |
|
110 | (call-next-method) | |
107 | (with-slots (body css js) |
|
111 | (with-slots (body css js) | |
108 | compiler |
|
112 | compiler | |
109 | ;; Compile the game's JS |
|
113 | ;; Compile the game's JS | |
110 | (push (list* 'progn (parse-file source)) js) |
|
114 | (dolist (source sources) | |
|
115 | (let ((ps (parse-file source)) | |||
|
116 | (game-name (filename-game source))) | |||
|
117 | (destructuring-bind (kw &rest locations) | |||
|
118 | ps | |||
|
119 | (unless (eq kw 'lib:game) | |||
|
120 | (report-error "Internal error!")) | |||
|
121 | (push | |||
|
122 | `(lib:game (,game-name) ,@locations) | |||
|
123 | js)))) | |||
111 | ;; Does the user need us to do anything else |
|
124 | ;; Does the user need us to do anything else | |
112 | (unless compile |
|
125 | (unless compile | |
113 | ;; Read in body |
|
126 | ;; Read in body | |
@@ -129,7 +142,7 b'' | |||||
129 | (alexandria:write-string-into-file |
|
142 | (alexandria:write-string-into-file | |
130 | (if (compile-only compiler) |
|
143 | (if (compile-only compiler) | |
131 | ;; Just the JS |
|
144 | ;; Just the JS | |
132 |
|
|
145 | (js-sources compiler) | |
133 | ;; All of it |
|
146 | ;; All of it | |
134 | (html-sources compiler)) |
|
147 | (html-sources compiler)) | |
135 | (target compiler) :if-exists :supersede)) |
|
148 | (target compiler) :if-exists :supersede)) |
@@ -3,7 +3,7 b'' | |||||
3 |
|
3 | |||
4 | (setf (root) |
|
4 | (setf (root) | |
5 | (create |
|
5 | (create | |
6 | ;;; Game session state |
|
6 | ;;; Game session state (saved in savegames) | |
7 | ;; Variables |
|
7 | ;; Variables | |
8 | vars (create) |
|
8 | vars (create) | |
9 | ;; Inventory (objects) |
|
9 | ;; Inventory (objects) | |
@@ -14,17 +14,25 b'' | |||||
14 | ;; Timers |
|
14 | ;; Timers | |
15 | timer-interval 500 |
|
15 | timer-interval 500 | |
16 | timer-obj nil |
|
16 | timer-obj nil | |
|
17 | ;; Games | |||
|
18 | loaded-games (list) | |||
|
19 | ||||
17 | ;;; Transient state |
|
20 | ;;; Transient state | |
|
21 | ;; ACTions | |||
|
22 | acts (create) | |||
18 | ;; Savegame data |
|
23 | ;; Savegame data | |
19 | state-stash (create) |
|
24 | state-stash (create) | |
20 | ;; List of audio files being played |
|
25 | ;; List of audio files being played | |
21 | playing (create) |
|
26 | playing (create) | |
22 | ;; Local variables stack (starts with an empty frame) |
|
27 | ;; Local variables stack (starts with an empty frame) | |
23 | locals (list) |
|
28 | locals (list) | |
|
29 | ||||
24 | ;;; Game data |
|
30 | ;;; Game data | |
25 | ;; ACTions |
|
31 | ;; Games (filename -> [locations]) | |
26 |
|
|
32 | games (list) | |
27 | ;; Locations |
|
33 | ;; The main (non library) game. Updated by openqst | |
|
34 | main-game nil | |||
|
35 | ;; Active locations | |||
28 | locs (create))) |
|
36 | locs (create))) | |
29 |
|
37 | |||
30 | ;; Launch the game from the first location |
|
38 | ;; Launch the game from the first location | |
@@ -36,9 +44,8 b'' | |||||
36 | ;; For $COUNTER and SETTIMER |
|
44 | ;; For $COUNTER and SETTIMER | |
37 | (#.(intern "SET-TIMER" "SUGAR-QSP.API") |
|
45 | (#.(intern "SET-TIMER" "SUGAR-QSP.API") | |
38 | (root timer-interval)) |
|
46 | (root timer-interval)) | |
39 |
;; Start the first |
|
47 | ;; Start the first game | |
40 | (funcall (getprop (root locs) |
|
48 | (#.(intern "RUN-GAME" "SUGAR-QSP.API") | |
41 |
|
|
49 | (chain *object (keys (root games)) 0)) | |
42 | (list)) |
|
|||
43 | (values))) |
|
50 | (values))) | |
44 |
|
51 |
@@ -10,7 +10,7 b'' | |||||
10 | #:vars #:objs #:current-location |
|
10 | #:vars #:objs #:current-location | |
11 | #:started-at #:timer-interval #:timer-obj |
|
11 | #:started-at #:timer-interval #:timer-obj | |
12 | #:state-stash #:playing #:locals |
|
12 | #:state-stash #:playing #:locals | |
13 | #:acts #:locs)) |
|
13 | #:acts #:locs #:games)) | |
14 |
|
14 | |||
15 | ;;; API functions |
|
15 | ;;; API functions | |
16 | (defpackage :sugar-qsp.api |
|
16 | (defpackage :sugar-qsp.api | |
@@ -39,7 +39,7 b'' | |||||
39 | (defpackage :sugar-qsp.lib |
|
39 | (defpackage :sugar-qsp.lib | |
40 | (:use :cl :ps :sugar-qsp.main :sugar-qsp.js) |
|
40 | (:use :cl :ps :sugar-qsp.main :sugar-qsp.js) | |
41 | (:local-nicknames (#:api :sugar-qsp.api)) |
|
41 | (:local-nicknames (#:api :sugar-qsp.api)) | |
42 | (:export #:str #:exec #:qspblock #:qspfor #:location |
|
42 | (:export #:str #:exec #:qspblock #:qspfor #:game #:location | |
43 | #:qspcond #:qspvar #:set #:local #:jump |
|
43 | #:qspcond #:qspvar #:set #:local #:jump | |
44 |
|
44 | |||
45 | #:killvar #:killall |
|
45 | #:killvar #:killall |
@@ -176,7 +176,8 b'' | |||||
176 |
|
176 | |||
177 | (p:defrule sugar-qsp-grammar (and (* (or spaces #\newline)) |
|
177 | (p:defrule sugar-qsp-grammar (and (* (or spaces #\newline)) | |
178 | (* location)) |
|
178 | (* location)) | |
179 | (:function second)) |
|
179 | (:lambda (list) | |
|
180 | `(lib:game ,@(second list)))) | |||
180 |
|
181 | |||
181 | (p:defrule location (and location-header block-body location-end) |
|
182 | (p:defrule location (and location-header block-body location-end) | |
182 | (:destructure (header body end) |
|
183 | (:destructure (header body end) |
@@ -29,11 +29,20 b'' | |||||
29 |
|
29 | |||
30 | ;;; 1loc |
|
30 | ;;; 1loc | |
31 |
|
31 | |||
|
32 | (defpsmacro game ((name) &body body) | |||
|
33 | `(progn | |||
|
34 | (setf (root games ,name) | |||
|
35 | (create)) | |||
|
36 | ,@(loop :for location :in body | |||
|
37 | :collect `(setf (root games ,name ,(caadr location)) | |||
|
38 | ,location)))) | |||
|
39 | ||||
32 | (defpsmacro location ((name) &body body) |
|
40 | (defpsmacro location ((name) &body body) | |
33 | `(setf (root locs ,name) |
|
41 | (declare (ignore name)) | |
34 | (async-lambda (args) |
|
42 | "Name is used by the game macro above" | |
35 | (label-block () |
|
43 | `(async-lambda (args) | |
36 | ,@body)))) |
|
44 | (label-block () | |
|
45 | ,@body))) | |||
37 |
|
46 | |||
38 | (defpsmacro goto% (target &rest args) |
|
47 | (defpsmacro goto% (target &rest args) | |
39 | `(progn |
|
48 | `(progn |
General Comments 0
You need to be logged in to leave comments.
Login now