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

@ -1,4 +1,4 @@
;;;; Copyright © 2023, Jaidyn Ann <jadedctrl@posteo.at> ;;;; Copyright © 2023, Jaidyn Ann <jadedctrl@posteo.at>
;;;; ;;;;
;;;; This program is free software: you can redistribute it and/or ;;;; This program is free software: you can redistribute it and/or
;;;; modify it under the terms of the GNU General Public License as ;;;; modify it under the terms of the GNU General Public License as
@ -40,6 +40,10 @@
(in-package :flora-search-aurora) (in-package :flora-search-aurora)
(defmacro aget-item (map item)
`(assoc-utils:aget (gethash :items ,map) ,item))
(defmacro getf-act (map act) (defmacro getf-act (map act)
`(getf (gethash :acts ,map) ,act)) `(getf (gethash :acts ,map) ,act))
@ -48,6 +52,56 @@
`(getf (gethash :knows ,map) ,idea)) `(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™ ;;; The Outside World™
@ -129,7 +183,7 @@
(childhood-friend-partings))))) (childhood-friend-partings)))))
(defun childhood-friend-interact (map) (defun childhood-friend-interact (map &optional interactee-id)
(make-dialogue-state map (childhood-friend-dialogue map))) (make-dialogue-state map (childhood-friend-dialogue map)))
@ -152,7 +206,7 @@
;;; ——————————————————————————————————— ;;; ———————————————————————————————————
;;; Random casino NPCs ;;; Random casino NPCs
;;; ——————————————————————————————————— ;;; ———————————————————————————————————
(defun boozy-lady-dialogue (&optional map) (defun boozy-lady-dialogue ()
(let ((messages (let ((messages
'((:eo "SaaaAAAl' belul', ĉu vjifik...vekfj/?" '((:eo "SaaaAAAl' belul', ĉu vjifik...vekfj/?"
:en "HeeeEey sweet-cheeks, u wan sum..?") :en "HeeeEey sweet-cheeks, u wan sum..?")
@ -173,11 +227,11 @@
(nth (random (length messages)) messages)))))) (nth (random (length messages)) messages))))))
(defun boozy-lady-interact (map) (defun boozy-lady-interact (map &optional interactee-id)
(make-dialogue-state map (boozy-lady-dialogue map))) (make-dialogue-state map (boozy-lady-dialogue)))
(defun boozy-friend-interact (map) (defun boozy-friend-interact (map &optional interactee-id)
(make-dialogue-state (make-dialogue-state
map map
(start-dialogue (start-dialogue
@ -187,7 +241,7 @@
:en "It's so embarrasing...")))) :en "It's so embarrasing..."))))
(defun casino-attendant-interact (map) (defun casino-attendant-interact (map &optional interactee-id)
(make-dialogue-state (make-dialogue-state
map map
(start-dialogue (start-dialogue
@ -197,7 +251,7 @@
:en "Have fun; may lady luck blow you a kiss!")))) :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 (make-dialogue-state
map map
(start-dialogue (start-dialogue
@ -292,7 +346,7 @@
:en "Five feet under, maybe...")))))) :en "Five feet under, maybe..."))))))
(defun bad-gambler-partings (&optional map) (defun bad-gambler-partings (map)
(let ((messages (let ((messages
'((:eo "... kaj ŝiaj mamoj tiom belis..." '((:eo "... kaj ŝiaj mamoj tiom belis..."
:en "... her titties were so nice, too...") :en "... her titties were so nice, too...")
@ -320,7 +374,7 @@
(bad-gambler-partings))))) (bad-gambler-partings)))))
(defun bad-gambler-interact (map) (defun bad-gambler-interact (map &optional interactee-id)
(make-dialogue-state map (bad-gambler-dialogue map))) (make-dialogue-state map (bad-gambler-dialogue map)))
@ -334,8 +388,7 @@
(defparameter *main-menu* `(((LABEL :en "PLAY" :eo "EKLUDI") (defparameter *main-menu* `(((LABEL :en "PLAY" :eo "EKLUDI")
(selection . 100) (selected . t) (selection . 100) (selected . t)
(return . ,(🌍:make-overworld-state (return . ,(🌍:make-overworld-state *casino-map*)))
(format nil "~Ares/casino.tmx" (uiop:getcwd)))))
((LABEL :en "SUBMENU" :eo "SUBMENUO") ((LABEL :en "SUBMENU" :eo "SUBMENUO")
(return . ,(📋:make-menu-state *submenu*))) (return . ,(📋:make-menu-state *submenu*)))
((LABEL :en "QUIT" :eo "REZIGNI") ((LABEL :en "QUIT" :eo "REZIGNI")

View File

@ -24,7 +24,7 @@
(:export #:overworld-state #:make-overworld-state #:overworld-state-draw (:export #:overworld-state #:make-overworld-state #:overworld-state-draw
#:merge-maps #:merge-maps
#:world-coords->screen-coords #:world-coords->screen-coords
#:getf-entity #:getf-entity-data #:getf-entity #:getf-entity-data #:removef-entity
#:move-entity-to #:move-entity #:move-entity-to #:move-entity
:left :right :left :right
:player)) :player))
@ -44,6 +44,13 @@ 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,6 +68,15 @@ rectangle as defined by its TOP-LEFT-CORNER & BOTTOM-RIGHT-CORNER."
,key)) ,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)) (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." "Return a list of entity-plists that are near the given coordinates within the given RADIUS."
(remove-if-not (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)) ((:plist= input '(:modifier nil :char #\return))
(let* ((player (getf-entity map 'player)) (let* ((player (getf-entity map 'player))
(interactee (car (entities-near-entity player (gethash :entities map)))) (interactee (car (entities-near-entity player (gethash :entities map))))
(interactee-id (car interactee))
(interaction (getf (cdr interactee) :interact))) (interaction (getf (cdr interactee) :interact)))
(if interaction (if interaction
(apply (intern (string-upcase interaction)) (list map)) (apply (intern (string-upcase interaction)) (list map interactee-id))
(list :map map)))) (list :map map))))
;; The pause-menu… ;; The pause-menu…
;; ((plist = input '(:modifier nil :char #\Esc))) ;; ((plist = input '(:modifier nil :char #\Esc)))
@ -288,7 +305,7 @@ alist containing a character (:CHAR) and :X & :Y coordinates."
;;; Overworld loop ;;; Overworld loop
;;; ——————————————————————————————————— ;;; ———————————————————————————————————
(defun overworld-state (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. "Render the given map to the matrix and take user-input for one frame.
A state-function for use with STATE-LOOP." A state-function for use with STATE-LOOP."
(sleep .02) (sleep .02)
@ -296,12 +313,12 @@ A state-function for use with STATE-LOOP."
(overworld-state-update map)) (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." "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 (apply #'🌍:overworld-state
(append (list matrix :map-path map-path) (list matrix :map map))))
args))))
(defun merge-maps (map-a map-b) (defun merge-maps (map-a map-b)

View File

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

View File

@ -208,8 +208,15 @@
</object> </object>
<object id="10" name="Ring" type="Entity" x="603.68" y="620.126"> <object id="10" name="Ring" type="Entity" x="603.68" y="620.126">
<properties> <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="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> </properties>
<point/> <point/>
</object> </object>