Celeste, Speed-running and Org Tables
Although I've played Celeste for long time, I'm not the best player. I've finished all the A-Sides minus Farewell, grabbed all the berries and cleared 4 B-sides. Celeste is a game that teaches us to embrace our mistakes as a learning opportunity. That practice makes us better. Not talent, but practice. As such it is a game dear to my heart. It is the second game I introduced to my daughter. While playing with my daughter recently, I've decided that I'm going to take chance at speed-running.
The first game I speed-run was hollow knight, aiming for a under 4 hours time. And although I did improved significantly. Even managed to implement a reliably do a couple of skips my attempts met a wall in the Watcher Knights. Although I managed to reach them in ~1H reliably I never managed to get close to beating them. Even with the help of Fireb0rn.
I'm under no delusions of grandeur, I can't commit the amount of time necessary to be a competitive speed-runner. But I don't need to. I only need to compete with my past self. My goal is a <1 hour Any%.
The baseline
This are currently my personal best times. As you can see I have a lot of room for improvement. Particularly on The Summit and Reflection. I think just not dying would help me bring the times down significantly. My plan is to start practising individual rooms in the summit.
| Level | Personal Best | 1H Target Times |
|------------------+---------------+-----------------|
| Forsaken City | 2:00.717 | 1:47 |
| Old Site | 5:00.492 | 2:42 |
| Celestial Resort | 16:03.373 | 8:00 |
| Golden Ridge | 17:15.479 | 4:55 |
| Mirror Temple | 19:15.507 | 7:51 |
| Reflection | 29:00.477 | 8:20 |
| The Summit | 40:52.063 | 16:00 |
|------------------+---------------+-----------------|
| Total | 2:09:28.108 | 49:35.000 |
#+TBLFM: @9$2='(celeste-ms->timestamp (apply '+ (mapcar 'celeste-timestamp->ms '(@2..@8))))::@9$3='(celeste-ms->timestamp (apply '+ (mapcar 'celeste-timestamp->ms '(@2..@8))))
Appendix
The code to support the org-mode table formulas, you can place them in your user-lisp-directory.
;;;###autoload
(defun celeste-timestamp->ms (timestamp)
"Return the number of milliseconds in a celeste timestamp.
A celeste Timestamp has a format of [H:]MM:SS.XXX"
(let* ((ts timestamp)
(pivot (cl-position ?. ts :from-end t))
minutes seconds milliseconds)
(if pivot
(setq milliseconds (cl-parse-integer (seq-subseq ts (1+ pivot))))
(setq milliseconds 0))
(setq ts (seq-subseq ts 0 pivot))
(setq pivot (cl-position ?: ts :from-end t))
(setq seconds (cl-parse-integer (seq-subseq ts (1+ pivot))))
(setq ts (seq-subseq ts 0 pivot))
;; TODO: Handle hours
(setq minutes (cl-parse-integer ts))
(+ (* minutes 60 1000) (* seconds 1000) milliseconds)))
;;;###autoload
(defun celeste-ms->timestamp (milliseconds)
"Return the timestamp in Celeste's format."
(let* ((ms milliseconds)
(hours (/ ms (* 60 60 1000)))
minutes seconds)
(if (zerop hours)
(setq hours nil)
(setq ms (- ms (* hours (* 60 60 1000)))))
(setq minutes (/ ms (* 60 1000)))
(setq ms (- ms (* minutes 60 1000)))
(setq seconds (/ ms 1000))
(setq ms (- ms (* seconds 1000)))
(if hours
(format "%d:%02d:%02d.%03d" hours minutes seconds ms)
(format "%d:%02d.%03d" minutes seconds ms))))
(cl-assert (equal (celeste-timestamp->ms "1:47") (+ (* 60 1000)
(* 47 1000))))
(cl-assert (equal (celeste-timestamp->ms "40:52.063") 2452063))
(cl-assert (equal (celeste-ms->timestamp 2452063) "40:52.063"))
(cl-assert (equal (celeste-ms->timestamp 7768108) "2:09:28.108"))