mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
62fa9d80e1
Fixes #3209
547 lines
31 KiB
Common Lisp
547 lines
31 KiB
Common Lisp
;;-*-Lisp-*-
|
|
(in-package goal)
|
|
|
|
;; TODO later - customize menu open keybind
|
|
|
|
(define-extern task-close! (function string symbol))
|
|
|
|
(define *speedrun-info* (new 'static 'speedrun-info))
|
|
(set! (-> *speedrun-info* active-custom-category) (new 'static 'speedrun-custom-category))
|
|
(set! (-> *speedrun-info* dump-custom-category) (new 'static 'speedrun-custom-category))
|
|
(set! (-> *speedrun-info* active-practice-objective) (new 'static 'speedrun-practice-objective))
|
|
(set! (-> *speedrun-info* active-practice-objective starting-position) (new 'static 'vector))
|
|
(set! (-> *speedrun-info* active-practice-objective starting-rotation) (new 'static 'vector))
|
|
(set! (-> *speedrun-info* active-practice-objective starting-camera-position) (new 'static 'vector))
|
|
(set! (-> *speedrun-info* active-practice-objective starting-camera-rotation) (new 'static 'matrix))
|
|
(set! (-> *speedrun-info* active-practice-objective start-zone-init-params) (new 'static 'objective-zone-init-params))
|
|
(set! (-> *speedrun-info* active-practice-objective end-zone-init-params) (new 'static 'objective-zone-init-params))
|
|
|
|
(defmethod draw-timer ((this speedrun-timer))
|
|
(clear *temp-string*)
|
|
(clear *pc-encoded-temp-string*)
|
|
(cond
|
|
((-> this started?)
|
|
(format *temp-string* "~,,2fs~%" (* (the float (- (current-time) (-> this start-time))) 0.0033333334)))
|
|
((and (!= 0 (-> this end-time)))
|
|
(format *temp-string* "~,,2fs~%" (* (the float (- (-> this end-time) (-> this start-time))) 0.0033333334)))
|
|
(else
|
|
(format *temp-string* "0.0s~%")))
|
|
(when *target*
|
|
(format *temp-string* "~,,2M~%" (-> *target* control ctrl-xz-vel)))
|
|
(pc-encode-utf8-string *temp-string* *pc-encoded-temp-string*)
|
|
(with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) (bucket-id debug-no-zbuf1))
|
|
;; reset bucket settings prior to drawing - font won't do this for us, and
|
|
;; draw-raw-image can sometimes mess them up. (intro sequence)
|
|
(dma-buffer-add-gs-set-flusha buf (alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1)) (tex1-1 (new 'static 'gs-tex1 :mmag #x1 :mmin #x1)))
|
|
(let ((font-ctx (new 'stack 'font-context *font-default-matrix* 256 350 0.0 (font-color default) (font-flags middle shadow kerning large))))
|
|
(set! (-> font-ctx scale) 0.325)
|
|
(draw-string-adv *pc-encoded-temp-string* buf font-ctx)))
|
|
(none))
|
|
|
|
(defmethod start! ((this speedrun-timer))
|
|
(set! (-> this started?) #t)
|
|
(set! (-> this stopped?) #f)
|
|
(set! (-> this start-time) (current-time))
|
|
(set! (-> this end-time) 0)
|
|
(none))
|
|
|
|
(defmethod reset! ((this speedrun-timer))
|
|
(set! (-> this started?) #f)
|
|
(set! (-> this stopped?) #f)
|
|
(set! (-> this start-time) 0)
|
|
(set! (-> this end-time) 0)
|
|
(none))
|
|
|
|
(defmethod stop! ((this speedrun-timer))
|
|
(when (not (-> this stopped?))
|
|
(set! (-> this started?) #f)
|
|
(set! (-> this stopped?) #t)
|
|
(set! (-> this end-time) (current-time))
|
|
(set! (-> this recorded-time) (* (the float (- (-> this end-time) (-> this start-time))) 0.0033333334)))
|
|
(-> this recorded-time))
|
|
|
|
(defmethod set-category! ((this speedrun-info) (category speedrun-category))
|
|
(set! (-> this category) category)
|
|
(none))
|
|
|
|
(defmethod start-run! ((this speedrun-info))
|
|
;; randomize game id so the autosplitter knows to restart
|
|
(reset! *autosplit-info-jak2*)
|
|
;; turn on speedrun verification display
|
|
(set! (-> this display-run-info?) #t)
|
|
(send-event (ppointer->process *speedrun-manager*) 'start-run)
|
|
;; ensure any required settings are enabled
|
|
(enforce-settings! this)
|
|
;; finalize any category specific setup code
|
|
(case (-> this category)
|
|
(((speedrun-category newgame-normal))
|
|
(initialize! *game-info* 'game (the-as game-save #f) "game-start"))
|
|
(((speedrun-category newgame-heromode))
|
|
(initialize! *game-info* 'game (the-as game-save #f) "game-start-hero"))
|
|
(((speedrun-category all-cheats-allowed))
|
|
(initialize! *game-info* 'game (the-as game-save #f) "game-start"))
|
|
(((speedrun-category custom))
|
|
(set-master-mode 'game)
|
|
(send-event (ppointer->process (-> *speedrun-manager* 0 popup-menu)) 'close-menu)
|
|
(process-spawn-function process (lambda :behavior process ()
|
|
(clear *temp-string*)
|
|
(pc-sr-mode-get-custom-category-continue-point (-> *speedrun-info* active-custom-category index) *temp-string*)
|
|
(if (string= *temp-string* "")
|
|
(initialize! *game-info* 'game (the-as game-save #f) "game-start")
|
|
(initialize! *game-info* 'game (the-as game-save #f) *temp-string*))
|
|
(until (and *target* (= (-> *target* next-state name) 'target-stance))
|
|
(suspend))
|
|
(when (nonzero? (-> *speedrun-info* active-custom-category completed-task))
|
|
(task-resolution-close! (-> *speedrun-info* active-custom-category completed-task)))))))
|
|
(if (!= -1 (-> *game-info* auto-save-which))
|
|
(set! (-> *setting-control* user-default auto-save) #t))
|
|
|
|
(none))
|
|
|
|
(defmethod enforce-settings! ((this speedrun-info))
|
|
(set! (-> *pc-settings* ps2-actor-vis?) #t) ;; force PS2 actor visibility
|
|
(set-frame-rate! *pc-settings* 60 #t) ;; force FPS to `60`
|
|
;; For posterity, the main reason why changing the cheats is useful is for two main reasons:
|
|
;; - If you are playing a category that requires cheats (ie. a turbo jetboard one) you'd
|
|
;; probably like the game to automatically set the appropriate ones for you
|
|
;; - If you are playing a category that forbids cheats, you wouldn't want your run invalidated because you forgot
|
|
(case (-> this category)
|
|
(((speedrun-category newgame-normal) (speedrun-category newgame-heromode))
|
|
;; disable any active cheats
|
|
(set! (-> *pc-settings* cheats) (the-as pc-cheats #x0)))
|
|
(((speedrun-category custom))
|
|
(set! (-> *game-info* secrets) (-> *speedrun-info* active-custom-category secrets))
|
|
(logior! (-> *game-info* features) (-> *speedrun-info* active-custom-category features))
|
|
(logclear! (-> *game-info* features) (-> *speedrun-info* active-custom-category forbidden-features))
|
|
(set! (-> *pc-settings* cheats) (-> *speedrun-info* active-custom-category pc-cheats))))
|
|
(none))
|
|
|
|
(defmethod draw-zone ((this objective-zone))
|
|
(add-debug-box
|
|
#t
|
|
(bucket-id debug2)
|
|
(-> this v1)
|
|
(-> this v2)
|
|
(if (-> this start?)
|
|
(new 'static 'rgba :r #xff :g #xff :b #x00 :a #x80)
|
|
(new 'static 'rgba :r #xff :g #x00 :b #xff :a #x80)))
|
|
(none))
|
|
|
|
(defstate waiting-for-player (objective-zone)
|
|
:virtual #t
|
|
:event (behavior ((proc process) (arg1 int) (event-type symbol) (event event-message-block))
|
|
(the-as object 0))
|
|
:trans (behavior ()
|
|
;; Check to see if we have entered the zone
|
|
(let ((min-point-x (fmin (-> self v1 x) (-> self v2 x)))
|
|
(min-point-y (fmin (-> self v1 y) (-> self v2 y)))
|
|
(min-point-z (fmin (-> self v1 z) (-> self v2 z)))
|
|
(max-point-x (fmax (-> self v1 x) (-> self v2 x)))
|
|
(max-point-y (fmax (-> self v1 y) (-> self v2 y)))
|
|
(max-point-z (fmax (-> self v1 z) (-> self v2 z)))
|
|
(pos (target-pos 0)))
|
|
(when (and (and (<= min-point-x (-> pos x))
|
|
(<= (-> pos x) max-point-x))
|
|
(and (<= min-point-y (-> pos y))
|
|
(<= (-> pos y) max-point-y))
|
|
(and (<= min-point-z (-> pos z))
|
|
(<= (-> pos z) max-point-z)))
|
|
(when (nonzero? (-> self on-enter))
|
|
((-> self on-enter)))
|
|
(go-virtual player-inside)))
|
|
(none))
|
|
:code (behavior ()
|
|
(until #f
|
|
(draw-zone self)
|
|
(suspend))
|
|
(none))
|
|
:post (behavior ()
|
|
(none)))
|
|
|
|
(defstate player-inside (objective-zone)
|
|
:virtual #t
|
|
:trans (behavior ()
|
|
;; Check to see if we have entered the zone
|
|
(let ((min-point-x (fmin (-> self v1 x) (-> self v2 x)))
|
|
(min-point-y (fmin (-> self v1 y) (-> self v2 y)))
|
|
(min-point-z (fmin (-> self v1 z) (-> self v2 z)))
|
|
(max-point-x (fmax (-> self v1 x) (-> self v2 x)))
|
|
(max-point-y (fmax (-> self v1 y) (-> self v2 y)))
|
|
(max-point-z (fmax (-> self v1 z) (-> self v2 z)))
|
|
(pos (target-pos 0)))
|
|
(when (not (and (and (<= min-point-x (-> pos x))
|
|
(<= (-> pos x) max-point-x))
|
|
(and (<= min-point-y (-> pos y))
|
|
(<= (-> pos y) max-point-y))
|
|
(and (<= min-point-z (-> pos z))
|
|
(<= (-> pos z) max-point-z))))
|
|
(when (nonzero? (-> self on-exit))
|
|
((-> self on-exit)))
|
|
(go-virtual waiting-for-player)))
|
|
(none))
|
|
:code (behavior ()
|
|
(until #f
|
|
(draw-zone self)
|
|
(suspend))
|
|
(none)))
|
|
|
|
(defbehavior objective-zone-init objective-zone ((start? symbol) (params objective-zone-init-params))
|
|
(set! (-> self start?) start?)
|
|
(set! (-> self v1 quad) (-> params v1 quad))
|
|
(set! (-> self v2 quad) (-> params v2 quad))
|
|
(go-virtual waiting-for-player)
|
|
(none))
|
|
|
|
(defmethod draw-info ((this speedrun-practice-objective))
|
|
(clear *temp-string*)
|
|
(clear *pc-encoded-temp-string*)
|
|
(pc-sr-mode-get-practice-entry-name (-> this index) *pc-encoded-temp-string*)
|
|
(format *temp-string* "<COLOR_WHITE>Practicing: <COLOR_GREEN>~S~%" *pc-encoded-temp-string*)
|
|
(if (> (pc-sr-mode-get-practice-entry-history-attempts (-> this index)) 0)
|
|
(format *temp-string* "<COLOR_WHITE>History: <COLOR_GREEN>~D<COLOR_WHITE>/~D (~,,2f%)~%"
|
|
(pc-sr-mode-get-practice-entry-history-success (-> this index))
|
|
(pc-sr-mode-get-practice-entry-history-attempts (-> this index))
|
|
(* 100.0 (/ (the float (pc-sr-mode-get-practice-entry-history-success (-> this index)))
|
|
(the float (pc-sr-mode-get-practice-entry-history-attempts (-> this index))))))
|
|
(format *temp-string* "<COLOR_WHITE>History: --~%"))
|
|
(if (> (pc-sr-mode-get-practice-entry-session-attempts (-> this index)) 0)
|
|
(format *temp-string* "<COLOR_WHITE>Session: <COLOR_GREEN>~D<COLOR_WHITE>/~D (~,,2f%)~%"
|
|
(pc-sr-mode-get-practice-entry-session-success (-> this index))
|
|
(pc-sr-mode-get-practice-entry-session-attempts (-> this index))
|
|
(* 100.0 (/ (the float (pc-sr-mode-get-practice-entry-session-success (-> this index)))
|
|
(the float (pc-sr-mode-get-practice-entry-session-attempts (-> this index))))))
|
|
(format *temp-string* "<COLOR_WHITE>Session: --~%"))
|
|
(pc-sr-mode-get-practice-entry-avg-time (-> this index) *pc-encoded-temp-string*)
|
|
(format *temp-string* "<COLOR_WHITE>Average Time: <COLOR_GREEN>~Ss~%" *pc-encoded-temp-string*)
|
|
(pc-sr-mode-get-practice-entry-fastest-time (-> this index) *pc-encoded-temp-string*)
|
|
(format *temp-string* "<COLOR_WHITE>Fastest Time: <COLOR_GREEN>~Ss~%" *pc-encoded-temp-string*)
|
|
(format *temp-string* "<COLOR_WHITE>\c91 L3: Reset~%")
|
|
(pc-encode-utf8-string *temp-string* *pc-encoded-temp-string*)
|
|
(with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) (bucket-id debug-no-zbuf2))
|
|
;; reset bucket settings prior to drawing - font won't do this for us, and
|
|
;; draw-raw-image can sometimes mess them up. (intro sequence)
|
|
(dma-buffer-add-gs-set-flusha buf (alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1)) (tex1-1 (new 'static 'gs-tex1 :mmag #x1 :mmin #x1)))
|
|
(let ((font-ctx (new 'stack 'font-context *font-default-matrix* 510 20 0.0 (font-color default) (font-flags right shadow kerning large))))
|
|
(set! (-> font-ctx scale) 0.325)
|
|
(draw-string-adv *pc-encoded-temp-string* buf font-ctx)))
|
|
(none))
|
|
|
|
(defmethod reset! ((this speedrun-practice-objective))
|
|
;; record attempt if attempt was started
|
|
(when (-> *speedrun-info* waiting-to-record-practice-attempt?)
|
|
(pc-sr-mode-record-practice-entry-attempt! (-> this index) #f (&-> (the-as speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))) recorded-time)))
|
|
;; TODO - load checkpoint if not already in that checkpoint
|
|
;; TODO - set features / cheats / completed-task / etc
|
|
;; Update player position
|
|
(vector-copy! (-> *target* root trans) (-> this starting-position))
|
|
(vector-copy! (-> *target* root quat) (-> this starting-rotation))
|
|
;; - get off jetboard and reset speed
|
|
(vector-copy! (-> *target* control transv) *zero-vector*)
|
|
(send-event *target* 'change-mode 'normal)
|
|
;; Update camera position and rotation
|
|
(vector-copy! (-> *camera-combiner* trans) (-> this starting-camera-position))
|
|
(matrix-identity! (-> *camera-combiner* inv-camera-rot))
|
|
(matrix-copy! (-> *camera-combiner* inv-camera-rot) (-> this starting-camera-rotation))
|
|
(process-spawn-function process
|
|
(lambda :behavior process ()
|
|
(suspend)
|
|
(send-event *camera* 'teleport)
|
|
(deactivate self)))
|
|
(cam-master-activate-slave #f)
|
|
(none))
|
|
|
|
(define *speedrun-popup-menu-entries*
|
|
(new 'static 'boxed-array :type popup-menu-entry
|
|
(new 'static 'popup-menu-button :label "Reset"
|
|
:on-confirm (lambda () (send-event (ppointer->process *speedrun-manager*) 'invoke (speedrun-menu-command reset))))
|
|
(new 'static 'popup-menu-submenu :label "Built-in category select"
|
|
:entries (new 'static 'boxed-array :type popup-menu-entry
|
|
(new 'static 'popup-menu-flag :label "Normal"
|
|
:on-confirm (lambda () (set-category! *speedrun-info* (speedrun-category newgame-normal)))
|
|
:is-toggled? (lambda () (= (-> *speedrun-info* category) (speedrun-category newgame-normal))))
|
|
(new 'static 'popup-menu-flag :label "Hero mode"
|
|
:on-confirm (lambda () (set-category! *speedrun-info* (speedrun-category newgame-heromode)))
|
|
:is-toggled? (lambda () (= (-> *speedrun-info* category) (speedrun-category newgame-heromode))))
|
|
(new 'static 'popup-menu-flag :label "All cheats allowed"
|
|
:on-confirm (lambda () (set-category! *speedrun-info* (speedrun-category all-cheats-allowed)))
|
|
:is-toggled? (lambda () (= (-> *speedrun-info* category) (speedrun-category all-cheats-allowed))))))
|
|
(new 'static 'popup-menu-dynamic-submenu :label "Custom category select"
|
|
:get-length (lambda () (pc-sr-mode-get-custom-category-amount))
|
|
:get-entry-label (lambda ((index int) (str-dest string)) (pc-sr-mode-get-custom-category-name index str-dest))
|
|
:on-entry-confirm (lambda ((index int))
|
|
;; hydrate from cpp
|
|
(pc-sr-mode-init-custom-category-info! index (-> *speedrun-info* active-custom-category))
|
|
(set-category! *speedrun-info* (speedrun-category custom)))
|
|
:entry-selected? (lambda ((index int))
|
|
(and (= (-> *speedrun-info* category) (speedrun-category custom))
|
|
(= index (-> *speedrun-info* active-custom-category index)))))
|
|
;; TODO - disabled until finalized
|
|
;; (new 'static 'popup-menu-dynamic-submenu :label "Practice select"
|
|
;; :entry-disabled? (lambda () (not (-> *speedrun-info* practicing?)))
|
|
;; :get-length (lambda () (pc-sr-mode-get-practice-entries-amount))
|
|
;; :get-entry-label (lambda ((index int) (str-dest string)) (pc-sr-mode-get-practice-entry-name index str-dest))
|
|
;; :on-entry-confirm (lambda ((index int))
|
|
;; ;; turn on timer
|
|
;; (set! (-> (the-as speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))) draw?) #t)
|
|
;; ;; tear down old processes
|
|
;; (when (nonzero? (-> *speedrun-info* active-practice-objective start-zone))
|
|
;; (deactivate (-> *speedrun-info* active-practice-objective start-zone 0)))
|
|
;; (when (nonzero? (-> *speedrun-info* active-practice-objective end-zone))
|
|
;; (deactivate (-> *speedrun-info* active-practice-objective end-zone 0)))
|
|
;; ;; init from cpp
|
|
;; (pc-sr-mode-init-practice-info! index (-> *speedrun-info* active-practice-objective))
|
|
;; ;; startup new processes
|
|
;; (set! (-> *speedrun-info* active-practice-objective start-zone)
|
|
;; (the-as (pointer objective-zone) (process-spawn objective-zone :init objective-zone-init #t (-> *speedrun-info* active-practice-objective start-zone-init-params))))
|
|
;; (set! (-> *speedrun-info* active-practice-objective start-zone 0 on-exit)
|
|
;; (lambda ()
|
|
;; (start! (the-as speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))))
|
|
;; (set! (-> *speedrun-info* waiting-to-record-practice-attempt?) #t)
|
|
;; (none)))
|
|
;; (set! (-> *speedrun-info* active-practice-objective start-zone 0 on-enter)
|
|
;; (lambda ()
|
|
;; (when (and *target* (>= (-> *target* control ctrl-xz-vel) (meters 30.0)))
|
|
;; (vector-copy! (-> *target* control transv) *zero-vector*))
|
|
;; (set! (-> *speedrun-info* waiting-to-record-practice-attempt?) #f)
|
|
;; (reset! (the-as speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))))
|
|
;; (none)))
|
|
|
|
;; (when (= 0 (-> *speedrun-info* active-practice-objective end-task))
|
|
;; (set! (-> *speedrun-info* active-practice-objective end-zone)
|
|
;; (the-as (pointer objective-zone) (process-spawn objective-zone :init objective-zone-init #f (-> *speedrun-info* active-practice-objective end-zone-init-params))))
|
|
;; (set! (-> *speedrun-info* active-practice-objective end-zone 0 on-enter)
|
|
;; (lambda ()
|
|
;; (when (-> *speedrun-info* waiting-to-record-practice-attempt?)
|
|
;; (stop! (the-as speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))))
|
|
;; (if (pc-sr-mode-record-practice-entry-attempt! (-> *speedrun-info* active-practice-objective index)
|
|
;; #t
|
|
;; (&-> (the-as speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))) recorded-time))
|
|
;; (sound-play "skill-pickup")
|
|
;; (sound-play "menu-pick"))
|
|
;; (set! (-> *speedrun-info* waiting-to-record-practice-attempt?) #f))
|
|
;; (none))))
|
|
;; (set! (-> *speedrun-info* practicing?) #t)
|
|
;; (reset! (-> *speedrun-info* active-practice-objective))
|
|
;; (set-master-mode 'game)
|
|
;; (send-event (ppointer->process (-> *speedrun-manager* 0 popup-menu)) 'close-menu))
|
|
;; :entry-selected? (lambda ((index int)) (and (-> *speedrun-info* practicing?) (= index (-> *speedrun-info* active-practice-objective index)))))
|
|
;; (new 'static 'popup-menu-button :label "Stop practicing"
|
|
;; :entry-disabled? (lambda () (not (-> *speedrun-info* practicing?)))
|
|
;; :on-confirm (lambda ()
|
|
;; (when (-> *speedrun-info* practicing?)
|
|
;; (when (nonzero? (-> *speedrun-info* active-practice-objective start-zone))
|
|
;; (deactivate (-> *speedrun-info* active-practice-objective start-zone 0)))
|
|
;; (when (nonzero? (-> *speedrun-info* active-practice-objective end-zone))
|
|
;; (deactivate (-> *speedrun-info* active-practice-objective end-zone 0))))
|
|
;; (set! (-> *speedrun-info* practicing?) #f)
|
|
;; (set! (-> (the-as speedrun-timer (ppointer->process (-> *speedrun-manager* 0 timer))) draw?) #f)))
|
|
(new 'static 'popup-menu-submenu :label "Tools"
|
|
:entries (new 'static 'boxed-array :type popup-menu-entry
|
|
(new 'static 'popup-menu-submenu :label "Create custom category"
|
|
:entries (new 'static 'boxed-array :type popup-menu-entry
|
|
(new 'static 'popup-menu-dynamic-submenu :label "Select secrets"
|
|
:get-length (lambda () 18)
|
|
:get-entry-label (lambda ((index int) (str-dest string)) (copy-string<-string str-dest (bitfield->string game-secrets index)))
|
|
:on-entry-confirm (lambda ((index int)) (logxor! (-> *speedrun-info* dump-custom-category secrets) (shl 1 index)))
|
|
:entry-selected? (lambda ((index int)) (logtest? (-> *speedrun-info* dump-custom-category secrets) (shl 1 index)))
|
|
:on-reset (lambda () (set! (-> *speedrun-info* dump-custom-category secrets) (game-secrets))))
|
|
(new 'static 'popup-menu-dynamic-submenu :label "Select features"
|
|
:get-length (lambda () 27)
|
|
:get-entry-label (lambda ((index int) (str-dest string)) (copy-string<-string str-dest (bitfield->string game-feature index)))
|
|
:on-entry-confirm (lambda ((index int)) (logxor! (-> *speedrun-info* dump-custom-category features) (shl 1 index)))
|
|
:entry-selected? (lambda ((index int)) (logtest? (-> *speedrun-info* dump-custom-category features) (shl 1 index)))
|
|
:on-reset (lambda () (set! (-> *speedrun-info* dump-custom-category features) (game-feature))))
|
|
(new 'static 'popup-menu-dynamic-submenu :label "Forbid features"
|
|
:get-length (lambda () 27)
|
|
:get-entry-label (lambda ((index int) (str-dest string)) (copy-string<-string str-dest (bitfield->string game-feature index)))
|
|
:on-entry-confirm (lambda ((index int)) (logxor! (-> *speedrun-info* dump-custom-category forbidden-features) (shl 1 index)))
|
|
:entry-selected? (lambda ((index int)) (logtest? (-> *speedrun-info* dump-custom-category forbidden-features) (shl 1 index)))
|
|
:on-reset (lambda () (set! (-> *speedrun-info* dump-custom-category forbidden-features) (game-feature))))
|
|
(new 'static 'popup-menu-dynamic-submenu :label "Select cheats"
|
|
:get-length (lambda () 20)
|
|
:get-entry-label (lambda ((index int) (str-dest string)) (copy-string<-string str-dest (bitfield->string pc-cheats index)))
|
|
:on-entry-confirm (lambda ((index int)) (logxor! (-> *speedrun-info* dump-custom-category pc-cheats) (shl 1 index)))
|
|
:entry-selected? (lambda ((index int)) (logtest? (-> *speedrun-info* dump-custom-category pc-cheats) (shl 1 index)))
|
|
:on-reset (lambda () (set! (-> *speedrun-info* dump-custom-category pc-cheats) (pc-cheats))))
|
|
(new 'static 'popup-menu-dynamic-submenu :label "Select completed task"
|
|
:get-length (lambda () (dec (the int (game-task max))))
|
|
:get-entry-label (lambda ((index int) (str-dest string)) (copy-string<-string str-dest (enum->string game-task index)))
|
|
:on-entry-confirm (lambda ((index int)) (set! (-> *speedrun-info* dump-custom-category completed-task) (the game-task index)))
|
|
:entry-selected? (lambda ((index int)) (= (-> *speedrun-info* dump-custom-category completed-task) (the game-task index)))
|
|
:on-reset (lambda () (set! (-> *speedrun-info* dump-custom-category completed-task) (game-task none))))
|
|
(new 'static 'popup-menu-button :label "Save new category to file"
|
|
:on-confirm (lambda () (pc-sr-mode-dump-new-custom-category (-> *speedrun-info* dump-custom-category))))))))
|
|
(new 'static 'popup-menu-button :label "Exit"
|
|
:on-confirm (lambda () (send-event (ppointer->process *speedrun-manager*) 'invoke (speedrun-menu-command exit))))
|
|
))
|
|
|
|
(define *speedrun-manager* (the-as (pointer speedrun-manager) #f))
|
|
|
|
(defbehavior speedrun-manager-init speedrun-manager ()
|
|
(set! *speedrun-manager* (the-as (pointer speedrun-manager) (process->ppointer self)))
|
|
(set! (-> *speedrun-manager* 0 popup-menu)
|
|
(the-as (pointer popup-menu) (process-spawn popup-menu :init popup-menu-init "Speedrun Menu" *speedrun-popup-menu-entries*)))
|
|
(set! (-> *speedrun-manager* 0 timer)
|
|
(the-as (pointer speedrun-timer) (process-spawn speedrun-timer :init speedrun-timer-init)))
|
|
(set! (-> *speedrun-manager* 0 ignore-menu-toggle?) #f)
|
|
(set! (-> *speedrun-manager* 0 opened-with-start?) #f)
|
|
(set! (-> *speedrun-info* practicing?) #f)
|
|
(set! (-> *speedrun-info* waiting-to-record-practice-attempt?) #f)
|
|
(go-virtual idle)
|
|
(none))
|
|
|
|
(defmethod update! ((this speedrun-info))
|
|
"A per frame update for speedrunning related stuff"
|
|
;; Ensure the speedrunner menu process is enabled or destroyed
|
|
(when (and (-> *pc-settings* speedrunner-mode?)
|
|
(not *speedrun-manager*))
|
|
(process-spawn speedrun-manager :init speedrun-manager-init #f :to *entity-pool*))
|
|
(when (and (not (-> *pc-settings* speedrunner-mode?))
|
|
*speedrun-manager*)
|
|
(deactivate (-> *speedrun-manager* 0)))
|
|
;; do speedrunner mode things
|
|
(when (-> *pc-settings* speedrunner-mode?)
|
|
;; Update auto-splitter struct
|
|
(update! *autosplit-info-jak2*)
|
|
;; see if we should stop drawing the run info (when you escape the fortress!)
|
|
(when (and (!= (-> this category) (speedrun-category custom))
|
|
(task-complete? *game-info* (game-task fortress-escape)))
|
|
(set! (-> this display-run-info?) #f))
|
|
;; Draw info to the screen
|
|
(when (and (not (-> *speedrun-info* practicing?)) (-> this display-run-info?))
|
|
(draw-run-info this))
|
|
;; enforce settings even if they've changed them
|
|
(enforce-settings! this)
|
|
;; draw objective info if practicing
|
|
(when (-> *speedrun-info* practicing?)
|
|
(draw-info (-> this active-practice-objective))))
|
|
(none))
|
|
|
|
(defmethod draw-run-info ((this speedrun-info))
|
|
"Draw speedrun related settings in the bottom left corner"
|
|
(when (and (-> *pc-settings* speedrunner-mode?)
|
|
(-> this display-run-info?))
|
|
(clear *temp-string*)
|
|
(clear *pc-encoded-temp-string*)
|
|
(clear *pc-cpp-temp-string*)
|
|
(cond
|
|
((= (-> this category) (speedrun-category custom))
|
|
(pc-sr-mode-get-custom-category-name (-> this active-custom-category index) *pc-cpp-temp-string*)
|
|
(format *temp-string*
|
|
"<COLOR_WHITE>Category: <COLOR_GREEN>~S~%<COLOR_WHITE>Secrets: <COLOR_GREEN>~D~%<COLOR_WHITE>Features: <COLOR_GREEN>~D~%<COLOR_WHITE>Forbidden Features: <COLOR_GREEN>~D~%<COLOR_WHITE>Cheats: <COLOR_GREEN>~D~%<COLOR_WHITE>Version: <COLOR_GREEN>~S~%"
|
|
*pc-cpp-temp-string*
|
|
(-> this active-custom-category secrets)
|
|
(-> this active-custom-category features)
|
|
(-> this active-custom-category forbidden-features)
|
|
(-> this active-custom-category pc-cheats)
|
|
*pc-settings-built-sha*))
|
|
(else
|
|
(format *temp-string*
|
|
"<COLOR_WHITE>Category: <COLOR_GREEN>~S~%<COLOR_WHITE>PC Cheats: <COLOR_GREEN>~D~%<COLOR_WHITE>Frame Rate: <COLOR_GREEN>~D~%<COLOR_WHITE>PS2 Actor Vis?: <COLOR_GREEN>~S~%<COLOR_WHITE>Version: <COLOR_GREEN>~S~%"
|
|
(enum->string speedrun-category (-> this category))
|
|
(the-as int (-> *pc-settings* cheats))
|
|
(-> *pc-settings* target-fps)
|
|
(if (-> *pc-settings* ps2-actor-vis?) "true" "false")
|
|
*pc-settings-built-sha*)))
|
|
(pc-encode-utf8-string *temp-string* *pc-encoded-temp-string*)
|
|
(with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) (bucket-id debug-no-zbuf2))
|
|
;; reset bucket settings prior to drawing - font won't do this for us, and
|
|
;; draw-raw-image can sometimes mess them up. (intro sequence)
|
|
(dma-buffer-add-gs-set-flusha buf (alpha-1 (new 'static 'gs-alpha :b #x1 :d #x1)) (tex1-1 (new 'static 'gs-tex1 :mmag #x1 :mmin #x1)))
|
|
(let ((font-ctx (new 'stack 'font-context *font-default-matrix* 510 (if (= (-> this category) (speedrun-category custom)) 355 365) 0.0 (font-color default) (font-flags right shadow kerning large))))
|
|
(set! (-> font-ctx scale) 0.325)
|
|
(draw-string-adv *pc-encoded-temp-string* buf font-ctx))))
|
|
(none))
|
|
|
|
;; Speedrun Menu
|
|
|
|
(defmethod deactivate ((this speedrun-manager))
|
|
(set! *speedrun-manager* (the-as (pointer speedrun-manager) #f))
|
|
((method-of-type process deactivate) this)
|
|
(none))
|
|
|
|
(defstate idle (speedrun-manager)
|
|
:virtual #t
|
|
:event (behavior ((proc process) (arg1 int) (event-type symbol) (event event-message-block))
|
|
(case event-type
|
|
(('start-run)
|
|
(set-time! (-> *speedrun-info* run-started-at)))
|
|
(('invoke)
|
|
(case (-> event param 0)
|
|
(((speedrun-menu-command reset))
|
|
(start-run! *speedrun-info*))
|
|
(((speedrun-menu-command exit))
|
|
(set-master-mode 'game)
|
|
(send-event (ppointer->process (-> self popup-menu)) 'close-menu))
|
|
(else
|
|
(format 0 "nyi: invoke ~D~%" (-> event param 0))))))
|
|
(the-as object 0))
|
|
:trans (behavior ()
|
|
(none))
|
|
:code (behavior ()
|
|
(until #f
|
|
(when (and (-> *speedrun-info* practicing?) (cpad-pressed? 0 l3))
|
|
(reset! (-> *speedrun-info* active-practice-objective)))
|
|
(when (and (-> *speedrun-info* display-run-info?)
|
|
(= (-> *speedrun-info* category) (speedrun-category custom))
|
|
(time-elapsed? (-> *speedrun-info* run-started-at) (seconds 15)))
|
|
(set! (-> *speedrun-info* display-run-info?) #f))
|
|
(suspend))
|
|
(none))
|
|
:post (behavior ()
|
|
(none)))
|
|
|
|
(defmethod draw-menu ((this speedrun-manager))
|
|
;; don't allow the menu to open during blackouts, apparently causes bugs
|
|
(when (>= (-> *game-info* blackout-time) (current-time))
|
|
(return 0))
|
|
;; handle opening and closing the menu
|
|
(cond
|
|
((!= (-> *pc-settings* speedrunner-mode-custom-bind) 0)
|
|
;; the user has let go of the keybind completely or partially, allow the bind to trigger again
|
|
(when (and (-> this ignore-menu-toggle?)
|
|
(!= (cpad-hold 0)
|
|
(logior (cpad-hold 0) (-> *pc-settings* speedrunner-mode-custom-bind))))
|
|
(set! (-> this ignore-menu-toggle?) #f))
|
|
;; bind handler
|
|
(when (and (not (-> this ignore-menu-toggle?))
|
|
(= (cpad-hold 0)
|
|
(logior (cpad-hold 0) (-> *pc-settings* speedrunner-mode-custom-bind))))
|
|
(cond
|
|
((= *master-mode* 'game)
|
|
(set-master-mode 'menu)
|
|
(send-event (ppointer->process (-> this popup-menu)) 'open-menu))
|
|
((= *master-mode* 'menu)
|
|
(set-master-mode 'game)
|
|
(send-event (ppointer->process (-> this popup-menu)) 'close-menu)))
|
|
(logclear! (cpad-hold 0) (-> *pc-settings* speedrunner-mode-custom-bind))
|
|
(logclear! (cpad-pressed 0) (-> *pc-settings* speedrunner-mode-custom-bind))
|
|
(set! (-> this ignore-menu-toggle?) #t)))
|
|
(else
|
|
(when (and (-> this ignore-menu-toggle?)
|
|
(or (not (cpad-hold? 0 l1)) (not (cpad-hold? 0 r1)))
|
|
(or (and (-> this opened-with-start?) (not (cpad-hold? 0 start)))
|
|
(and (not (-> this opened-with-start?)) (not (cpad-hold? 0 select)))))
|
|
(set! (-> this ignore-menu-toggle?) #f))
|
|
(when (and (cpad-hold? 0 l1) (cpad-hold? 0 r1) (or (cpad-hold? 0 select) (cpad-hold? 0 start))
|
|
(not (-> this ignore-menu-toggle?)))
|
|
(cond
|
|
((= *master-mode* 'game)
|
|
(set-master-mode 'menu)
|
|
(send-event (ppointer->process (-> this popup-menu)) 'open-menu))
|
|
((= *master-mode* 'menu)
|
|
(set-master-mode 'game)
|
|
(send-event (ppointer->process (-> this popup-menu)) 'close-menu)))
|
|
(cpad-clear! 0 l1 r1)
|
|
(cond
|
|
((cpad-hold? 0 select)
|
|
(cpad-clear! 0 select)
|
|
(set! (-> this opened-with-start?) #f))
|
|
((cpad-hold? 0 start)
|
|
(cpad-clear! 0 start)
|
|
(set! (-> this opened-with-start?) #t)))
|
|
(set! (-> this ignore-menu-toggle?) #t))))
|
|
;; render menu / handle inputs
|
|
(update-menu! (the-as popup-menu (ppointer->process (-> this popup-menu))))
|
|
(none))
|