Support for taking items

That is, directly moving an entity from the map
into the player’s pocket. Real simple
implementation, it’s just another
interact-function for use with your entities.
This commit is contained in:
Jaidyn Ann 2023-06-26 11:12:06 -05:00
parent 738239f50a
commit 2a78737d28
4 changed files with 98 additions and 21 deletions

View File

@ -40,6 +40,10 @@
(in-package :flora-search-aurora)
(defmacro aget-item (map item)
`(assoc-utils:aget (gethash :items ,map) ,item))
(defmacro getf-act (map act)
`(getf (gethash :acts ,map) ,act))
@ -48,6 +52,56 @@
`(getf (gethash :knows ,map) ,idea))
;;; ———————————————————————————————————
;;; Trans-map entity interactions
;;; ———————————————————————————————————
(defun take-item (map entity-id)
"Take an entity from the MAP :ENTITIES and place it in the players pockets.
That is, into MAPs :ITEMS."
(let ((item-plist (cdr (getf-entity map entity-id))))
(when item-plist
(setf (aget-item map entity-id) item-plist)
(removef-entity map entity-id))))
(defun take-item-dialogue (item-plist)
"Return some dialogue expressing surprise/dread or whatever at the collection
of a new item. The attributes set for the entity item should be:
ID
NAME-[EO|EN]
DESC-[EO|EN]
ADJECTIVE-[EO|EN]
REACTION-FACE
REACTION-TALKING
All are optional, save ID."
(start-dialogue
(face 'player (or (getf item-plist :reaction-face) "^_^")
(or (getf item-plist :reaction-talking) "^o^"))
(mumble 'player :en (format nil "(Hey, it's a ~A! ~A!)"
(or (getf item-plist :name-en) (getf item-plist :id))
(or (getf item-plist :adjective-en) "Nice"))
:eo (format nil "(Ho, jen ~A! ~A!)"
(or (getf item-plist :name-eo) (getf item-plist :id))
(or (getf item-plist :adjective-eo) "Interese")))
(mumble 'player :en (if (getf item-plist :desc-en)
(format nil "~~~~ ~A ~~~~" (getf item-plist :desc-en))
"(I'm glad I found it.)")
:eo (if (getf item-plist :desc-eo)
(format nil "~~~~ ~A ~~~~" (getf item-plist :desc-eo))
"(Kia bonŝanco!)"))))
(defun take-item-interact (map interactee-id)
"Try to pick up the interactee entity, then have the player react to the
pickup. See TAKE-ITEM-DIALOGUE for customizing the reaction dialogue.
Should be the `interact` function for takeable items."
(let ((item-plist (cdr (getf-entity map interactee-id))))
(when (take-item map interactee-id)
(make-dialogue-state map (take-item-dialogue item-plist)))))
;;; ———————————————————————————————————
;;; The Outside World™
@ -129,7 +183,7 @@
(childhood-friend-partings)))))
(defun childhood-friend-interact (map)
(defun childhood-friend-interact (map &optional interactee-id)
(make-dialogue-state map (childhood-friend-dialogue map)))
@ -152,7 +206,7 @@
;;; ———————————————————————————————————
;;; Random casino NPCs
;;; ———————————————————————————————————
(defun boozy-lady-dialogue (&optional map)
(defun boozy-lady-dialogue ()
(let ((messages
'((:eo "SaaaAAAl' belul', ĉu vjifik...vekfj/?"
:en "HeeeEey sweet-cheeks, u wan sum..?")
@ -173,11 +227,11 @@
(nth (random (length messages)) messages))))))
(defun boozy-lady-interact (map)
(make-dialogue-state map (boozy-lady-dialogue map)))
(defun boozy-lady-interact (map &optional interactee-id)
(make-dialogue-state map (boozy-lady-dialogue)))
(defun boozy-friend-interact (map)
(defun boozy-friend-interact (map &optional interactee-id)
(make-dialogue-state
map
(start-dialogue
@ -187,7 +241,7 @@
:en "It's so embarrasing..."))))
(defun casino-attendant-interact (map)
(defun casino-attendant-interact (map &optional interactee-id)
(make-dialogue-state
map
(start-dialogue
@ -197,7 +251,7 @@
:en "Have fun; may lady luck blow you a kiss!"))))
(defun casino-bartender-interact (map)
(defun casino-bartender-interact (map &optional interactee-id)
(make-dialogue-state
map
(start-dialogue
@ -292,7 +346,7 @@
:en "Five feet under, maybe..."))))))
(defun bad-gambler-partings (&optional map)
(defun bad-gambler-partings (map)
(let ((messages
'((:eo "... kaj ŝiaj mamoj tiom belis..."
:en "... her titties were so nice, too...")
@ -320,7 +374,7 @@
(bad-gambler-partings)))))
(defun bad-gambler-interact (map)
(defun bad-gambler-interact (map &optional interactee-id)
(make-dialogue-state map (bad-gambler-dialogue map)))
@ -334,8 +388,7 @@
(defparameter *main-menu* `(((LABEL :en "PLAY" :eo "EKLUDI")
(selection . 100) (selected . t)
(return . ,(🌍:make-overworld-state
(format nil "~Ares/casino.tmx" (uiop:getcwd)))))
(return . ,(🌍:make-overworld-state *casino-map*)))
((LABEL :en "SUBMENU" :eo "SUBMENUO")
(return . ,(📋:make-menu-state *submenu*)))
((LABEL :en "QUIT" :eo "REZIGNI")

View File

@ -24,7 +24,7 @@
(:export #:overworld-state #:make-overworld-state #:overworld-state-draw
#:merge-maps
#:world-coords->screen-coords
#:getf-entity #:getf-entity-data
#:getf-entity #:getf-entity-data #:removef-entity
#:move-entity-to #:move-entity
:left :right
:player))
@ -44,6 +44,13 @@ rectangle as defined by its TOP-LEFT-CORNER & BOTTOM-RIGHT-CORNER."
(>= (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
@ -61,6 +68,15 @@ rectangle as defined by its TOP-LEFT-CORNER & BOTTOM-RIGHT-CORNER."
,key))
(defun removef-entity (map entity-id)
"Remove an entity of the given ID from the map entirely. Nuke em!
Literally kill them, show no mercy, dig your sharp nails into their fleshy
stomache and PULL HARD, show NO REMORSE. RAAAAAA 🗡🩸"
(mapcar (lambda (chunk-alist)
(overworld::remove-from-alistf entity-id (cdr chunk-alist)))
(gethash :entities map)))
(defun entities-near-coords (coords radius entities &key (x-radius radius) (y-radius radius))
"Return a list of entity-plists that are near the given coordinates within the given RADIUS."
(remove-if-not
@ -128,9 +144,10 @@ Returns parameters to be used in the next invocation of OVERWORLD-STATE."
((:plist= input '(:modifier nil :char #\return))
(let* ((player (getf-entity map 'player))
(interactee (car (entities-near-entity player (gethash :entities map))))
(interactee-id (car interactee))
(interaction (getf (cdr interactee) :interact)))
(if interaction
(apply (intern (string-upcase interaction)) (list map))
(apply (intern (string-upcase interaction)) (list map interactee-id))
(list :map map))))
;; The pause-menu…
;; ((plist = input '(:modifier nil :char #\Esc)))
@ -288,7 +305,7 @@ alist containing a character (:CHAR) and :X & :Y coordinates."
;;; Overworld loop
;;; ———————————————————————————————————
(defun overworld-state
(matrix &key (map-path nil) (map (load-map map-path)))
(matrix &key map)
"Render the given map to the matrix and take user-input for one frame.
A state-function for use with STATE-LOOP."
(sleep .02)
@ -296,12 +313,12 @@ A state-function for use with STATE-LOOP."
(overworld-state-update map))
(defun make-overworld-state (map-path)
(defun make-overworld-state (map)
"Return a state-function for a a map, for use with STATE-LOOP."
(lambda (matrix &rest args)
(lambda (matrix &key (map map))
(apply #'🌍:overworld-state
(append (list matrix :map-path map-path)
args))))
(list matrix :map map))))
(defun merge-maps (map-a map-b)

View File

@ -18,7 +18,7 @@
;;;; used by the overworld.
(defpackage :flora-search-aurora.overworld.tiled
(:nicknames :fsa.o.t :overworld.tiled)
(:nicknames :fsa.o.t :overworld.tiled :🌍.🀨)
(:use :cl :anaphora-basic
:flora-search-aurora.overworld.util)
(:export #:load-map))

View File

@ -208,8 +208,15 @@
</object>
<object id="10" name="Ring" type="Entity" x="603.68" y="620.126">
<properties>
<property name="adjective-en" value="pretty"/>
<property name="adjective-eo" value="bele"/>
<property name="avatar" value="~o~"/>
<property name="desc-en" value="It shines in the moonlight, as all else is gone."/>
<property name="id" value="ring"/>
<property name="interact" value="ring-interact"/>
<property name="interact" value="take-item-interact"/>
<property name="name-en" value="ring"/>
<property name="name-eo" value="ringo"/>
<property name="reaction-face" value="&gt;_&lt;"/>
</properties>
<point/>
</object>