Libregamejam version of the game

This commit is contained in:
Jaidyn Ann 2023-07-15 05:04:17 -05:00
parent 72c49e3c89
commit 8d4fcb2295
12 changed files with 174 additions and 56 deletions

View File

@ -199,6 +199,7 @@ Returns the state for use with STATE-LOOP, pay attention!"
(list :parameters (list :dialogue (cdr dialogue-list) :map map)) (list :parameters (list :dialogue (cdr dialogue-list) :map map))
(progn (progn
(:hide-cursor) (:hide-cursor)
(clear-input)
(list :drop (1+ (or (getf dialogue :drop) 0)) (list :drop (1+ (or (getf dialogue :drop) 0))
:function (getf dialogue :function) :function (getf dialogue :function)
:parameters (if (member :parameters dialogue) :parameters (if (member :parameters dialogue)

View File

@ -13,7 +13,7 @@
;;;; You should have received a copy of the GNU General Public License ;;;; You should have received a copy of the GNU General Public License
;;;; along with this program. If not, see <https://www.gnu.org/licenses/>. ;;;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;;; FLORA-SEARCH-AURORA.DISPLAY ;;;; FLORA-SEARCH-AURORA.DISPLAY
;;;; All display-related curses go here. ;;;; All display-related curses go here.
(in-package :flora-search-aurora.display) (in-package :flora-search-aurora.display)

View File

@ -13,7 +13,7 @@
;;;; You should have received a copy of the GNU General Public License ;;;; You should have received a copy of the GNU General Public License
;;;; along with this program. If not, see <https://www.gnu.org/licenses/>. ;;;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;;; FLORA-SEARCH-AURORA.ENGINE ;;;; FLORA-SEARCH-AURORA.ENGINE
;;;; The core of the games engine, the loop. Not much to see here other ;;;; The core of the games engine, the loop. Not much to see here other
;;;; than a loop. Honest! ;;;; than a loop. Honest!
@ -39,7 +39,7 @@ overheat, or something ¯\_(ツ)_/¯"
(let ((state-result (let ((state-result
(apply (car states) (cons matrix state-params)))) ;; Run the last-added state-loop. (apply (car states) (cons matrix state-params)))) ;; Run the last-added state-loop.
(:print-screen-matrix (:matrix-delta last-matrix matrix)) ;; Print its results. (:print-screen-matrix (:matrix-delta last-matrix matrix)) ;; Print its results.
;; (format *error-output* "~S~%" state-result) ;; (format *error-output* "S::~S~%D::~S~%" states state-result)
(force-output) (force-output)
(state-loop (state-loop
(cond ((listp state-result) (cond ((listp state-result)

View File

@ -446,9 +446,38 @@ run the :USE function of the nearest entity, if it has any."
:en "... You're pretentious, as per usual."))) :en "... You're pretentious, as per usual.")))
(defun childhood-friend-dialogue-lavendula (sasha)
(start-dialogue
(say sasha :eo "Ee... dankon?"
:en "Uh... thanks?")
(say sasha :eo "Kion vi eĉ alcelas per ĉi tio? Je dio."
:en "What're you even getting at? Jesus.")
(say 'player :eo "Saŝa, mi pensas ke lavendo perfekte akordas vin."
:en "Sasha, I think lavender fits you perfectly.")
(say 'player :eo "Vi malfidas ĉiun, eĉ tiujn kiuj plej fidas je vi."
:en "You distrust and alienate everyone, even those who are most loyal to you.")
(say 'player :eo "Mi eble ne diris rekte ĝis nun, do jen:"
:en "Maybe I haven't said it directly before, so I'll go ahead now:")
(face sasha ";w:" ":w:")
(say 'player :eo "Mi zorgas pri vi multe, vi ĉiam estis mia plej kara amiko."
:en "I care about you a lot, Sasha, and you've always been my dearest friend.")
(say 'player :eo "Malgraŭ via mistraktado, mi neniam foriris, ĉu ne?"
:en "Despite your pushing me away -- violently -- I never did leave, right?")
(say 'player :eo "Mi konscias ke vi \"testadis\" nian amikecon, sed vi ne devas tion fari plu."
:en "I know you try to \"test\" our friendship, but you don't have to do that anymore.")
(say sasha :en "...")
(say sasha :eo "... ĉu vere bonas?"
:en "... is it really alright?")
(say 'player :eo "Jes. Friends?"
:en "Yea. Friends?")
(face sasha "<w<" "^o^")
(say sasha :eo "Amikoj."
:en "Friends.")))
(defun childhood-friend-dialogue-bracelet (map sasha) (defun childhood-friend-dialogue-bracelet (map sasha)
(append (childhood-friend-dialogue-bracelet-intro sasha) (append (childhood-friend-dialogue-bracelet-intro sasha)
(if (getf-act map :sasha-flourish) (if (getf-act map :encourage-friendship)
(childhood-friend-dialogue-bracelet-good-end sasha) (childhood-friend-dialogue-bracelet-good-end sasha)
(childhood-friend-dialogue-bracelet-bad-end sasha)))) (childhood-friend-dialogue-bracelet-bad-end sasha))))
@ -456,11 +485,17 @@ run the :USE function of the nearest entity, if it has any."
(defun childhood-friend-use (map item-plist &optional entity-id) (defun childhood-friend-use (map item-plist &optional entity-id)
(let ((item-id (:string->symbol (getf item-plist :id)))) (let ((item-id (:string->symbol (getf item-plist :id))))
(cond ((eq item-id 'bracelet) (cond ((eq item-id 'bracelet)
(if (getf-act map :encourage-friendship)
(setf (getf-act map :perfect-friendship) 't))
(make-dialogue-state (make-dialogue-state
map (childhood-friend-dialogue-bracelet map entity-id))) map (childhood-friend-dialogue-bracelet map entity-id)))
((eq item-id 'neĝfloro) ((eq item-id 'neĝfloro)
(remove-item map entity-id) (remove-item map entity-id)
(make-dialogue-state map (childhood-friend-dialogue-edelweiss entity-id))) (make-dialogue-state map (childhood-friend-dialogue-edelweiss entity-id)))
((eq item-id 'lavendula)
(setf (getf-act map :encourage-friendship) 't)
(remove-item map entity-id)
(make-dialogue-state map (childhood-friend-dialogue-lavendula entity-id)))
('t ('t
(refusal-use map item-plist entity-id))))) (refusal-use map item-plist entity-id)))))
@ -569,15 +604,11 @@ avoid triggering this."
(defun flashback-childhood-friend-use (map item-plist &optional entity-id) (defun flashback-childhood-friend-use (map item-plist &optional entity-id)
(let ((item-id (:string->symbol (getf item-plist :id)))) (let ((item-id (:string->symbol (getf item-plist :id))))
(cond ((eq item-id 'bracelet)) (cond ((eq item-id 'bracelet)
;; If player gives her the special bracelet, skip the dialogue intro ;; If player gives her the special bracelet, skip the dialogue intro
(make-dialogue-state (make-dialogue-state
map (flashback-childhood-friend-dialogue-bracelet map entity-id)) map (flashback-childhood-friend-dialogue-bracelet map entity-id)))
((eq item-id 'neĝfloro) ('t (childhood-friend-use map item-plist entity-id)))))
(make-dialogue-state map (childhood-friend-dialogue-edelweiss entity-id)))
('t
;; Otherwise, have her politely refuse. =w=
(refusal-use map item-plist entity-id)))))
@ -1284,9 +1315,8 @@ Initializes the current instance of the game, and such."
(defparameter *flashback-casino-map* (🌍:plist->map (metacopy:copy-thing *flashback-casino-map-plist*))) (defparameter *flashback-casino-map* (🌍:plist->map (metacopy:copy-thing *flashback-casino-map-plist*)))
(defparameter *flashback-school-map* (🌍:plist->map (metacopy:copy-thing *flashback-school-map-plist*))) (defparameter *flashback-school-map* (🌍:plist->map (metacopy:copy-thing *flashback-school-map-plist*)))
(defparameter *outdoors-map* (🌍:plist->map (metacopy:copy-thing *outdoors-map-plist*))) (defparameter *outdoors-map* (🌍:plist->map (metacopy:copy-thing *outdoors-map-plist*)))
(take-item *base-map* 'neĝfloro) (take-item *base-map* 'lavendula)
;; (make-flashback-state (alexandria:random-elt (flashbacks))))) (make-flashback-state (alexandria:random-elt (flashbacks)))))
(make-overworld-state *base-map*)))
(defun main-menu () (defun main-menu ()

View File

@ -94,3 +94,11 @@ Part of INVENTORY-STATE."
(lambda (matrix &key (title title) (subtitle subtitle) (side-text side-text) (return return) (progress 0)) (lambda (matrix &key (title title) (subtitle subtitle) (side-text side-text) (return return) (progress 0))
(funcall #'intermission-state (funcall #'intermission-state
matrix :title title :subtitle subtitle :side-text side-text :progress progress :return return))) matrix :title title :subtitle subtitle :side-text side-text :progress progress :return return)))
(defun make-intermission-state (title subtitle side-text return)
"Return a state-plist for intermission, for use with STATE-LOOP."
(list :parameters nil
:function
(make-intermission-function title subtitle side-text return)))

View File

@ -13,7 +13,7 @@
;;;; You should have received a copy of the GNU General Public License ;;;; You should have received a copy of the GNU General Public License
;;;; along with this program. If not, see <https://www.gnu.org/licenses/>. ;;;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;;; FLORA-SEARCH-AURORA.INVENTORY ;;;; FLORA-SEARCH-AURORA.INVENTORY 🎒
;;;; The menu for inventory selection/management. ;;;; The menu for inventory selection/management.
(in-package :flora-search-aurora.inventory) (in-package :flora-search-aurora.inventory)
@ -95,7 +95,7 @@ Part of INVENTORY-STATE."
(list :parameters (list :map map :inventory inventory-menu))) (list :parameters (list :map map :inventory inventory-menu)))
;; Return the menu itself, if non-nil. ;; Return the menu itself, if non-nil.
(menu-return (menu-return
menu-return) 't)
;; If menu-return was non-nil, the user left the menu. Lets leave inventory! ;; If menu-return was non-nil, the user left the menu. Lets leave inventory!
('t ('t
(list :drop 1 :parameters (list :map map)))))) (list :drop 1 :parameters (list :map map))))))
@ -108,15 +108,15 @@ Part of INVENTORY-STATE."
(defun render-selected-item (matrix items) (defun render-selected-item (matrix items)
"Draw the title, avatar, and description of the currently-selected item to "Draw the title, avatar, and description of the currently-selected item to
the bottom of the screen." the bottom of the screen."
(let* ((item (menu:selected-menu-item items)) (let* ((item (📋:selected-menu-item items))
(name (list :en (or (getf item :name-en) (getf item :inv-name-en) (getf item :id)) (name (list :en (or (getf item :name-en) (getf item :inv-name-en) (getf item :id))
:eo (or (getf item :name-eo) (getf item :inv-name-eo)))) :eo (or (getf item :name-eo) (getf item :inv-name-eo))))
(desc (list :en (getf item :desc-en) (desc (list :en (getf item :desc-en)
:eo (getf item :desc-eo)))) :eo (getf item :desc-eo))))
(display:render-string-verbatim matrix (str:concat ":" (:getf-lang name) ": " (:render-string-verbatim matrix (str:concat ":" (:getf-lang name) ": "
(getf item :avatar)) (getf item :avatar))
'(:x 1 :y 17)) '(:x 1 :y 17))
(display:render-string matrix (:getf-lang desc) (:render-string matrix (:getf-lang desc)
'(:x 1 :y 18) :width 70))) '(:x 1 :y 18) :width 70)))
@ -140,7 +140,7 @@ Part of INVENTORY-STATE."
(inventory-state-update map inventory submenu)) (inventory-state-update map inventory submenu))
(defun make-inventory-state (map) (defun make-inventory-function (map)
"Return a state-function for inventory-listing, for use with STATE-LOOP." "Return a state-function for inventory-listing, for use with STATE-LOOP."
(lambda (matrix &key (map map) (submenu nil) (inventory (items->menu-plist (gethash :items map)))) (lambda (matrix &key (map map) (submenu nil) (inventory (items->menu-plist (gethash :items map))))
(apply #'🎒:inventory-state (apply #'🎒:inventory-state

View File

@ -32,13 +32,6 @@ rectangle as defined by its TOP-LEFT-CORNER & BOTTOM-RIGHT-CORNER."
(>= (getf point :y) (getf top-left-corner :y)))) (>= (getf point :y) (getf top-left-corner :y))))
(defmacro remove-from-alistf (key alist)
"Remove the given item from an associative list destructively."
`(alexandria:removef
,alist ,key
:test (lambda (key item) (eq key (car item)))))
;;; ——————————————————————————————————— ;;; ———————————————————————————————————
;;; Accessors ;;; Accessors
@ -61,7 +54,7 @@ rectangle as defined by its TOP-LEFT-CORNER & BOTTOM-RIGHT-CORNER."
Literally kill them, show no mercy, dig your sharp nails into their fleshy Literally kill them, show no mercy, dig your sharp nails into their fleshy
stomache and PULL HARD, show NO REMORSE. RAAAAAA 🗡🩸" stomache and PULL HARD, show NO REMORSE. RAAAAAA 🗡🩸"
(mapcar (lambda (chunk-alist) (mapcar (lambda (chunk-alist)
(overworld::remove-from-alistf entity-id (cdr chunk-alist))) (:remove-from-alistf entity-id (cdr chunk-alist)))
(gethash :entities map))) (gethash :entities map)))
@ -168,8 +161,10 @@ Used primarily in moving between different maps in an overworld state."
(defun overworld-state-update (map Δt) (defun overworld-state-update (map Δt)
"Do nothing, lol. Core part of OVERWORLD-STATE. "Do nothing, lol. Core part of OVERWORLD-STATE.
Returns parameters to be used in the next invocation of OVERWORLD-STATE." Returns parameters to be used in the next invocation of OVERWORLD-STATE."
(process-overworld-time map Δt) (let ((time-result (process-overworld-time map Δt)))
(process-overworld-input map)) (if time-result
time-result
(process-overworld-input map))))
(defun seconds->game-datetime (seconds &key (game-day-length 240)) (defun seconds->game-datetime (seconds &key (game-day-length 240))
@ -186,15 +181,42 @@ Returns a plist of properties :DAY, :HOUR, and :MINUTE, all numbers."
:minute (floor (* 60 minutes-fraction)))))) :minute (floor (* 60 minutes-fraction))))))
(defun end-game-string (map)
(str:concat
(if (getf-act map :encourage-scientist)
(:getf-lang '(:en "The cities of Etteburg and Bigborough live in peace. Doctor Klara Tim reached new heights in her professional career."
:eo "La urboj de Etburgo kaj Egburo apudvivas pace. Doktoro Klara Tim atingis altojn en sia kariero, plimemfide."))
(:getf-lang '(:en "The city of Etteburg was nearly completely destroyed by the neighboring city Bigborough's police force, which claimed the city as its own.")))
" "
(if (getf-act map :perfect-friendship)
(:getf-lang '(:en "Friendship with Sasha blossoms, and the two are closer than ever before. She no longer broods by the cliffside, but has reintegrated into society. What an impactful flower, huh?"))
(if (getf-act map :encourage-friendship)
(:getf-lang '(:en "Friendship with Sasha is better than ever before, yet still somewhat distant. Often, Sasha returns to the cliffside."))
(:getf-lang '(:en "To this day, Sasha broods by the cliffside alone."))))))
(defun end-game (map)
(setf flora-search-aurora:*knows* (gethash :knows map))
(🎭:make-intermission-state
'(:eo "LUDO FINITA" :en "GAME OVER")
'(:en "Where are they now?")
(list :en (end-game-string map))
(list :drop 1)))
(defun process-overworld-time (map Δt) (defun process-overworld-time (map Δt)
"Do nothing, lol. Core part of OVERWORLD-STATE. "Do nothing, lol. Core part of OVERWORLD-STATE.
Returns parameters to be used in the next invocation of OVERWORLD-STATE." Returns parameters to be used in the next invocation of OVERWORLD-STATE."
(let* ((time (:incf-0 (gethash :seconds map) Δt)) (let* ((time (:incf-0 (gethash :seconds map) Δt))
(game-datetime (seconds->game-datetime time))) (game-datetime (seconds->game-datetime time)))
(if (eq (gethash :day map) 3)
(end-game map)
(progn
;; Go through the day-update procedures! ;; Go through the day-update procedures!
(when (not (eq (getf game-datetime :day) (when (not (eq (getf game-datetime :day)
(gethash :day map))) (gethash :day map)))
(setf (gethash :day map) (getf game-datetime :day))))) (setf (gethash :day map) (getf game-datetime :day)))
nil))))
(defun process-overworld-input (map) (defun process-overworld-input (map)

View File

@ -22,6 +22,7 @@
#:plist= #:plist=
#:incf-0 #:incf-0
#:at-least #:at-most #:at-least #:at-most
#:remove-from-alistf
#:string->symbol #:string->symbol
#:system-language #:langcode->keysym #:getf-lang #:system-language #:langcode->keysym #:getf-lang
:*language*)) :*language*))
@ -111,8 +112,9 @@
(defpackage :flora-search-aurora (defpackage :flora-search-aurora
(:nicknames :fsa :) (:nicknames :fsa :)
(:export #:main (:export #:main
:player) :player :*knows*)
(:use :cl (:use :cl
:flora-search-aurora.input :flora-search-aurora.display :flora-search-aurora.input :flora-search-aurora.display
:flora-search-aurora.overworld :flora-search-aurora.dialogue :flora-search-aurora.overworld :flora-search-aurora.dialogue
:flora-search-aurora.menu)) :flora-search-aurora.menu))

View File

@ -430,7 +430,7 @@ Fojfoje mi ja ŝatas mian fakon, mdr.</property>
</properties> </properties>
<point/> <point/>
</object> </object>
<object id="10" name="Ring" type="Entity" x="346.347" y="606.126"> <object id="10" name="Ring" type="Entity" x="26.347" y="657.459">
<properties> <properties>
<property name="adjective-en" value="pretty"/> <property name="adjective-en" value="pretty"/>
<property name="adjective-eo" value="bele"/> <property name="adjective-eo" value="bele"/>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="left-down" width="72" height="41" tilewidth="17" tileheight="17" infinite="0" nextlayerid="5" nextobjectid="29"> <map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="left-down" width="72" height="41" tilewidth="17" tileheight="17" infinite="0" nextlayerid="7" nextobjectid="35">
<tileset firstgid="1" source="font.tsx"/> <tileset firstgid="1" source="font.tsx"/>
<layer id="1" name="Foreground" width="72" height="41"> <layer id="1" name="Foreground" width="72" height="41">
<properties> <properties>
@ -128,7 +128,35 @@
<property name="Δy" type="int" value="-1"/> <property name="Δy" type="int" value="-1"/>
</properties> </properties>
</object> </object>
<object id="26" name="Cat" x="1114" y="367.5"> </objectgroup>
<objectgroup id="2" name="People">
<object id="11" name="Player" type="Person" x="606.727" y="675.464">
<properties>
<property name="facing-right" type="bool" value="false"/>
<property name="id" value="✿:player"/>
</properties>
<point/>
</object>
</objectgroup>
<objectgroup id="5" name="Items">
<object id="30" name="Leontopodium nivale" type="Item" x="606" y="28">
<properties>
<property name="adjective-en" value="invigorating"/>
<property name="adjective-eo" value="kuraĝige"/>
<property name="avatar" value="&lt;*&gt;"/>
<property name="desc-en" value="Leontopodium nivale: Courage, daring."/>
<property name="desc-eo" value="Leontopodium nivale: Kuraĝo, bravemo.r"/>
<property name="id" value="✿:neĝfloro"/>
<property name="interact" value="✿:TAKE-ITEM-INTERACT"/>
<property name="name-en" value="Edelweiss"/>
<property name="name-eo" value="Neĝfloro"/>
<property name="use" value="✿:to-person-use"/>
</properties>
<point/>
</object>
</objectgroup>
<objectgroup id="6" name="Descriptions">
<object id="31" name="Cat" x="1117" y="370.5">
<properties> <properties>
<property name="avatar" value="f"/> <property name="avatar" value="f"/>
<property name="desc-en">(It's a kitty! How cute!) <property name="desc-en">(It's a kitty! How cute!)
@ -142,7 +170,7 @@
</properties> </properties>
<point/> <point/>
</object> </object>
<object id="27" name="Dog" x="162.5" y="301.5"> <object id="32" name="Dog" x="165.5" y="304.5">
<properties> <properties>
<property name="avatar" value="d"/> <property name="avatar" value="d"/>
<property name="desc-en">(Bark bark! It's a dog!) <property name="desc-en">(Bark bark! It's a dog!)
@ -156,9 +184,7 @@
</properties> </properties>
<point/> <point/>
</object> </object>
</objectgroup> <object id="33" name="Exit window" type="Trigger" x="609" y="679.5">
<objectgroup id="2" name="People">
<object id="10" name="Exit window" type="Trigger" x="606.329" y="676.813">
<properties> <properties>
<property name="desc-en">(Jesus, this place is a nightmare.) <property name="desc-en">(Jesus, this place is a nightmare.)
(No wonder they went out of business!) (No wonder they went out of business!)
@ -174,15 +200,5 @@ r</property>
</properties> </properties>
<point/> <point/>
</object> </object>
<object id="11" name="Player" type="Person" x="603.102" y="675.464">
<properties>
<property name="facing-right" type="bool" value="false"/>
<property name="id" value="✿:player"/>
</properties>
<point/>
</object>
<object id="28" x="603" y="25">
<point/>
</object>
</objectgroup> </objectgroup>
</map> </map>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="left-down" width="288" height="100" tilewidth="12" tileheight="17" infinite="0" nextlayerid="20" nextobjectid="130"> <map version="1.10" tiledversion="1.10.1" orientation="orthogonal" renderorder="left-down" width="288" height="100" tilewidth="12" tileheight="17" infinite="0" nextlayerid="21" nextobjectid="133">
<tileset firstgid="1" source="font.tsx"/> <tileset firstgid="1" source="font.tsx"/>
<layer id="1" name="Background" width="288" height="100"> <layer id="1" name="Background" width="288" height="100">
<properties> <properties>
@ -1875,8 +1875,40 @@ DANĜERA LOKO - VENENA MATERIO
<point/> <point/>
</object> </object>
</objectgroup> </objectgroup>
<objectgroup id="20" name="Items">
<object id="131" name="Leontopodium nivale" type="Item" x="3270.67" y="104">
<properties>
<property name="adjective-en" value="invigorating"/>
<property name="adjective-eo" value="kuraĝige"/>
<property name="avatar" value="&lt;*&gt;"/>
<property name="desc-en" value="Leontopodium nivale: Courage, daring."/>
<property name="desc-eo" value="Leontopodium nivale: Kuraĝo, bravemo.r"/>
<property name="id" value="✿:neĝfloro"/>
<property name="interact" value="✿:TAKE-ITEM-INTERACT"/>
<property name="name-en" value="Edelweiss"/>
<property name="name-eo" value="Neĝfloro"/>
<property name="use" value="✿:to-person-use"/>
</properties>
<point/>
</object>
<object id="132" name="Lavendula" type="Item" x="1109" y="1660">
<properties>
<property name="adjective-en" value="offputting"/>
<property name="adjective-eo" value="malkomfortige"/>
<property name="avatar" value="&lt;@&gt;"/>
<property name="desc-en" value="Lavendula: Distrust, facade."/>
<property name="desc-eo" value="Lavendula: Malfido, ŝajnigo."/>
<property name="id" value="✿:lavendula"/>
<property name="interact" value="✿:TAKE-ITEM-INTERACT"/>
<property name="name-en" value="Lavender"/>
<property name="name-eo" value="Lavendo"/>
<property name="use" value="✿:to-person-use"/>
</properties>
<point/>
</object>
</objectgroup>
<objectgroup id="7" name="People"> <objectgroup id="7" name="People">
<object id="2" name="Player" type="Person" x="2806.33" y="491.34"> <object id="2" name="Player" type="Person" x="484.997" y="216.673">
<properties> <properties>
<property name="facing-right" type="bool" value="true"/> <property name="facing-right" type="bool" value="true"/>
<property name="id" value="✿:player"/> <property name="id" value="✿:player"/>

View File

@ -125,6 +125,13 @@ minimum returns your more pitiful of moments."
;;; ——————————————————————————————————— ;;; ———————————————————————————————————
;;; Linguistic & symbolic affirs ;;; Linguistic & symbolic affirs
;;; ——————————————————————————————————— ;;; ———————————————————————————————————
(defmacro remove-from-alistf (key alist &key (test 'eql))
"Remove the given item from an associative list destructively."
`(alexandria:removef
,alist ,key
:test (lambda (key item) (,test key (car item)))))
(defun string->symbol (string) (defun string->symbol (string)
"Given a STRING with an optionally defined package (e.g., package:symbol), "Given a STRING with an optionally defined package (e.g., package:symbol),
return it as an appopriate symbol." return it as an appopriate symbol."