diff --git a/dialogue.lisp b/dialogue.lisp index 16b4810..58d5678 100644 --- a/dialogue.lisp +++ b/dialogue.lisp @@ -199,6 +199,7 @@ Returns the state for use with STATE-LOOP, pay attention!" (list :parameters (list :dialogue (cdr dialogue-list) :map map)) (progn (✎:hide-cursor) + (clear-input) (list :drop (1+ (or (getf dialogue :drop) 0)) :function (getf dialogue :function) :parameters (if (member :parameters dialogue) diff --git a/display.lisp b/display.lisp index 747de8c..116497f 100644 --- a/display.lisp +++ b/display.lisp @@ -13,7 +13,7 @@ ;;;; You should have received a copy of the GNU General Public License ;;;; along with this program. If not, see . -;;;; FLORA-SEARCH-AURORA.DISPLAY +;;;; FLORA-SEARCH-AURORA.DISPLAY ✎ ;;;; All display-related curses go here. (in-package :flora-search-aurora.display) diff --git a/engine.lisp b/engine.lisp index 31e11bd..965725c 100644 --- a/engine.lisp +++ b/engine.lisp @@ -13,7 +13,7 @@ ;;;; You should have received a copy of the GNU General Public License ;;;; along with this program. If not, see . -;;;; FLORA-SEARCH-AURORA.ENGINE +;;;; FLORA-SEARCH-AURORA.ENGINE ⚙ ;;;; The core of the game’s engine, the loop. Not much to see here other ;;;; than a loop. Honest! @@ -39,7 +39,7 @@ overheat, or something ¯\_(ツ)_/¯" (let ((state-result (apply (car states) (cons matrix state-params)))) ;; Run the last-added state-loop. (✎: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) (state-loop (cond ((listp state-result) diff --git a/flora-search-aurora.lisp b/flora-search-aurora.lisp index 9286404..c5c9579 100644 --- a/flora-search-aurora.lisp +++ b/flora-search-aurora.lisp @@ -446,9 +446,38 @@ run the :USE function of the nearest entity, if it has any." :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 "symbol (getf item-plist :id)))) (cond ((eq item-id 'bracelet) + (if (getf-act map :encourage-friendship) + (setf (getf-act map :perfect-friendship) 't)) (make-dialogue-state map (childhood-friend-dialogue-bracelet map entity-id))) ((eq item-id 'neĝfloro) (remove-item map 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 (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) (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 - (make-dialogue-state - map (flashback-childhood-friend-dialogue-bracelet map entity-id)) - ((eq item-id 'neĝfloro) - (make-dialogue-state map (childhood-friend-dialogue-edelweiss entity-id))) - ('t - ;; Otherwise, have her politely refuse. =w= - (refusal-use map item-plist entity-id))))) + (make-dialogue-state + map (flashback-childhood-friend-dialogue-bracelet map entity-id))) + ('t (childhood-friend-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-school-map* (🌍:plist->map (metacopy:copy-thing *flashback-school-map-plist*))) (defparameter *outdoors-map* (🌍:plist->map (metacopy:copy-thing *outdoors-map-plist*))) - (take-item *base-map* 'neĝfloro) -;; (make-flashback-state (alexandria:random-elt (flashbacks))))) - (make-overworld-state *base-map*))) + (take-item *base-map* 'lavendula) + (make-flashback-state (alexandria:random-elt (flashbacks))))) (defun main-menu () diff --git a/intermission.lisp b/intermission.lisp index df98a6d..57340ef 100644 --- a/intermission.lisp +++ b/intermission.lisp @@ -94,3 +94,11 @@ Part of INVENTORY-STATE." (lambda (matrix &key (title title) (subtitle subtitle) (side-text side-text) (return return) (progress 0)) (funcall #'intermission-state 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))) + diff --git a/inventory.lisp b/inventory.lisp index 17c9486..d588932 100644 --- a/inventory.lisp +++ b/inventory.lisp @@ -13,7 +13,7 @@ ;;;; You should have received a copy of the GNU General Public License ;;;; along with this program. If not, see . -;;;; FLORA-SEARCH-AURORA.INVENTORY +;;;; FLORA-SEARCH-AURORA.INVENTORY 🎒 ;;;; The menu for inventory selection/management. (in-package :flora-search-aurora.inventory) @@ -95,7 +95,7 @@ Part of INVENTORY-STATE." (list :parameters (list :map map :inventory inventory-menu))) ;; Return the menu itself, if non-nil. (menu-return - menu-return) + 't) ;; If menu-return was non-nil, the user left the menu. Let’s leave inventory! ('t (list :drop 1 :parameters (list :map map)))))) @@ -108,15 +108,15 @@ Part of INVENTORY-STATE." (defun render-selected-item (matrix items) "Draw the title, avatar, and description of the currently-selected item to 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)) :eo (or (getf item :name-eo) (getf item :inv-name-eo)))) (desc (list :en (getf item :desc-en) :eo (getf item :desc-eo)))) - (display:render-string-verbatim matrix (str:concat ":" (…:getf-lang name) ": " - (getf item :avatar)) + (✎:render-string-verbatim matrix (str:concat ":" (…:getf-lang name) ": " + (getf item :avatar)) '(:x 1 :y 17)) - (display:render-string matrix (…:getf-lang desc) + (✎:render-string matrix (…:getf-lang desc) '(:x 1 :y 18) :width 70))) @@ -140,7 +140,7 @@ Part of INVENTORY-STATE." (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." (lambda (matrix &key (map map) (submenu nil) (inventory (items->menu-plist (gethash :items map)))) (apply #'🎒:inventory-state diff --git a/overworld.lisp b/overworld.lisp index 986ae36..b4b06e7 100644 --- a/overworld.lisp +++ b/overworld.lisp @@ -32,13 +32,6 @@ 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,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 stomache and PULL HARD, show NO REMORSE. RAAAAAA 🗡🩸" (mapcar (lambda (chunk-alist) - (overworld::remove-from-alistf entity-id (cdr chunk-alist))) + (…:remove-from-alistf entity-id (cdr chunk-alist))) (gethash :entities map))) @@ -168,8 +161,10 @@ Used primarily in moving between different maps in an overworld state." (defun overworld-state-update (map Δt) "Do nothing, lol. Core part of OVERWORLD-STATE. Returns parameters to be used in the next invocation of OVERWORLD-STATE." - (process-overworld-time map Δt) - (process-overworld-input map)) + (let ((time-result (process-overworld-time map Δt))) + (if time-result + time-result + (process-overworld-input map)))) (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)))))) +(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) "Do nothing, lol. Core part of OVERWORLD-STATE. Returns parameters to be used in the next invocation of OVERWORLD-STATE." (let* ((time (…:incf-0 (gethash :seconds map) Δt)) (game-datetime (seconds->game-datetime time))) - ;; Go through the day-update procedures! - (when (not (eq (getf game-datetime :day) - (gethash :day map))) - (setf (gethash :day map) (getf game-datetime :day))))) + (if (eq (gethash :day map) 3) + (end-game map) + (progn + ;; Go through the day-update procedures! + (when (not (eq (getf game-datetime :day) + (gethash :day map))) + (setf (gethash :day map) (getf game-datetime :day))) + nil)))) (defun process-overworld-input (map) diff --git a/packages.lisp b/packages.lisp index 3362e36..f35ea8f 100644 --- a/packages.lisp +++ b/packages.lisp @@ -22,6 +22,7 @@ #:plist= #:incf-0 #:at-least #:at-most + #:remove-from-alistf #:string->symbol #:system-language #:langcode->keysym #:getf-lang :*language*)) @@ -111,8 +112,9 @@ (defpackage :flora-search-aurora (:nicknames :fsa :✿) (:export #:main - :player) + :player :*knows*) (:use :cl :flora-search-aurora.input :flora-search-aurora.display :flora-search-aurora.overworld :flora-search-aurora.dialogue :flora-search-aurora.menu)) + diff --git a/res/maps/casino.tmx b/res/maps/casino.tmx index 0b2781f..f5e5eb6 100644 --- a/res/maps/casino.tmx +++ b/res/maps/casino.tmx @@ -430,7 +430,7 @@ Fojfoje mi ja ŝatas mian fakon, mdr. - + diff --git a/res/maps/factory.tmx b/res/maps/factory.tmx index 8af95a0..c821227 100644 --- a/res/maps/factory.tmx +++ b/res/maps/factory.tmx @@ -1,5 +1,5 @@ - + @@ -128,7 +128,35 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (It's a kitty! How cute!) @@ -142,7 +170,7 @@ - + (Bark bark! It's a dog!) @@ -156,9 +184,7 @@ - - - + (Jesus, this place is a nightmare.) (No wonder they went out of business!) @@ -174,15 +200,5 @@ r - - - - - - - - - - diff --git a/res/maps/outdoors.tmx b/res/maps/outdoors.tmx index 94ee265..e928e69 100644 --- a/res/maps/outdoors.tmx +++ b/res/maps/outdoors.tmx @@ -1,5 +1,5 @@ - + @@ -1875,8 +1875,40 @@ DANĜERA LOKO - VENENA MATERIO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/util.lisp b/util.lisp index b3005c4..9794fa7 100644 --- a/util.lisp +++ b/util.lisp @@ -125,6 +125,13 @@ minimum returns your more pitiful of moments." ;;; ——————————————————————————————————— ;;; 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) "Given a STRING with an optionally defined package (e.g., “package:symbol”), return it as an appopriate symbol."