diff --git a/dialogue.lisp b/dialogue.lisp index fb9671e..4214bc8 100644 --- a/dialogue.lisp +++ b/dialogue.lisp @@ -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: I’m 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 speaker’s face to either their -talking-face or the face given by the dialogue." + "Given a line (plist) of DIALOGUE, change speaker’s 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 DIALOGUE’s :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,23 +158,35 @@ 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)) - (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)) - (setf (getf (car dialogue-list) :progress) (length text)) - (list :dialogue dialogue-list :map map)) - ((cdr dialogue-list) - (list :dialogue dialogue-list :map map))))) + (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 enter’s 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))))) + ;; 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)) + ;; 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))))) diff --git a/flora-search-aurora.lisp b/flora-search-aurora.lisp index 1b0958a..f2dc644 100644 --- a/flora-search-aurora.lisp +++ b/flora-search-aurora.lisp @@ -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))) diff --git a/overworld.lisp b/overworld.lisp index 10f1867..3895d2a 100644 --- a/overworld.lisp +++ b/overworld.lisp @@ -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 diff --git a/util.lisp b/util.lisp index bd70a1d..616b1b6 100644 --- a/util.lisp +++ b/util.lisp @@ -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."