From 95442b39db7ac63a1125fa7a1e881fa3d0fbcce6 Mon Sep 17 00:00:00 2001 From: Jaidyn Ann <10477760+JadedCtrl@users.noreply.github.com> Date: Mon, 19 Jun 2023 08:47:45 -0500 Subject: [PATCH] =?UTF-8?q?Change=20entity=20faces=20while=20they=E2=80=99?= =?UTF-8?q?re=20talking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What a cool effect ^w^ ^o^ ^w^ --- dialogue.lisp | 129 +++++++++++++++++++++++++++++++++++++++ flora-search-aurora.lisp | 29 +++++---- overworld.lisp | 33 ---------- overworld.tiled.lisp | 4 +- 4 files changed, 148 insertions(+), 47 deletions(-) create mode 100644 dialogue.lisp diff --git a/dialogue.lisp b/dialogue.lisp new file mode 100644 index 0000000..8d75e27 --- /dev/null +++ b/dialogue.lisp @@ -0,0 +1,129 @@ +;;;; 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 +;;;; published by the Free Software Foundation, either version 3 of +;;;; the License, or (at your option) any later version. +;;;; +;;;; This program is distributed in the hope that it will be useful, +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;;; GNU General Public License for more details. +;;;; +;;;; You should have received a copy of the GNU General Public License +;;;; along with this program. If not, see . + +;;;; FLORA-SEARCH-AURORA.OVERWORLD +;;;; All game-functions and data relating to the “overworld” (that is, +;;;; the primary gameplay, the RPG-ish-ish bits). + +(defpackage :flora-search-aurora.dialogue + (:nicknames :fsa.d :dialogue) + (:use :cl + :flora-search-aurora.overworld :flora-search-aurora.ui :flora-search-aurora.input) + (:export #:dialogue-state #:say)) + +(in-package :flora-search-aurora.dialogue) + + + +;;; ——————————————————————————————————— +;;; Dialogue-generation DSL (sorta) +;;; ——————————————————————————————————— +(defun dialogue (&rest dialogue-tree) + (reduce (lambda (a b) (append a b)) + dialogue-tree)) + + +(defun say (speaker text) + (list + (list :speaker speaker :text text :face 'talking-face) + (car (face speaker 'normal-face)))) + + +(defun mumble (speaker text) + (list + (list :speaker speaker :text text))) + + +(defun face (speaker face) + (list + (list :speaker speaker :face face))) + + + +;;; ——————————————————————————————————— +;;; Dialogue logic +;;; ——————————————————————————————————— +(defun pressed-enter-p () + (and (listen) + (eq (getf (normalize-char-plist (read-char-plist)) :char) + #\return))) + + +(defun appropriate-face (map speaker face) + (let ((talking-face (getf-entity-data map speaker :talking-face)) + (normal-face (getf-entity-data map speaker :normal-face))) + (cond ((and (eq face 'talking-face) + talking-face) + talking-face) + ((and (eq face 'normal-face) + normal-face) + normal-face) + ((stringp face) + face)))) + + +(defun dialogue-state-update (dialogue-list map) + "The logic/input-processing helper function for DIALOGUE-STATE." + (let* ((speaker (intern (string-upcase (getf (car dialogue-list) :speaker)))) + (new-face (appropriate-face map speaker + (getf (car dialogue-list) :face)))) + ;; Replace the face, when appropriate. + (when new-face + (setf (getf-entity-data map speaker :face) new-face))) + ;; Progress the dialogue as appropriate. + (let ((text (getf (car dialogue-list) :text))) + (cond ((or (pressed-enter-p) + (not text)) + (if (cdr dialogue-list) + (list :dialogue (cdr dialogue-list) :map map) + (values nil + (list :map map)))) + ((cdr dialogue-list) + (list :dialogue dialogue-list :map map)) + ('t + (values nil + (list :map map)))))) + + + +;;; ——————————————————————————————————— +;;; Dialogue drawing +;;; ——————————————————————————————————— +(defun dialogue-state-draw (matrix dialogue-list) + "Draw the dialogue where appropriate. +Helper function for DIALOGUE-STATE." + (let ((text (getf (car dialogue-list) :text))) + (when text + (render-line matrix text 0 0)))) + + + +;;; ——————————————————————————————————— +;;; Dialogue loop +;;; ——————————————————————————————————— +(defun dialogue-state (matrix &key dialogue map) + "Render a bit of dialogue to the screen, using :FLORA-SEARCH-AURORA.OVERWORLD +entities as the speakers. Dialogue should be in the format: + ((:text \"Hello, papa!\" + :speaker \"son\" ;; The entity’s ID (if applicable) + :face \"owo\") ;; If you want their face to change + (:face \"=w=\" :speaker 'son) ;; change their face back when done talking + (:text \"Hello, you little gremlin! <3\" + :speaker \"papa\" + ...)) +A state-function for use with STATE-LOOP." + (sleep .02) + (dialogue-state-draw matrix dialogue) + (dialogue-state-update dialogue map)) diff --git a/flora-search-aurora.lisp b/flora-search-aurora.lisp index 4294881..8cf410c 100644 --- a/flora-search-aurora.lisp +++ b/flora-search-aurora.lisp @@ -25,12 +25,14 @@ (load "overworld.util.lisp") (load "overworld.tiled.lisp") (load "overworld.lisp") +(load "dialogue.lisp") (defpackage :flora-search-aurora (:export #:main) (:use :cl :flora-search-aurora.input :flora-search-aurora.display - :flora-search-aurora.overworld :flora-search-aurora.ui)) + :flora-search-aurora.overworld :flora-search-aurora.dialogue + :flora-search-aurora.ui)) (in-package :flora-search-aurora) @@ -39,9 +41,9 @@ (defun literary-girl-dialogue (map) (lambda (matrix &key (map map) - (dialogue - `((:speaker "literary-girl" :face "xDx" :text "daddy") - (:speaker "player" :face "<3" :text "i love u")))) + (dialogue (dialogue::dialogue + (dialogue::say "literary-girl" "Oh, hello.") + (dialogue::say "player" "What, no quip?")))) (overworld-state-draw matrix map) (dialogue-state matrix :map map :dialogue dialogue))) @@ -50,18 +52,19 @@ (states &key (last-matrix (make-screen-matrix)) (matrix (make-screen-matrix)) (state-params nil)) "Begin the game’s loop, which executes (henceforthly called) state-functions over and over again until Hell freezes over and a new king reigns supreme. -Given a list of state-functions, states, it will execute the first function. +Given a list of state-functions, STATES, it will execute the first function. Each state-function must take at least a single parameter, a matrix of characters. A state-function should edit this matrix in-place, replacing its elements with characters that will later be printed to the terminal. -If this function returns NIL, then it will be removed from state-function list and the next -function in the list will be run in the next iteration. If no more functions remain, the loop -terminates. -If this function returns a list, then the given list will be used as additional parameters to the -state-function in the next iteration, in addition to the aforementioned matrix. -If this function returns a function, then the returned function will go to the front of the -state-function list, and will be ran in the next iteration onward. -If this function returns anything else, then it’ll simply be run again in the next iteration. +What the state-function returns is pretty important: + * NIL — The function is removed from STATES, and so the next function in STATES will start + getting executed instead. + * NIL; List — The function is popped off STATES and the list is used as the new parameters for + the next function in STATES. + * Function — The function is pushed to the front of STATES, and so is executed instead of the + current function. + * List — The current function (front of STATES) continues to be executed with the given + list as a parameters list. Make note to add a delay w SLEEP to your state functions, or… well, y’know. Your computer will overheat, or something ¯\_(ツ)_/¯" (when states diff --git a/overworld.lisp b/overworld.lisp index 8d873ef..4a070ec 100644 --- a/overworld.lisp +++ b/overworld.lisp @@ -253,36 +253,3 @@ A state-function for use with STATE-LOOP." (sleep .02) (overworld-state-draw matrix map) (overworld-state-update map)) - - - -;;; ——————————————————————————————————— -;;; Dialogue state -;;; ——————————————————————————————————— -(defun dialogue-state-update (dialogue-list map) - (if dialogue-list - (let ((speaker (intern (string-upcase (getf (car dialogue-list) :speaker)))) - (face (getf (car dialogue-list) :face))) - (setf (getf-entity-data map speaker :face) face))) - - (cond ((and dialogue-list - (listen) - (eq (getf (normalize-char-plist (read-char-plist)) - :char) - #\return)) - (list :dialogue (cdr dialogue-list) :map map)) - (dialogue-list - (list :dialogue dialogue-list :map map)) - ('t - (values nil - (list :map map))))) - - -(defun dialogue-state-draw (matrix dialogue-list) - (render-line matrix (getf (car dialogue-list) :text) 0 0)) - - -(defun dialogue-state (matrix &key dialogue map) - (sleep .02) - (dialogue-state-draw matrix dialogue) - (dialogue-state-update dialogue map)) diff --git a/overworld.tiled.lisp b/overworld.tiled.lisp index 6bafbca..7c56239 100644 --- a/overworld.tiled.lisp +++ b/overworld.tiled.lisp @@ -82,7 +82,9 @@ alist of Tiled cell “chunks”." (cl-tiled:map-tile-width tiled-map))) :y (floor (/ (cl-tiled:object-y tiled-obj) (cl-tiled:map-tile-height tiled-map)))) - :face (gethash "face" properties #'string-equal) + :face (gethash "normal_face" properties #'string-equal) + :normal-face (gethash "normal_face" properties #'string-equal) + :talking-face (gethash "talking_face" properties #'string-equal) :interact (gethash "interact" properties #'string-equal) :direction (if (gethash "facing_right" properties #'string-equal) 'right