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.
-