Add `move` directive to dialogues — for moving! :D

This commit is contained in:
Jaidyn Ann 2023-06-22 19:08:14 -05:00
parent c7c0ed6d65
commit b617e92aba
4 changed files with 95 additions and 52 deletions

View File

@ -21,7 +21,7 @@
(:nicknames :fsa.dia :dialogue :💬)
(:use :cl)
(:export #:dialogue-state
#:start-dialogue #:face #:say #:mumble))
#:start-dialogue #:face #:say #:mumble #:move))
(in-package :flora-search-aurora.dialogue)
@ -67,6 +67,11 @@ If not, have some tea on me: Im paying. =w="
(list :speaker speaker :text text :progress 0)))
(defun move (speaker world-coords)
(list
(list :speaker speaker :coords world-coords)))
;;; ———————————————————————————————————
;;; Accessors
@ -100,8 +105,8 @@ If FACE is NIL… guess what that does. :^)"
(defun update-speaking-face (map dialogue)
"Given a line (plist) of dialogue, change speakers face to either their
talking-face or the face given by the dialogue."
"Given a line (plist) of DIALOGUE, change speakers face to either their
talking-face or the face given by the DIALOGUE."
(let* ((speaker (intern (string-upcase (getf dialogue :speaker))))
(new-face (appropriate-face map speaker (getf dialogue :face))))
;; Replace the face, when appropriate.
@ -110,7 +115,7 @@ talking-face or the face given by the dialogue."
(defun progress-line-delivery (dialogue)
"Progress the delivery of a line (plist) of dialogue. That is, increment the
"Progress the delivery of a line (plist) of DIALOGUE. That is, increment the
said character-count :PROGRESS, which dictates the portion of the message that
should be printed on the screen at any given moment."
(let ((progress (getf dialogue :progress))
@ -120,6 +125,32 @@ should be printed on the screen at any given moment."
(incf (getf dialogue :progress) 1))))
(defun progress-movement (map dialogue)
"Move the entity by one tile in the targeted position that is, the
coordinates listed in the DIALOGUEs :COORDS property. If applicable, ofc."
(let* ((speaker (dialogue-speaker dialogue))
(target-coords (getf dialogue :coords))
(speaker-coords (🌍:getf-entity-data map speaker :coords))
(finished-moving-p (if target-coords (:plist= speaker-coords target-coords) 't)))
(when (not finished-moving-p)
(🌍:move-entity
map speaker
:x (cond ((< (getf target-coords :x) (getf speaker-coords :x)) -1)
((> (getf target-coords :x) (getf speaker-coords :x)) 1)
('t 0))
:y (cond ((< (getf target-coords :y) (getf speaker-coords :y)) -1)
((> (getf target-coords :y) (getf speaker-coords :y)) 1)
('t 0))))
finished-moving-p))
(defun finished-printing-p (dialogue)
"Whether or not a line of dialogue has been completely printed to the screen."
(or (not (getf dialogue :text))
(eq (length (getf dialogue :text))
(getf dialogue :progress))))
(defun dialogue-state-update (map dialogue-list)
"The logic/input-processing helper function for DIALOGUE-STATE.
Progress through the lines of dialogue when the user hits ENTER, etc.
@ -127,22 +158,34 @@ Returns the state for use with STATE-LOOP, pay attention!"
(update-speaking-face map (car dialogue-list))
(progress-line-delivery (car dialogue-list))
;; Progress to the next line of dialogue as appropriate.
(let* ((text (getf (car dialogue-list) :text))
(finished-printing-p (eq (length text)
(getf (car dialogue-list) :progress)))
(did-press-enter-p (pressed-enter-p)))
(cond ((or (not text)
(and did-press-enter-p finished-printing-p))
(let* ((dialogue (car dialogue-list))
(text (getf dialogue :text))
(did-press-enter-p (pressed-enter-p))
(did-finish-printing-p (finished-printing-p dialogue))
(did-finish-moving-p (progress-movement map dialogue)))
;; Only show the cursor when rendering text!
(if did-finish-moving-p
(:show-cursor)
(:hide-cursor))
(cond
;; When enters hit and most everything is done (rendering text, etc),
;; progress the dialogue.
((or (and did-press-enter-p did-finish-printing-p did-finish-moving-p)
(and (not text) did-finish-moving-p))
(if (cdr dialogue-list)
(list :dialogue (cdr dialogue-list) :map map)
(progn
(:hide-cursor)
(values nil
(list :map map)))))
((and did-press-enter-p (not finished-printing-p))
;; Allow interupting text-printing to end it!
((and did-press-enter-p (not did-finish-printing-p))
(setf (getf (car dialogue-list) :progress) (length text))
(list :dialogue dialogue-list :map map))
((cdr dialogue-list)
;; If no input, keep steady!
((or (not did-finish-printing-p)
(not did-finish-moving-p)
(cdr dialogue-list))
(list :dialogue dialogue-list :map map)))))

View File

@ -45,7 +45,8 @@
(lambda (matrix &key (map map)
(dialogue (💬:start-dialogue
(💬:say "literary-girl" "Blah blah, testing. A multi-lined one. For real! jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj akls djlaks jdlaksj dlakjsd")
(💬:say "player" "ktp ktp jes jes?"))))
(💬:say "player" "ktp ktp jes jes?")
(💬:move "player" '(:x 30 :y 10)))))
(🌍:overworld-state-draw matrix map)
(💬:dialogue-state matrix :map map :dialogue dialogue)))

View File

@ -24,33 +24,12 @@
(:export #:overworld-state #:overworld-state-draw
#:world-coords->screen-coords
#:getf-entity #:getf-entity-data
#:move-entity-to #:move-entity
:left :right
:player))
(in-package :flora-search-aurora.overworld)
;;; ———————————————————————————————————
;;; Misc. utility
;;; ———————————————————————————————————
(defun every-other-element (list)
"Collect every-other-element of a list. E.g., (1 2 3 4) → (1 3)."
(when list
(cons (car list)
(every-other-element (cddr list)))))
(defun plist= (a b &key (test #'eql))
"Return whether or not two property lists are equal, by comparing values of each pair.
Uses the keys of plist a."
(let ((keys (every-other-element a)))
(loop for key in keys
do (when (not (apply test (list (getf a key)
(getf b key))))
(return nil))
finally (return 't))))
;;; ———————————————————————————————————
;;; Accessors
@ -86,7 +65,7 @@ Uses the keys of plist a."
"Return a list of entities near the given entity — that is, within touching-distance."
(remove-if
(lambda (test-entity)
(plist= (cdr entity)
(:plist= (cdr entity)
(cdr test-entity)))
(entities-near-coords (getf (cdr entity) :coords)
(+ (length (getf (cdr entity) :face)) 2)
@ -98,7 +77,7 @@ Uses the keys of plist a."
(let ((chunk (world-coords-chunk coords)))
(member 't (cdr (assoc chunk map-chunks))
:test (lambda (ignored cell)
(plist= (getf cell :coords) coords)))))
(:plist= (getf cell :coords) coords)))))
(defun walkable-tile-p (map x y)
@ -123,24 +102,26 @@ Returns parameters to be used in the next invocation of OVERWORLD-STATE."
(let* ((input (:normalize-char-plist (:read-char-plist))))
(cond
;; Interacting with nearby characters/entities
((plist= input '(:modifier nil :char #\return))
((:plist= input '(:modifier nil :char #\return))
(let* ((player (getf-entity map 'player))
(interactee (car (entities-near-entity player (gethash :entities map))))
(interaction (getf (cdr interactee) :interact)))
(if interaction
(apply (intern (string-upcase interaction)) (list map))
(list :map map))))
;; The pause-menu…
;; ((plist = input '(:modifier nil :char #\Esc)))
;; Simple up-down-left-right movements
((plist= input '(:modifier nil :char #\→))
((:plist= input '(:modifier nil :char #\→))
(move-entity map 'player :x 1)
(list :map map))
((plist= input '(:modifier nil :char #\←))
((:plist= input '(:modifier nil :char #\←))
(move-entity map 'player :x -1)
(list :map map))
((plist= input '(:modifier nil :char #\↑))
((:plist= input '(:modifier nil :char #\↑))
(move-entity map 'player :y -1)
(list :map map))
((plist= input '(:modifier nil :char #\↓))
((:plist= input '(:modifier nil :char #\↓))
(move-entity map 'player :y 1)
(list :map map))
('t

View File

@ -20,7 +20,7 @@
(defpackage :flora-search-aurora.util
(:nicknames :fsa.ut :util :)
(:use :cl :assoc-utils)
(:export #:split-string-by-length #:at-least #:at-most))
(:export #:split-string-by-length #:plist= #:at-least #:at-most))
(in-package :flora-search-aurora.util)
@ -37,6 +37,24 @@ equal or lower to the given length."
(append substrings `(,string))))
(defun every-other-element (list)
"Collect every-other-element of a list. E.g., (1 2 3 4) → (1 3)."
(when list
(cons (car list)
(every-other-element (cddr list)))))
(defun plist= (a b &key (test #'eql))
"Return whether or not two property lists are equal, by comparing values of each pair.
Uses the keys of plist a."
(let ((keys (every-other-element a)))
(loop for key in keys
do (when (not (apply test (list (getf a key)
(getf b key))))
(return nil))
finally (return 't))))
(defun at-least (minimum num)
"This function returns at least every hope and dream you've ever had, and at
maximum returns your more pitiful of moments."