summaryrefslogtreecommitdiff
path: root/speedrun.lisp
blob: e3932824c75e319b1afdd1667dc7a8f08def43ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
(defclass speedrun ()
  ((state
    ;; RUNNING, STOPPED
    :initarg :state
    :accessor speedrun-state)
   (title
    :initarg :title
    :accessor speedrun-title)
   (start-timestamp
    :initarg :start-timestamp
    :accessor speedrun-start-timestamp)
   (elapsed ;; milliseconds
    :initarg :elapsed
    :accessor speedrun-elapsed)
   (splits
    :initarg :splits
    :accessor speedrun-splits)
   (run-dao
    :initarg :run-dao
    :accessor speedrun-run-dao)
   (current-split-index
    :initarg :current-split-index
    :accessor speedrun-current-split-index)))

(defun make-speedrun (category)
  (let* ((run (make-instance 'run :category category))
         (splits (mapcar (lambda (category-split)
                           (make-instance 'run-split :category-split category-split :run run))
                         (category-splits category))))
    (make-instance 'speedrun
                   :state 'STOPPED
                   :title (category-name category)
                   :splits splits
                   :current-split-index 0
                   :elapsed 0.0
                   :run-dao run)))

(defun current-split (speedrun)
  (nth (speedrun-current-split-index speedrun) (speedrun-splits speedrun)))

;; Updates the current total elapsed time of the speedrun if it's running
(defun update-time (speedrun)
  (if (eq (speedrun-state speedrun) 'RUNNING)
      (setf (speedrun-elapsed speedrun) (millis-since-internal-timestamp (speedrun-start-timestamp speedrun)))))

;; Initializes a speedrun to start running the timer
(defun start-speedrun (speedrun)
  (let ((now (get-internal-real-time)))
    (setf (speedrun-state speedrun) 'RUNNING
          (speedrun-start-timestamp speedrun) now 
          (run-split-start-timestamp (current-split speedrun)) now)))

;; Saves the speedrun into the database
(defun save-speedrun (speedrun)
  (mapcar #'mito:save-dao (cons (speedrun-run-dao speedrun) (speedrun-splits speedrun))))

;; Set the state of the speedrun to be stopped if there are no more splits.
;; Or, set the current split to the next one in the list.
(defun next-split (speedrun)
  (let ((now (get-internal-real-time)))
    (unless (equal (speedrun-state speedrun) 'STOPPED)
      (setf (run-split-end-timestamp (current-split speedrun)) now)
      (if (equal (speedrun-current-split-index speedrun) (1- (length (speedrun-splits speedrun))))
          (progn
            (setf
             ;; Since timer computation can get +-0.02 seconds out of sync of splits, just set it to the sum of the splits' elapsed time
             (speedrun-elapsed speedrun) (millis-since-internal-timestamp 0 (apply '+ (mapcar 'run-split-elapsed-time (speedrun-splits speedrun)))) 
             (speedrun-state speedrun) 'STOPPED)
            (save-speedrun speedrun))
          (progn
            (inc (speedrun-current-split-index speedrun))
            (setf (run-split-start-timestamp (current-split speedrun)) now))))))