diff --git a/extras/body.html b/extras/body.html --- a/extras/body.html +++ b/extras/body.html @@ -9,6 +9,10 @@
 
 
+
+ + +
diff --git a/extras/default.css b/extras/default.css --- a/extras/default.css +++ b/extras/default.css @@ -29,6 +29,10 @@ flex: 3 3 30px; } +.qsp-col3 { + flex: 0 0 40px; +} + #qsp-main { flex: 6 6 60px; } @@ -58,7 +62,7 @@ outline: #9E9E9E outset 3px } -// Dropdown +/* Dropdown */ #qsp-dropdown { display: none; @@ -82,3 +86,18 @@ #qsp-dropdown a:hover { background-color: #ddd; } + +/* Buttons */ + +.qsp-col3 a, .qsp-col3 img { + width: 50px; + height: 50px; +} + +#qsp-btn-save { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAACSklEQVRoge3ZPWgUQRjG8V/iRRFU/GoEQdSohSgWWqQSooVgK9iJFiKCnYV2BkFQsBRBQQwWVsHKIoWxEOzEwmhhogbRMhhFicTvYm+JCUlmZzabRLN/OPaWeZ+ZeW7feXf2lpqampqamnRaImKP4hA2VjCP27hbpoNGwbib2IPreB+IPYY7M7SvxWYM4QNO4QqWyQxVRgdeYnnB+K5A+wUcbB7z+O14hxPx08toLRDTgfv4mjrIJFrwwMS0HsABXMTxlE6LpNYqfE7pPJIBdOKhLM1uxIiLrpG5YtC4GSLMVGGkLdD+GpfxAuvxaVL7oCzN+jCG7iKDVmHkKS5hSSBuJ3bg6hRt+Zrpa553z8bEuoQrUVXk1exwKLBI1ZpPBnAL+0KBqanVim1Ykaifji+yNfIrVphipB1n8BgjCfqZ2IrTuIZXMcIUIydxFj8TtEW4JysW52JEKWtkVHUm4EdzjChSrkgLlmJXghb6m8ep9MN4K25XjvTF3sCaElrT6McS+0w2Mirb+JWhrH4CC/0+UpjUK7Ia5/86f4IeHMHeEvPJ+4km1chHE43k9KROpCyLPrViym8/vjW/b5Jt3acjL7/RzEX5bRg3sjKg+2fK7/PmZ9aZzdTqxwYzp06IBZFaDeHUCbFgUquy1Anx35TfRWXkd+WzCBOcQxEjQ7JH0PmiHW9CQUWM9Mr+Y+osO6ME8nF7Q4FFn8T2y14VDMt2vsFfqCRbZBvTdbLXFI9CgphHyjbsVu4+EcMInuH7HI1XU1NTU7OI+QMFe2N82rtssgAAAABJRU5ErkJggg=='); +} + +#qsp-btn-load { + background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAACCklEQVRoge3Yz6sNYRzH8deVexNxSaEoroWFUuomOceSPVnIwsbSxs6Psrgphf9AsrZR7kJWsroUlrZKKZRSl4USGouZk9Npzp1n5pm5x4/nXdNzpvP9Pp/v95nv82OGRCKRSCQS/w8zuIn3yGpe37CEQ6sedQk38BA7G/jO4BQ+YEebQZUxVfH/OxzGVSxX2D4o2mO4jmt4jpNFe6d5mPFkRbvQ0H9h6OqUtR33/xXr0celGn4/sYjXoQ5dJ3ILB7AOW2r4bcIj7GsrkEFpXWyrwwbaf15nXWqv6SqK1abuHDmPjV0EMobhBWIZt8cZVu0j2ZDNHF7gblRozdiO49g1zqDOEzmKJ7gcGVQTzmLDSgZ1Eunh2dD9aewpsXtctH3cwzn5ALysoVWlXZvhleMV5ovfU8J363mciAliRLsRg0Q244vfT3A/zgT2cQHbImIY1S4ldPk9Ii+NH8V9H08DfbfiY6BtiHYpoYmMBr4bbwN9YzfVoEELnew9+blpwBv5u0oI9wPtQrUbkWFaXqOzsZ01IFg7pLQOyp/A58igmhCsHZJInYndNsHa/0wiVWTy9/a5NjprQGvag0Qmwd462iGltdQ8lihqlVVIIn/9/CAvrajDWgTRB8VhMt1/aSljVr4RToc6hJTWioe1jujJD4rfQx2qRvuTyX1JuTIh3UQikUgkEhPnF+1xZ9hHnLjAAAAAAElFTkSuQmCC'); +} diff --git a/src/api.ps b/src/api.ps --- a/src/api.ps +++ b/src/api.ps @@ -36,6 +36,8 @@ (defm (root api base64-to-state) (data) (setf (root state-stash) (decode-u-r-i-component (atob data))) (let ((data (*j-s-o-n.parse (root state-stash)))) + (api-call clear-id :qsp-main) + (api-call clear-id :qsp-stat) (api-call clear-act) (setf (root vars) (ps:@ data vars)) (setf (root objs) (ps:@ data objs)) @@ -198,3 +200,11 @@ :do (incf i) :do (incf elt.inner-h-t-m-l (api-call make-menu-item-html i item.text item.icon item.loc))) (setf elt.style.display "block"))) + +;;; Content + +(defm (root api clean-audio) () + (loop :for k :in (*object.keys (root playing)) + :for v := (ps:getprop (root playing) k) + :do (when (ps:@ v ended) + (ps:delete (ps:@ (root playing) k))))) diff --git a/src/intrinsic-macros.lisp b/src/intrinsic-macros.lisp --- a/src/intrinsic-macros.lisp +++ b/src/intrinsic-macros.lisp @@ -128,6 +128,9 @@ ;;; 17sound +(ps:defpsmacro isplay (filename) + `(funcall (root playing includes) ,filename)) + ;;; 18img ;;; 19input diff --git a/src/intrinsics.ps b/src/intrinsics.ps --- a/src/intrinsics.ps +++ b/src/intrinsics.ps @@ -197,13 +197,13 @@ (defm (root lib delobj) (name) (let ((index (ps:chain (root objs) (index-of name)))) (when (> index -1) - (funcall (root lib killobj) index))) + (funcall (root lib killobj) (1+ index)))) (values)) -(defm (root lib killobj) (&optional num) - (if num - (ps:chain (root objs) (splice (1+ num) 1)) - (setf (root objs) (list))) +(defm (root lib killobj) (&optional (num nil)) + (if (eq nil num) + (setf (root objs) (list)) + (ps:chain (root objs) (splice (1- num) 1))) (api-call update-objs) (values)) @@ -232,13 +232,21 @@ ;;; 17sound -(defm (root lib play) ()) - -(defm (root lib isplay) ()) +(defm (root lib play) (filename &optional (volume 100)) + (let ((audio (ps:new (*audio filename)))) + (setf (ps:getprop (root playing) filename) audio) + (setf (ps:@ audio volume) (* volume 0.01)) + (ps:chain audio (play)))) -(defm (root lib close) ()) +(defm (root lib close) (filename) + (funcall (root playing filename) stop) + (ps:delete (root playing filename))) -(defm (root lib closeall) ()) +(defm (root lib closeall) () + (loop :for k :in (*object.keys (root playing)) + :for v := (ps:getprop (root playing) k) + :do (funcall v stop)) + (setf (root playing) (ps:create))) ;;; 18img diff --git a/src/main.ps b/src/main.ps --- a/src/main.ps +++ b/src/main.ps @@ -2,11 +2,22 @@ (in-package sugar-qsp) (setf (root) - (ps:create vars (ps:create) - objs (list) - state-stash (ps:create) - acts (ps:create) - locs (ps:create))) + (ps:create + ;;; Game session state + ;; Variables + vars (ps:create) + ;; Inventory (objects) + objs (list) + ;;; Transient state + ;; Savegame data + state-stash (ps:create) + ;; List of audio files being played + playing (ps:create) + ;;; Game data + ;; ACTions + acts (ps:create) + ;; Locations + locs (ps:create))) ;; Launch the game from the first location (setf window.onload