Split off STATE-LOOP into an engine package (⚙)

… while making generic state-function-creators for
both dialogues and overworld maps. This should
make game-specific code more pretty-like!
This commit is contained in:
Jaidyn Ann 2023-06-23 13:29:09 -05:00
parent e21d16069b
commit 4d4b65da9c
4 changed files with 108 additions and 72 deletions

View File

@ -20,7 +20,7 @@
(defpackage :flora-search-aurora.dialogue (defpackage :flora-search-aurora.dialogue
(:nicknames :fsa.dia :dialogue :💬) (:nicknames :fsa.dia :dialogue :💬)
(:use :cl) (:use :cl)
(:export #:dialogue-state (:export #:dialogue-state #:make-dialogue-state
#:start-dialogue #:face #:say #:mumble #:move #:start-dialogue #:face #:say #:mumble #:move
:normal-face :talking-face)) :normal-face :talking-face))
@ -330,5 +330,12 @@ A state-function for use with STATE-LOOP."
(dialogue-state-update map dialogue)) (dialogue-state-update map dialogue))
(defun make-dialogue-state (map dialogue-list)
"Return a state-function for a section of dialogue, for use with STATE-LOOP."
(lambda (matrix &key (map map) (dialogue dialogue-list))
(🌍:overworld-state-draw matrix map)
(dialogue-state matrix :map map :dialogue dialogue-list)))
;; Split a banana in two, bisection-fruit, ;; Split a banana in two, bisection-fruit,
;; Yummy-yummy, toot-toot~ 🎵 ;; Yummy-yummy, toot-toot~ 🎵

74
engine.lisp Normal file
View File

@ -0,0 +1,74 @@
;;;; Copyright © 2023, Jaidyn Ann <jadedctrl@posteo.at>
;;;;
;;;; 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 <https://www.gnu.org/licenses/>.
;;;; FLORA-SEARCH-AURORA.ENGINE
;;;; The core of the games engine, the loop. Not much to see here other
;;;; than a loop. Honest!
(defpackage :flora-search-aurora.engine
(:nicknames :fsa.eng :engine :)
(:export #:state-loop #:main)
(:use :cl))
(in-package :flora-search-aurora.engine)
(defun state-loop
(states &key (last-matrix (:make-screen-matrix)) (matrix (:make-screen-matrix)) (state-params nil))
"Begin the games 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.
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.
What the state-function returns is pretty important, having different repercussions:
* 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, yknow. Your computer will
overheat, or something ¯\_()_/¯"
(when states
(multiple-value-bind (state-result new-state-params)
(apply (car states) (cons matrix state-params)) ;; Run the latest-added update/draw loop
(:print-screen-matrix (:matrix-delta last-matrix matrix)) ;; Print its results.
(force-output)
(state-loop
(cond ((functionp state-result)
(cons state-result states))
((not state-result)
(cdr states))
('t states))
:last-matrix matrix
:state-params
(cond ((not state-result)
new-state-params)
((listp state-result)
state-result))))))
(defun main (states)
"A toplevel-worthy function that configures rendering and kicks off the
games loop. Lets get started!"
(cl-charms:with-curses ()
(cl-charms:enable-raw-input :interpret-control-characters 't)
(:hide-cursor)
(:clear-screen)
(state-loop states)))

View File

@ -27,6 +27,7 @@
(load "overworld.tiled.lisp") (load "overworld.tiled.lisp")
(load "overworld.lisp") (load "overworld.lisp")
(load "dialogue.lisp") (load "dialogue.lisp")
(load "engine.lisp")
(defpackage :flora-search-aurora (defpackage :flora-search-aurora
(:nicknames :fsa :) (:nicknames :fsa :)
@ -39,13 +40,7 @@
(in-package :flora-search-aurora) (in-package :flora-search-aurora)
(defun literary-girl-dialogue-2 (map) (defparameter *literary-girl-dialogue*
(print "OWO"))
(defun literary-girl-dialogue (map)
(let
((dialogue
(💬:start-dialogue (💬:start-dialogue
(💬:mumble "literary-girl" :en "...") (💬:mumble "literary-girl" :en "...")
(💬:say "player" :eo "Kielas apud la mar'?" (💬:say "player" :eo "Kielas apud la mar'?"
@ -53,58 +48,11 @@
(💬:face "player" "<.<") (💬:face "player" "<.<")
(💬:say "literary-girl" :eo "Kielas apud la ruinoj de via viv'?" (💬:say "literary-girl" :eo "Kielas apud la ruinoj de via viv'?"
:en "How's your trainwreck of a life?") :en "How's your trainwreck of a life?")
(💬:face "player" '💬:normal-face)))) (💬:face "player" '💬:normal-face)))
(lambda (matrix &key (map map) (dialogue dialogue))
(🌍:overworld-state-draw matrix map)
(💬:dialogue-state matrix :map map :dialogue dialogue))))
(defun state-loop (defun literary-girl-dialogue (map)
(states &key (last-matrix (make-screen-matrix)) (matrix (make-screen-matrix)) (state-params nil)) (make-dialogue-state map *literary-girl-dialogue*))
"Begin the games 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.
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.
What the state-function returns is pretty important, having different repercussions:
* 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, yknow. Your computer will
overheat, or something ¯\_()_/¯"
(when states
(multiple-value-bind (state-result new-state-params)
(apply (car states) (cons matrix state-params)) ;; Run the latest-added update/draw loop
(:print-screen-matrix (:matrix-delta last-matrix matrix)) ;; Print its results.
(force-output)
(state-loop
(cond ((functionp state-result)
(cons state-result states))
((not state-result)
(cdr states))
('t states))
:last-matrix matrix
:state-params
(cond ((not state-result)
new-state-params)
((listp state-result)
state-result))))))
(defun make-main-overworld-state ()
"Return a state-function for the games overworld (the majority of the game), for use
with STATE-LOOP."
(lambda (matrix &rest args)
(apply #'🌍:overworld-state
(append (list matrix)
'(:map-path #p"/home/jaidyn/.local/src/games/flora search aurora/res/map.tmx")
args))))
(defparameter *submenu* `(((LABEL :en "IDK") (selection . 100) (selected t)) (defparameter *submenu* `(((LABEL :en "IDK") (selection . 100) (selected t))
@ -113,7 +61,8 @@ with STATE-LOOP."
(defparameter *main-menu* `(((LABEL :en "PLAY" :eo "EKLUDI") (defparameter *main-menu* `(((LABEL :en "PLAY" :eo "EKLUDI")
(selection . 100) (selected . t) (selection . 100) (selected . t)
(return . ,(make-main-overworld-state))) (return . ,(🌍:make-overworld-state
(format nil "~Ares/map.tmx" (uiop:getcwd)))))
((LABEL :en "SUBMENU" :eo "SUBMENUO") ((LABEL :en "SUBMENU" :eo "SUBMENUO")
(return . ,(📋:make-menu-state *submenu*))) (return . ,(📋:make-menu-state *submenu*)))
((LABEL :en "QUIT" :eo "REZIGNI") ((LABEL :en "QUIT" :eo "REZIGNI")
@ -121,12 +70,10 @@ with STATE-LOOP."
(defun main () (defun main ()
"A pathetic fascimile of a main loop. What does it do? WHAST DOES TI DODOO?" "A pathetic fascimile of a main loop. What does it do? WHAST DOES TI DODOO?
(cl-charms:with-curses () What a mysteryyy! Youll have to check out the engine to uncover it.
(cl-charms:enable-raw-input :interpret-control-characters 't) engine.lisp, that is. Cheers! :D"
(:hide-cursor) (:main (list (📋:make-menu-state *main-menu*))))
(:clear-screen)
(state-loop (list (📋:make-menu-state *main-menu*)))))
(main) ;; — Knock-knock (main) ;; — Knock-knock

View File

@ -21,7 +21,7 @@
(:nicknames :fsa.o :overworld :🌍) (:nicknames :fsa.o :overworld :🌍)
(:use :cl (:use :cl
:flora-search-aurora.overworld.tiled :flora-search-aurora.overworld.util) :flora-search-aurora.overworld.tiled :flora-search-aurora.overworld.util)
(:export #:overworld-state #:overworld-state-draw (:export #:overworld-state #:make-overworld-state #:overworld-state-draw
#:world-coords->screen-coords #:world-coords->screen-coords
#:getf-entity #:getf-entity-data #:getf-entity #:getf-entity-data
#:move-entity-to #:move-entity #:move-entity-to #:move-entity
@ -250,3 +250,11 @@ A state-function for use with STATE-LOOP."
(sleep .02) (sleep .02)
(overworld-state-draw matrix map) (overworld-state-draw matrix map)
(overworld-state-update map)) (overworld-state-update map))
(defun make-overworld-state (map-path)
"Return a state-function for a a map, for use with STATE-LOOP."
(lambda (matrix &rest args)
(apply #'🌍:overworld-state
(append (list matrix :map-path map-path)
args))))