diff --git a/database/run.lisp b/database/run.lisp index 739dc96..adee23a 100644 --- a/database/run.lisp +++ b/database/run.lisp @@ -24,12 +24,16 @@ (if start (floor (* 100 (local-time:timestamp-difference end start)))))) -(defun format-elapsed-time (run-split) +(defun run-split-format-elapsed-time (run-split) (let ((elapsed (run-split-elapsed-time run-split))) (if elapsed (format-time (make-time-alist elapsed)) "-"))) +;;(defun best-split (category-split) +;; (mito:select-dao 'run-split +;; (sxql:order-by (:- V + ;; Returns stuff like PB, best of each split, etc. (defun run-statistics (category) `((asdf . 1))) diff --git a/lispruns.asd b/lispruns.asd index 4f6b6d8..98faa3f 100644 --- a/lispruns.asd +++ b/lispruns.asd @@ -1,25 +1,24 @@ (asdf:defsystem "lispruns" - :description "A speedrun timer using n-curses written in lisp" - :version "0.1" - :author "Simponic" - :depends-on (:unix-opts - :mito - :sxql - :cl-ppcre - :croatoan - :local-time) - :components ((:file "util") ;; Miscellaneous helpers - (:file "config") ;; For importing category configuration files - (:file "digits") ;; Lisp file with cool ascii digits - (:file "text" :depends-on ("digits")) ;; Helper functions for performing figlet-like actions and such - (:file "time") ;; Custom time forms - (:file "ui" :depends-on ("util" "text" "time")) ;; Functions to draw the UI - (:file "speedrun" :depends-on ("util")) ;; The actual timer logic - (:file "database/category") ;; Category DAO - (:file "database/run") ;; Run DAO - (:file "main" :depends-on ("database/category" - "database/run" - "util" - "config" - "ui" - "speedrun")))) + :description "A speedrun timer using n-curses written in lisp" + :version "0.1" + :author "Simponic" + :depends-on (:mito + :sxql + :cl-ppcre + :croatoan + :local-time) + :components ((:file "util") ;; Miscellaneous helpers + (:file "config") ;; For importing category configuration files + (:file "digits") ;; Lisp file with cool ascii digits + (:file "text" :depends-on ("digits")) ;; Helper functions for performing figlet-like actions and such + (:file "time") ;; Custom time forms + (:file "ui" :depends-on ("util" "text" "time")) ;; Functions to draw the UI + (:file "speedrun" :depends-on ("util")) ;; The actual timer logic + (:file "database/category") ;; Category DAO + (:file "database/run") ;; Run DAO + (:file "main" :depends-on ("database/category" + "database/run" + "util" + "config" + "ui" + "speedrun")))) diff --git a/main.lisp b/main.lisp index cfe5d38..40823cd 100644 --- a/main.lisp +++ b/main.lisp @@ -20,7 +20,7 @@ (if (ignore-errors (funcall validator input)) input (progn - (format t "E: Invalid input. Try again.") + (format t "E: Invalid input. Try again.~%") (get-input prompt validator))))) ;; Options is an alist with the prompt string as the car and the value as the cdr @@ -53,6 +53,29 @@ (progn (format t "E: Could not find option that matched query.~%") (select-option options))))))) +(defun user-create-new-category () + (let* ((name (get-input "Category Name (e.g. \"SM64\"): " 'empty-p)) + (percentage (get-input "Percentage (e.g. \"16 Star\"): " 'empty-p)) + (category (mito:insert-dao (make-instance 'category :name name :percentage percentage))) + (splits (do ((spliti 1 (1+ spliti)) + (inputs '() (push (get-input (format nil "Split Name [~a]~a: " spliti (if (<= spliti 1) " (blank when done adding)" ""))) inputs))) + ((equal (car inputs) "") + (mapcar (lambda + (category-split-name) + (mito:insert-dao + (make-instance 'category-split + :name category-split-name + :category category))) + (reverse (cdr inputs))))))))) + +(defun with-selected-category (f) + (let* ((categories (mito:select-dao 'category)) + (category-alist (mapcar (lambda (category) `(,(format nil "~a - ~a" (category-name category) (category-percentage category)) . ,category)) categories))) + (if categories + (funcall f (select-option category-alist)) + (format t "E: There are no categories. Try creating one or importing one")))) + + (defun main () (let ((choice (select-option '(("Help" . HELP) ("Import a category" . IMPORT-CATEGORY) @@ -62,6 +85,7 @@ ("Exit" . EXIT))))) (case choice ('HELP + (format t "~%") (mapcar #'(lambda (x) (format t "~a~%" x)) *lispruns-logo*)) ('IMPORT-CATEGORY (import-category (get-input @@ -69,25 +93,9 @@ (uiop/os:getcwd)) 'probe-file))) ('NEW-CATEGORY - (let* ((name (get-input "Category Name (e.g. \"SM64\"): " 'not-empty-string)) - (percentage (get-input "Percentage (e.g. \"16 Star\"): " 'not-empty-string)) - (category (mito:insert-dao (make-instance 'category :name name :percentage percentage))) - (splits (do ((spliti 1 (1+ spliti)) - (inputs '() (push (get-input (format nil "Split [~a]: " spliti)) inputs))) - ((equal (car inputs) "") - (mapcar (lambda - (category-split-name) - (mito:insert-dao - (make-instance 'category-split - :name category-split-name - :category category))) - (reverse (cdr inputs))))))))) + (user-create-new-category)) ('START-SPEEDRUN - (let* ((categories (mito:select-dao 'category)) - (category-alist (mapcar (lambda (category) `(,(format nil "~a - ~a" (category-name category) (category-percentage category)) . ,category)) categories))) - (if categories - (speedrun-ui (select-option category-alist)) - (format t "E: There are no categories. Try creating one or importing one")))) + (with-selected-category 'speedrun-ui)) ('EXIT (quit)))) (format t "~%") diff --git a/ui.lisp b/ui.lisp index e574767..39db207 100644 --- a/ui.lisp +++ b/ui.lisp @@ -18,6 +18,12 @@ (inc yi)) slices))) +;; Formats a category split and a run split for the splits window +(defun make-split-line (csplit speedrun-split) + `((,(category-split-name csplit) . ,(/ 4 12)) + ("" . ,(/ 1 12)) + (,(run-split-format-elapsed-time speedrun-split) . ,(/ 3 12)))) + ;; Creates a window with the total time and statistics (defun timer-window (speedrun pos width height) (let* ((timerglet (lispglet (format-time (make-time-alist (speedrun-elapsed speedrun))))) @@ -82,6 +88,7 @@ (subseq elements (car elements-to-draw-subseq) (cadr elements-to-draw-subseq)))) highlight-menu)) +;; The big bad monolithic UI loop (defun speedrun-ui (category) (croatoan:with-screen (scr :input-blocking nil :input-echoing nil :cursor-visible nil :enable-colors t :input-buffering nil :input-blocking nil) (setf (croatoan:background scr) (make-instance 'croatoan:complex-char :color-pair (cdr (assoc 'main *colors*)))) @@ -90,7 +97,9 @@ (state 'TITLE) (redraws '(title-instance)) (speedrun (make-speedrun category)) - (csplits (category-splits category))) + (csplits (category-splits category)) + ;; TODO + (pbs ())) (flet ((render () (case state ('TITLE @@ -124,16 +133,8 @@ :current-element-index (speedrun-current-split-index speedrun) :height splits-height :width max-width - :elements (mapcar (lambda (csplit speedrun-split) - `( - (,(category-split-name csplit) . ,(/ 4 12)) - ("" . ,(/ 1 12)) - (,(format-elapsed-time speedrun-split) . ,(/ 3 12)) - )) - csplits - (speedrun-splits speedrun)))) -;; :elements (mapcar #'category-split-name csplits))) -;; :elements `((("FIRST SPLIT IS EPIC" . ,(/ 4 12)) ("" . ,(/ 1 12)) ("10:10:00.22" . ,(/ 3 12)) ("" . ,(/ 1 12)) ("20:00.00" . ,(/ 3 12)))))) + ;; Todo: add personal bests to elements + :elements (mapcar 'make-split-line csplits (speedrun-splits speedrun)))) (splits-instance (highlight-list-window split-list `(0 ,centered-x))) (timer-instance (timer-window speedrun `(,splits-height ,centered-x) max-width timer-height))) (croatoan:refresh splits-instance) @@ -143,6 +144,7 @@ (if (zerop (mod frame 30)) (inc scroll)) (sleep (/ 1 60)))) + (croatoan:event-case (scr event) (#\q (return-from croatoan:event-case)) (#\space diff --git a/util.lisp b/util.lisp index 3369a03..fe2cb69 100644 --- a/util.lisp +++ b/util.lisp @@ -10,5 +10,5 @@ (defun max-length (lists) (reduce (lambda (a x) (max a x)) (mapcar #'length lists))) -(defun not-empty-string (str) - (not (zerop (length str)))) +(defun empty-p (s) + (not (zerop (length s))))