diff --git a/flora-search-aurora.lisp b/flora-search-aurora.lisp index 8dc87ea..9e013e9 100644 --- a/flora-search-aurora.lisp +++ b/flora-search-aurora.lisp @@ -1,4 +1,4 @@ - ;;;; Copyright © 2023, Jaidyn Ann +;;;; Copyright © 2023, Jaidyn Ann ;;;; ;;;; This program is free software: you can redistribute it and/or ;;;; modify it under the terms of the GNU General Public License as @@ -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 player’s pockets. +That is, into MAP’s :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") diff --git a/overworld.lisp b/overworld.lisp index c5cc190..c4440bc 100644 --- a/overworld.lisp +++ b/overworld.lisp @@ -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) diff --git a/overworld.tiled.lisp b/overworld.tiled.lisp index f7ba717..aa4d4e8 100644 --- a/overworld.tiled.lisp +++ b/overworld.tiled.lisp @@ -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)) diff --git a/res/casino.tmx b/res/casino.tmx index f534459..f0fd16d 100644 --- a/res/casino.tmx +++ b/res/casino.tmx @@ -208,8 +208,15 @@ + + + + - + + + +