diff --git a/overworld.lisp b/overworld.lisp index 15eb278..58f2e8b 100644 --- a/overworld.lisp +++ b/overworld.lisp @@ -30,25 +30,63 @@ ;;; ——————————————————————————————————— ;;; Overworld loop ;;; ——————————————————————————————————— -(defun overworld-state (matrix &key (map-path nil) (map nil) (entity-data nil)) +(defun overworld-state (matrix &key (map-path nil) + (map (cl-tiled:load-map map-path)) + (entities-alist '((player . (:x 0 :y 0 :icon #\@))))) "Render the given map to the matrix and take user-input — for one frame. A state-function for use with #'state-loop." (sleep .02) - (let ((map (if (not map) (cl-tiled:load-map map-path) map))) - (overworld-state-draw matrix map entity-data) - (overworld-state-update map entity-data))) + (overworld-state-draw matrix map entities-alist) + (overworld-state-update map entities-alist)) -(defun overworld-state-draw (matrix map entity-data) +(defun overworld-state-draw (matrix map entities-alist) "Draw the overworld map to the given matrix. A core part of #'overworld-state." - (matrix-write-tiled-map matrix map)) + (matrix-write-tiled-map matrix map) + (matrix-write-entities matrix entities-alist)) -(defun overworld-state-update (map entity-data) +(defun overworld-state-update (map entities-alist) "Do nothing, lol. Core part of #'overworld-state. Returns parameters to be used in the next invocation of #'overworld-state." - (list :map map :entity-data entity-data)) + (process-overworld-input map entities-alist) + (list :map map :entities-alist entities-alist)) + + + +;;; ——————————————————————————————————— +;;; Overworld logic +;;; ——————————————————————————————————— +(defun process-overworld-input (map entities) + "Get and process any keyboard input, modifying the map or entities as necessary." + (if (listen) + (let* ((input (normalize-char-plist (read-char-plist)))) + (cond + ((plist= input '(:modifier nil :char #\→)) + (move-entity 'player entities :x 1)) + ((plist= input '(:modifier nil :char #\←)) + (move-entity 'player entities :x -1)) + ((plist= input '(:modifier nil :char #\↑)) + (move-entity 'player entities :y -1)) + ((plist= input '(:modifier nil :char #\↓)) + (move-entity 'player entities :y 1)))))) + + + +(defun move-entity (entity entities-alist &key (x 0) (y 0)) + "Move an entity relative to its current position." + (let ((entity-plist (cdr (assoc entity entities-alist)))) + (move-entity-to entity entities-alist + :x (+ x (getf entity-plist :x)) + :y (+ y (getf entity-plist :y))))) + + +(defun move-entity-to (entity entities-alist &key (x 0) (y 0)) + "Move the given entity to the given coordinates." + (let ((entity-plist (cdr (assoc entity entities-alist)))) + (setf (getf entity-plist :x) x) + (setf (getf entity-plist :y) y))) @@ -88,3 +126,44 @@ with 15 characters-per-line." (+ (* (cl-tiled:tile-row tile) 15) (cl-tiled:tile-column tile) 32))) + + + +;;; ——————————————————————————————————— +;;; Entity magic (AKA player, NPCs) +;;; ——————————————————————————————————— +(defun matrix-write-entities (matrix entities-alist) + "Draw all entities from an alist of entities to the matrix." + (mapcar (lambda (entity-assoc) + (print entity-assoc) + (force-output) + (matrix-write-entity matrix (cdr entity-assoc))) + entities-alist)) + + +(defun matrix-write-entity (matrix entity-plist) + "Render an entity-plist to the matrix." + (setf (aref matrix (getf entity-plist :y) (getf entity-plist :x)) + (getf entity-plist :icon))) + + + +;;; ——————————————————————————————————— +;;; 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))))