Files
jak-project/goal_src/jak2/pc/progress/progress-pc.gc

1223 lines
49 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
#|
Additional PC port specific file for overriding/expanding the progress menu
This gives us more freedom to write code how we want.
|#
(deftype progress-global-state-pc (basic)
((decoration-draw-time uint64)
(aspect-ratio-ratio-index int8)
(frame-rate-choice-index int8)
(frame-rate-disclaimer-time time-frame)
(music-player-track music-player-track-info)
(music-player-flava int8)
(music-player-selected symbol)
)
)
(define *progress-state-pc* (new 'static 'progress-global-state-pc :music-player-track #f))
(defmacro when-not-drawn-decoration (&rest body)
`(when (> (-> *display* real-clock integral-frame-counter) (-> *progress-state-pc* decoration-draw-time))
,@body
(set! (-> *progress-state-pc* decoration-draw-time) (-> *display* real-clock integral-frame-counter))))
(defun set-progress-frame-rate-index ((idx int))
"Set the frame rate option index accordingly."
(when idx
(set! (-> *progress-state-pc* frame-rate-choice-index) idx)
(return 0)
)
;; default to 60 fps
(set! (-> *progress-state-pc* frame-rate-choice-index) 0)
;; lookup entry that matches
(dotimes (i (-> *frame-rate-options* length))
(if (= (-> *pc-settings* target-fps) (-> *frame-rate-options* i))
(set! (-> *progress-state-pc* frame-rate-choice-index) i))
)
0)
(defmethod init-defaults ((obj progress))
"Initialize default menu settings."
(set! (-> *progress-state* aspect-ratio-choice) (get-aspect-ratio))
(set! (-> *progress-state* video-mode-choice) (get-video-mode))
(set! (-> *progress-state* yes-no-choice) #f)
(set! (-> *progress-state* on-off-choice) #f)
(set! (-> *progress-state* color-flash-counter) 0)
(set! (-> *progress-state* game-options-item-selected) 0)
(set! (-> *progress-state* game-options-item-picked) #f)
(set! (-> *progress-state* game-options-vibrations) (-> *setting-control* user-default vibration))
(set! (-> *progress-state* game-options-subtitles) (-> *setting-control* user-default subtitle))
(set! (-> *progress-state* game-options-language-index)
(the-as int (-> *setting-control* user-default language))
)
(set! (-> *progress-state* game-options-subtitle-language-index)
(the-as int (-> *setting-control* user-default subtitle-language))
)
(set! (-> *progress-state* graphic-options-item-selected) 0)
(set! (-> *progress-state* graphic-options-item-picked) #f)
(set! (-> *progress-state* graphic-options-aspect-ratio) (get-aspect-ratio))
(set! (-> *progress-state* graphic-options-progressive-scan)
(-> *setting-control* user-default use-progressive-scan)
)
(set! (-> *progress-state* qr-options-item-selected) 0)
(set! (-> *progress-state* qr-options-item-picked) #f)
(set! (-> *progress-state* total-num-tasks) 0)
(set! (-> *progress-state* secrets-unlocked) #f)
(set! (-> *progress-state* clear-screen) #f)
(set! (-> obj sliding) 0.0)
(set! (-> obj sliding-height) 0.0)
(set! (-> obj sliding-off) 1.0)
(set! (-> obj scanlines-alpha) 0.0)
(set! (-> (the-as menu-on-off-game-vibrations-option (-> *game-options* options 0)) value-to-modify)
(&-> *setting-control* user-default vibration)
)
(set! (-> (the-as menu-on-off-game-subtitles-option (-> *game-options* options 1)) value-to-modify)
(&-> *setting-control* user-default subtitle)
)
(set! (-> (the-as menu-language-option (-> *game-options* options 2)) language-selection)
(-> *setting-control* user-current language)
)
(set! (-> (the-as menu-language-option (-> *game-options* options 2)) language-direction) #t)
(set! (-> (the-as menu-language-option (-> *game-options* options 2)) language-transition) #f)
(set! (-> (the-as menu-language-option (-> *game-options* options 2)) language-x-offset) 0)
(set! (-> (the-as menu-on-off-option (-> *game-options-japan* options 0)) value-to-modify)
(&-> *setting-control* user-default vibration)
)
(set! (-> (the-as menu-on-off-option (-> *game-options-demo* options 0)) value-to-modify)
(&-> *setting-control* user-default vibration)
)
(set! (-> (the-as menu-on-off-option (-> *graphic-options* options 2)) value-to-modify)
(&-> *setting-control* user-default use-progressive-scan)
)
(set! (-> (the-as menu-on-off-option (-> *graphic-title-options-pal* options 2)) value-to-modify)
(&-> *setting-control* user-default use-progressive-scan)
)
(set! (-> (the-as menu-slider-option (-> *sound-options* options 0)) value-to-modify)
(&-> *setting-control* user-default sfx-volume)
)
(set! (-> (the-as menu-slider-option (-> *sound-options* options 1)) value-to-modify)
(&-> *setting-control* user-default music-volume)
)
(set! (-> (the-as menu-slider-option (-> *sound-options* options 2)) value-to-modify)
(&-> *setting-control* user-default dialog-volume)
)
(set! (-> (the-as menu-missions-option (-> *missions-options* options 0)) task-line-index) 0)
(set-setting-by-param *setting-control* 'extra-bank '((force2 menu1)) 0 0)
;; PC STATE BEGIN
;; --------------
(init! *progress-pc-generic-store*)
(set! (-> *progress-state-pc* music-player-track) #f)
)
(defun progress-pc-fetch-external-times ((highscore-index int))
(when (-> *pc-settings* speedrunner-mode?)
(case highscore-index
((0) (pc-fetch-external-highscores "scatter"))
((1) (pc-fetch-external-highscores "blaster"))
((2) (pc-fetch-external-highscores "vulcan"))
((3) (pc-fetch-external-highscores "peacemaker"))
((4) (pc-fetch-external-highscores "jetboard"))
((5) (pc-fetch-external-race-times "class3"))
((6) (pc-fetch-external-race-times "class2"))
((7) (pc-fetch-external-race-times "class1"))
((8) (pc-fetch-external-race-times "port"))
((9) (pc-fetch-external-race-times "erol"))
((10) (pc-fetch-external-race-times "class3rev"))
((11) (pc-fetch-external-race-times "class2rev"))
((12) (pc-fetch-external-race-times "class1rev"))
((13) (pc-fetch-external-highscores "onin"))
((14) (pc-fetch-external-highscores "mash"))
((15) (pc-fetch-external-speedrun-times "any"))
((16) (pc-fetch-external-speedrun-times "anyhoverless"))
((17) (pc-fetch-external-speedrun-times "allmissions"))
((18) (pc-fetch-external-speedrun-times "100"))
((19) (pc-fetch-external-speedrun-times "anyorbs"))
((20) (pc-fetch-external-speedrun-times "anyhero")))))
(defmethod set-menu-options ((obj progress) (arg0 symbol))
"Set the menu options for the menu state specified by arg0."
(set! (-> obj current-options) #f)
(case arg0
(('go-away)
(go (method-of-object obj go-away))
)
(('main)
(set! (-> obj current-options) (cond
(*cheat-mode*
*main-options*
)
((= *kernel-boot-message* 'kiosk)
*main-kiosk-options*
)
((demo?)
*main-demo-options*
)
(else
*main-options*
)
)
)
)
(('game-options)
(set! (-> obj current-options)
(if (demo?) *game-options-demo* *game-options-pc*))
)
(('game-options-title)
(set! (-> obj current-options)
(if (demo?) *game-options-demo* *game-options-title-pc*))
)
(('graphic-options)
(set! (-> obj current-options) *graphic-options-pc*)
)
(('sound-options)
(set! (-> obj current-options) *sound-options*)
)
(('select-load 'select-save)
(set! (-> obj current-options) *load-save-options*)
)
(('select-save-title)
(set! (-> obj current-options) *save-options-title*)
)
(('select-save-title-hero)
(logior! (-> *game-info* purchase-secrets) (game-secrets hero-mode))
(logior! (-> *game-info* secrets) (game-secrets hero-mode))
(set! (-> obj current-options) *save-options-title*)
)
(('loading 'saving 'creating 'formatting)
(set! (-> obj current-options) *loading-options*)
)
(('unformatted-card 'insufficient-space 'no-memory-card)
(set! (-> obj current-options) *insufficient-space-options*)
)
(('secrets-insufficient-space 'secrets-no-memory-card)
(set! (-> obj current-options) *secrets-insufficient-space-options*)
)
(('insert-card)
(set! (-> obj current-options) *insert-card-options*)
)
(('error-loading 'error-saving 'error-formatting 'error-creating)
(set! (-> obj current-options) *error-loading-options*)
)
(('error-auto-saving)
(set! (-> obj current-options) *error-auto-saving-options*)
)
(('card-removed)
(set! (-> obj current-options) *card-removed-options*)
)
(('error-disc-removed)
(set! (-> obj current-options) *error-disc-removed-options*)
)
(('error-reading)
(set! (-> obj current-options) *error-reading-options*)
)
(('icon-info)
(set! (-> obj current-options) *icon-info-options*)
)
(('format-card)
(set! (-> obj current-options) *format-card-options*)
)
(('already-exists)
(set! (-> obj current-options) *already-exists-options*)
)
(('create-game)
(set! (-> obj current-options) *create-game-options*)
)
(('video-mode-warning)
(set! (-> obj current-options) *video-mode-warning-options*)
)
(('video-mode-ok)
(set! (-> obj current-options) *video-mode-ok-options*)
)
(('progressive-mode-warning)
(set! (-> obj current-options) *progressive-mode-warning-options*)
)
(('progressive-mode-ok)
(set! (-> obj current-options) *progressive-mode-ok-options*)
)
(('quit)
(set! (-> obj current-options) *quit-options*)
)
(('title)
(set! (-> obj current-options) *title-pc*)
)
(('title-options)
(set! (-> obj current-options) *options-pc*)
)
(('select-start 'select-pre-start 'select-kiosk-start)
(set! (-> obj current-options) *select-start-options*)
(set! (-> (the-as menu-select-start-option (-> (the-as (array menu-option) (-> *select-start-options* options)) 0))
task-index
)
0
)
0
)
(('select-scene)
(set! (-> obj current-options) *select-scene-options*)
(set! (-> (the-as menu-select-scene-option (-> (the-as (array menu-option) (-> *select-scene-options* options)) 0))
task-index
)
0
)
0
)
(('select-scene-special)
(set! (-> *progress-state* starting-state) 'title)
(set! (-> obj state-pos) 0)
(let ((v1-67 (-> obj state-pos)))
(set! (-> obj state-stack v1-67) 'title)
(set! (-> obj option-index-stack v1-67) 3)
(let ((v1-68 (+ v1-67 1)))
(set! (-> obj state-stack v1-68) 'unlocked-secrets)
(set! (-> obj option-index-stack v1-68) (-> obj option-index))
(set! (-> obj state-pos) (+ v1-68 1))
)
)
(dotimes (s5-1 (-> obj state-pos))
(format
#t
"select-scene-special: ~S ~D~%"
(symbol->string (-> obj state-stack s5-1))
(-> obj option-index-stack s5-1)
)
)
(set! (-> obj current-options) *select-scene-options*)
)
(('bigmap)
(set! (-> obj current-options) *bigmap-options*)
)
(('missions)
(set! (-> *progress-state* missions-total-spacing) 0.0)
(set! (-> (the-as menu-missions-option (-> (the-as (array menu-option) (-> *missions-options* options)) 0))
task-line-index
)
0
)
(set! (-> obj current-options) *missions-options*)
)
(('highscores)
(set! (-> (the-as menu-highscores-option (-> (the-as (array menu-option) (-> *highscores-options* options)) 0))
page-index
)
0
)
(set! (-> (the-as menu-highscores-option (-> (the-as (array menu-option) (-> *highscores-options* options)) 0))
prev-page-index
)
0
)
(set! (-> obj current-options) *highscores-options*)
;; ensure external data is fetched if applicable
(progress-pc-fetch-external-times 0)
(set! (-> *progress-pc-generic-store* current-highscore-page-index) 0)
)
(('secret)
(set! (-> obj secret-buying) #f)
(set! (-> obj current-options) *secret-options*)
)
(('quit-restart)
(set! (-> obj current-options) *quit-restart-options*)
)
(('unlocked-secrets)
(set! (-> obj current-options) *unlocked-secrets-pc*)
)
(('aspect-ratio-custom)
(set! (-> *progress-state-pc* aspect-ratio-ratio-index) 0)
(set! (-> obj current-options) *aspect-ratio-custom-options*)
)
(('music-player)
(set! (-> *progress-state-pc* music-player-selected) #f)
(set! (-> (the-as menu-music-player-option (-> *music-player-options* options 0)) excitement) 0)
(set! (-> obj current-options) *music-player-options*)
(when (aif (level-get *level* 'title) (= (-> it status) 'active))
(remove-setting *setting-control* (handle->process (-> *game-info* controller 0)) 'music-volume)
)
)
(('resolutions)
(set! (-> (the-as menu-resolution-option (-> *resolutions-options* options 0)) selected-index) -1)
(set! (-> obj current-options) *resolutions-options*)
)
(('fps-disclaimer)
(set-time! (-> *progress-state-pc* frame-rate-disclaimer-time))
(set! (-> obj current-options) *frame-rate-disclaimer-options*)
)
(('generic-menu)
;; a single condition to handle all generic menu links
(let ((curr-history-entry (-> *progress-pc-generic-store* history-stack
(-> *progress-pc-generic-store* history-stack-index))))
;; call the on-load function is appropriate, this can be used to perform some kind of generic setup
;; for the particular route
(call-on-load curr-history-entry)
;; restore state from the history entry
(set! (-> *progress-pc-generic-store* clear-screen?) #f)
(set! (-> *progress-pc-generic-store* current-menu-hover-index) (-> curr-history-entry hover-index))
(set! (-> *progress-pc-generic-store* current-menu-scroll-index) (the float (-> curr-history-entry scroll-index)))
(if (!= (-> curr-history-entry progress-id) 'generic-menu)
;; do a recursive call to hit the relevant case in this switch
(set-menu-options obj (-> curr-history-entry progress-id))
;; otherwise, set the options
(set! (-> obj current-options) (-> curr-history-entry ref)))))
)
(when (= (-> obj current-options) #f)
(format #t "Didn't find new menu settings!!~%")
(pop-state obj)
)
0
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; CUSTOM MENU OPTIONS
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro min-max-wrap-around+! (var inc minimum maximum)
`(set! ,var (min-max-wrap-around (+ ,var ,inc) ,minimum ,maximum)))
(defmethod respond-progress ((obj menu-aspect-ratio-custom-option) (arg0 progress) (arg1 symbol))
"Handle progress menu navigation logic."
(let ((aspect-custom-val-ptr (case (-> *progress-state-pc* aspect-ratio-ratio-index)
((0)
(&-> *pc-settings* aspect-custom-x))
((1)
(&-> *pc-settings* aspect-custom-y))
(else
(&-> *pc-settings* aspect-custom-x))
)))
(cond
((cpad-pressed? 0 left l-analog-left)
(when (< 0 (-> *progress-state-pc* aspect-ratio-ratio-index))
(sound-play "roll-over")
(1-! (-> *progress-state-pc* aspect-ratio-ratio-index))
)
)
((cpad-pressed? 0 right l-analog-right)
(when (> 1 (-> *progress-state-pc* aspect-ratio-ratio-index))
(sound-play "roll-over")
(1+! (-> *progress-state-pc* aspect-ratio-ratio-index))
)
)
((cpad-pressed? 0 up l-analog-up)
(when (> 99 (-> aspect-custom-val-ptr))
(sound-play "roll-over")
(1+! (-> aspect-custom-val-ptr))
)
)
((cpad-pressed? 0 down l-analog-down)
(when (< 1 (-> aspect-custom-val-ptr))
(sound-play "roll-over")
(1-! (-> aspect-custom-val-ptr))
)
)
((cpad-pressed? 0 triangle)
(cpad-clear! 0 triangle)
(sound-play "generic-beep")
(pop-state arg0)
)
((cpad-pressed? 0 confirm)
(cpad-clear! 0 confirm)
(when (>= (/ (the float (-> *pc-settings* aspect-custom-x)) (the float (-> *pc-settings* aspect-custom-y))) (/ 4.0 3.0))
(set! (-> *setting-control* user-default aspect-ratio) 'aspect4x3)
(set-aspect! *pc-settings* (-> *pc-settings* aspect-custom-x) (-> *pc-settings* aspect-custom-y))
(sound-play "generic-beep")
(pop-state arg0)
)
)
))
0
)
(defmethod respond-progress menu-frame-rate-disclaimer-option ((this menu-frame-rate-disclaimer-option) (arg0 progress) (arg1 symbol))
"Handle progress menu navigation logic."
(when (time-elapsed? (-> *progress-state-pc* frame-rate-disclaimer-time) (seconds 3))
(let ((choice (&-> *progress-state* yes-no-choice))
(sound? #f)
)
(cond
((cpad-pressed? 0 left l-analog-left)
(set! sound? (not (-> choice 0)))
(set! (-> choice 0) #t)
)
((cpad-pressed? 0 right l-analog-right)
(set! sound? (-> choice 0))
(set! (-> choice 0) #f)
)
((cpad-pressed? 0 confirm)
(cpad-clear! 0 confirm)
(cond
((-> *progress-state* yes-no-choice)
(true! *frame-rate-disclaimer-seen?*)
(sound-play "generic-beep")
(set-frame-rate! *pc-settings* (-> *frame-rate-options* (-> *progress-state-pc* frame-rate-choice-index)) #t)
(commit-to-file *pc-settings*)
(pop-state arg0)
)
(else
(sound-play "generic-beep")
(set-progress-frame-rate-index (the int #f))
(pop-state arg0)
)
)
)
)
(if sound?
(sound-play "generic-beep")
)
)
)
0
)
(defbehavior play-music-player progress ((info music-player-track-info) (flava int))
"play a music track using music player track info."
(set! (-> *progress-state-pc* music-player-track) info)
(set-setting! 'music (-> info name) 0.0 0)
(set-setting! 'sound-flava #f 999999.0 flava)
(set-setting! 'sound-mode #f 0.0 (-> info mode))
(apply-settings *setting-control*)
(sound-group-continue (sound-group music))
0)
(defbehavior stop-music-player progress ()
"play a music track using music player track info."
(remove-setting! 'music)
(remove-setting! 'sound-flava)
(remove-setting! 'sound-mode)
(sound-set-midi-reg 0 0)
(sound-set-midi-reg 2 0)
(sound-set-midi-reg 16 0)
(set! (-> *progress-state-pc* music-player-track) #f)
;(min! (-> *setting-control* user-current sound-excitement) 0.0)
(sound-set-midi-reg 16 (the int (* 100.0 (-> *setting-control* user-current sound-excitement))))
(set! (-> *setting-control* sound-excitement-change-time) (-> *display* base-clock frame-counter))
(apply-settings *setting-control*)
(sound-group-pause (sound-group music))
0)
(defun count-bits ((val int))
"return the number of bits set to 1."
(let ((bits 0))
(dotimes (i 64)
(if (logtest? val (ash 1 i))
(1+! bits))
)
bits)
)
(defun bit-on-offset ((bits int) (n int))
"return the bit offset of where the n'th bit that is set to 1 is"
(let ((bit-on-i 0))
(dotimes (i 64)
(if (logtest? bits (ash 1 i))
(if (= bit-on-i n)
(return i)
(1+! bit-on-i)))
))
-1)
(defmethod respond-progress ((obj menu-music-player-option) (arg0 progress) (arg1 symbol))
"Handle progress menu navigation logic."
(if (= 0.0 (-> obj max-scroll))
(set! (-> obj max-scroll) (+ -141.0 (* (-> *music-player-tracks* length) 23))))
;; control logic
(let ((scroll-sound? #f)
(track-max (1- (-> *music-player-tracks* length)))
(flava-max (1- (count-bits (the-as int (-> *music-player-tracks* (-> obj music-index) flava)))))
(old-excitement (-> obj excitement))
(play? #f))
;; excitement controls
(cond
((cpad-pressed? 0 right l-analog-right)
(seekl! (-> obj excitement) 3 1))
((cpad-pressed? 0 left l-analog-left)
(seekl! (-> obj excitement) 0 1))
)
(when (!= (-> obj excitement) old-excitement)
(sound-play "generic-beep")
(sound-set-midi-reg 16 (* 25 (-> obj excitement))) ;; play new excitement track
(unless (or (< (-> obj excitement) old-excitement) (process-by-name "sound-stinger" arg0))
(process-spawn-function process :to arg0 :name "sound-stinger"
(lambda :behavior process ((stinger int))
(let ((state-time (current-time)))
(format 0 "set stinger ~D~%" stinger)
(sound-set-midi-reg 0 stinger)
(until (>= (- (current-time) state-time) (seconds 0.5))
(suspend))
(sound-set-midi-reg 0 0)
)
)
(+ 9 (-> obj excitement)))
)
(unless (process-by-name "sound-excitement" arg0)
(process-spawn-function process :to arg0 :name "sound-excitement"
(lambda :behavior process ((excite-fade int))
(let ((state-time (current-time)))
(format 0 "set excitement fade ~D~%" (* 25 excite-fade))
(sound-set-midi-reg 2 (* 25 excite-fade)) ;; fade out old excitement track
(until (>= (- (current-time) state-time) (seconds 0.8))
(suspend))
)
)
old-excitement)
)
)
(cond
((or (cpad-pressed? 0 down l-analog-down)
(and (cpad-hold? 0 down l-analog-down) (>= (- (current-time) (-> obj last-move)) (seconds 0.2))))
(set! (-> obj last-move) (current-time))
(true! scroll-sound?)
(cond
((-> *progress-state-pc* music-player-selected)
(min-max-wrap-around+! (-> obj flava-index) 1 0 flava-max))
(else
(min-max-wrap-around+! (-> obj music-index) 1 0 track-max)
(if (= (-> obj music-index) 0)
(set! (-> obj current-scroll) 0.0)))
))
((or (cpad-pressed? 0 up l-analog-up)
(and (cpad-hold? 0 up l-analog-up) (>= (- (current-time) (-> obj last-move)) (seconds 0.2))))
(set! (-> obj last-move) (current-time))
(true! scroll-sound?)
(cond
((-> *progress-state-pc* music-player-selected)
(min-max-wrap-around+! (-> obj flava-index) -1 0 flava-max))
(else
(min-max-wrap-around+! (-> obj music-index) -1 0 track-max)
(if (= (-> obj music-index) track-max)
(set! (-> obj current-scroll) (-> obj max-scroll))))
))
((cpad-pressed? 0 confirm)
(cpad-clear! 0 confirm)
(sound-play "generic-beep")
(cond
;; track is locked. do nothing.
((not (get-bit (-> *pc-settings* music-unlocked) (-> obj music-index)))
)
;; we have a track with a submenu selected
((-> *progress-state-pc* music-player-selected)
(let ((flava (bit-on-offset (the-as int (-> *music-player-tracks* (-> obj music-index) flava)) (-> obj flava-index))))
(cond
((flava-unlocked? flava)
(set! (-> *progress-state-pc* music-player-flava) flava)
(true! play?)
;; exit submenu
(false! (-> *progress-state-pc* music-player-selected))
)
(else
;; do nothing.
)
)
)
)
;; we have a track with a submenu that's not open, open it
((nonzero? (-> *music-player-tracks* (-> obj music-index) flava))
;; same track that's currently playing, we can just reuse the flava position that's being used
;; otherwise use zero.
(if (= (-> *progress-state-pc* music-player-track) (-> *music-player-tracks* (-> obj music-index)))
(set! (-> obj flava-index) (count-bits (logand (1- (ash 1 (-> *progress-state-pc* music-player-flava))) (the-as int (-> *music-player-tracks* (-> obj music-index) flava)))))
(set! (-> obj flava-index) 0))
(true! (-> *progress-state-pc* music-player-selected)))
;; no submenu required, just play track.
(else
(set! (-> *progress-state-pc* music-player-flava) 0)
(true! play?))
)
(when play?
(play-music-player (-> *music-player-tracks* (-> obj music-index)) (-> *progress-state-pc* music-player-flava))
)
)
((cpad-pressed? 0 triangle)
(cpad-clear! 0 triangle)
(sound-play "generic-beep")
(cond
((-> *progress-state-pc* music-player-selected)
(false! (-> *progress-state-pc* music-player-selected)))
(else
(stop-music-player)
(pop-state arg0))
)
)
)
(when scroll-sound?
(sound-play "roll-over"))
)
0
)
(defun calculate-current-resolution-index ((want-aspect float) (want-w int) (want-h int))
(let ((res-w 0)
(res-h 0)
(res-aspect 0.0)
(res-valid 0))
(dotimes (i (pc-get-num-resolutions))
(pc-get-resolution i (& res-w) (& res-h))
(set! res-aspect (/ (the float res-w) (the float res-h)))
(when (or (= (pc-get-display-mode) 'windowed)
(< (fabs (- want-aspect res-aspect)) 0.05))
(if (and (= res-h want-h) (= res-w want-w))
(return res-valid))
(1+! res-valid))
)
(cond
;; 512x416
((and (= want-w 512) (= want-h 416))
res-valid)
;; 512x208
((and (= want-w 512) (= want-h 208))
(1+ res-valid))
;; nothing found
(else
-1)
))
)
(defglobalconstant DEBUG_RESOLUTION_OPTION #f)
(defmethod respond-progress ((this menu-resolution-option) (arg0 progress) (arg1 symbol))
"Handle progress menu navigation logic."
;; control logic
(let ((scroll-sound? #f)
(resolutions-valid 0)
(resolution-found #f)
(cur-w 0)
(cur-h 0)
(select-w -1)
(select-h -1)
)
(set! (-> this num-resolutions) (pc-get-num-resolutions))
(cond
;; valid state
((> (-> this num-resolutions) 0)
(true! (-> this valid?))
;; this code isnt the greatest...
;; the logic here is that, unlike jak 1, we don't build a list of resolutions and then scroll through that.
;; we calculate the list every frame, keeping track of the index that is highlighted.
;; this allows for infinite resolutions and for it to update live according to monitor changes.
(cond
((fullscreen?)
;; grab current window sizes for aspect ratio purposes (only relevant for fullscreen)
(pc-get-window-size (&-> this win-w) (&-> this win-h))
(set! cur-w (-> *pc-settings* width))
(set! cur-h (-> *pc-settings* height))
(set! (-> this win-aspect) (/ (the float (-> this win-w)) (the float (-> this win-h))))
(#when DEBUG_RESOLUTION_OPTION (format *stdcon* "fullscreen mode~%"))
)
(else
(set! cur-w (-> *pc-settings* window-width))
(set! cur-h (-> *pc-settings* window-height))
(set! (-> this win-aspect) (/ (the float cur-w) (the float cur-h)))
(#when DEBUG_RESOLUTION_OPTION (format *stdcon* "windowed mode~%"))
)
)
;; check if we want to automatically pick something already
(when (= -1 (-> this selected-index))
(set! (-> this selected-index) (calculate-current-resolution-index (-> this win-aspect) cur-w cur-h))
(#when DEBUG_RESOLUTION_OPTION (format #t "recalc index got ~D~%" (-> this selected-index)))
;; update if not invalid?
(cond
((= (-> this selected-index) -1)
(set! (-> this selected-index) 0) ;; give up, just select the first one by default.
)
(else
(set! select-w cur-w)
(set! select-h cur-h)
(true! resolution-found)
(set! (-> this scroll-index) (the float (-> this selected-index)))
)
)
)
;; if we haven't automatically picked a resolution, iterate and find the one highlighted
(when (not resolution-found)
(#when DEBUG_RESOLUTION_OPTION (format *stdcon* "finding resolution ~D~%" (-> this selected-index)))
(dotimes (i (-> this num-resolutions))
;; count "valid" resolutions
(let ((this-w 0) (this-h 0) (this-aspect 0.0))
(pc-get-resolution i (& this-w) (& this-h))
(set! this-aspect (/ (the float this-w) (the float this-h)))
(when (or (= (pc-get-display-mode) 'windowed)
(< (fabs (- (-> this win-aspect) this-aspect)) 0.05))
;; this is the highlighted option - save it
(when (= resolutions-valid (-> this selected-index))
(set! select-w this-w) (set! select-h this-h)
(true! resolution-found)
;;(set! i (-> this num-resolutions)) ;; abandon loop
)
(1+! resolutions-valid)
))
)
)
;; if still didn't find it, it must be one of the hardcoded cases
(cond
(resolution-found
;; yay
)
;; 512x416
((and (fullscreen?) (= resolutions-valid (-> this selected-index)))
(set! select-w 512)
(set! select-h 416)
)
;; 512x208
((and (fullscreen?) (= (1+ resolutions-valid) (-> this selected-index)))
(set! select-w 512)
(set! select-h 208)
)
;; STILL nothing? I don't know how this happens, just don't even try then.
(else
(false! (-> this valid?))
)
)
;; hardcoded cases
(when (fullscreen?)
(+! resolutions-valid 2))
)
;; not sure what happened, but there's not even any resolutions
(else
(false! (-> this valid?))
)
)
(cond
((-> this valid?)
(#when DEBUG_RESOLUTION_OPTION
(format *stdcon* "selected: ~D (~D x ~D)~%" (-> this selected-index) select-w select-h)
(format *stdcon* "current: ~D x ~D~%" cur-w cur-h)
(format *stdcon* "resolution: ~D valid (out of ~D)~%" resolutions-valid (-> this num-resolutions))
)
(cond
;; navigate up
((or (cpad-pressed? 0 up l-analog-up)
(and (cpad-hold? 0 up l-analog-up) (time-elapsed? (-> this last-move) (seconds 0.2))))
(set-time! (-> this last-move))
(true! scroll-sound?)
(min-max-wrap-around+! (-> this selected-index) -1 0 (1- resolutions-valid))
)
;; navigate down
((or (cpad-pressed? 0 down l-analog-down)
(and (cpad-hold? 0 down l-analog-down) (time-elapsed? (-> this last-move) (seconds 0.2))))
(set-time! (-> this last-move))
(true! scroll-sound?)
(min-max-wrap-around+! (-> this selected-index) 1 0 (1- resolutions-valid))
)
;; select
((cpad-pressed? 0 confirm)
(cpad-clear! 0 confirm)
(set-size! *pc-settings* select-w select-h #t)
(pc-settings-save)
(pop-state arg0))
;; exit
((cpad-pressed? 0 triangle)
(cpad-clear! 0 triangle)
(pop-state arg0))
)
)
(else
;; just triangle to exit
(when (cpad-pressed? 0 triangle)
(cpad-clear! 0 triangle)
(pop-state arg0))
)
)
(when scroll-sound?
(sound-play "roll-over"))
)
0
)
(defun hide-progress-screen ()
(when (and *progress-process* *progress-state* (!= (-> *progress-state* starting-state) 'title))
(stop-music-player)
(set-next-state (-> *progress-process* 0) 'go-away 0)
(clear-history! *progress-pc-generic-store*)
)
0
(none)
)
;; NOTE - this technically includes the gold/silver/bronze times
;; maybe figure out how to omit them eventually, (not sure if there is anything that differentiates them)
;; From a highscores perspective it doesn't really matter, the default scores are awful
(define-extern get-highscore-score (function int int))
(defun progress-pc-get-num-nonzero-local-scores ((highscore-index int))
(let ((count 0)
(score-ptr (get-game-score-ref *game-info* (get-highscore-score highscore-index))))
(dotimes (idx 8)
(when (> (-> score-ptr idx) 0)
(inc! count)))
count))
(defun progress-pc-max-external-scores ((highscore-index int))
(case highscore-index
((0) (pc-get-num-external-highscores "scatter"))
((1) (pc-get-num-external-highscores "blaster"))
((2) (pc-get-num-external-highscores "vulcan"))
((3) (pc-get-num-external-highscores "peacemaker"))
((4) (pc-get-num-external-highscores "jetboard"))
((5) (pc-get-num-external-race-times "class3"))
((6) (pc-get-num-external-race-times "class2"))
((7) (pc-get-num-external-race-times "class1"))
((8) (pc-get-num-external-race-times "port"))
((9) (pc-get-num-external-race-times "erol"))
((10) (pc-get-num-external-race-times "class3rev"))
((11) (pc-get-num-external-race-times "class2rev"))
((12) (pc-get-num-external-race-times "class1rev"))
((13) (pc-get-num-external-highscores "onin"))
((14) (pc-get-num-external-highscores "mash"))))
(defun progress-pc-max-highscore-rows ((highscore-index int))
(case highscore-index
((0) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-highscores "scatter")))
((1) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-highscores "blaster")))
((2) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-highscores "vulcan")))
((3) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-highscores "peacemaker")))
((4) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-highscores "jetboard")))
((5) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-race-times "class3")))
((6) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-race-times "class2")))
((7) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-race-times "class1")))
((8) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-race-times "port")))
((9) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-race-times "erol")))
((10) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-race-times "class3rev")))
((11) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-race-times "class2rev")))
((12) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-race-times "class1rev")))
((13) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-highscores "onin")))
((14) (+ (progress-pc-get-num-nonzero-local-scores highscore-index) (pc-get-num-external-highscores "mash")))
((15) (pc-get-num-external-speedrun-times "any"))
((16) (pc-get-num-external-speedrun-times "anyhoverless"))
((17) (pc-get-num-external-speedrun-times "allmissions"))
((18) (pc-get-num-external-speedrun-times "100"))
((19) (pc-get-num-external-speedrun-times "anyorbs"))
((20) (pc-get-num-external-speedrun-times "anyhero"))
(else 8)))
(defmethod respond-progress menu-highscores-option ((this menu-highscores-option) (progress progress) (selected? symbol))
"Handle progress menu navigation logic."
(set! (-> progress sliding) (seek-ease (-> progress sliding) 0.0 (* 0.1 (-> self clock time-adjust-ratio)) 0.3 (* 0.001 (-> self clock time-adjust-ratio))))
(set! (-> progress sliding-off) (seek-ease (-> progress sliding-off) 1.0 (* 0.1 (-> self clock time-adjust-ratio)) -0.3 (* 0.001 (-> self clock time-adjust-ratio))))
(when (and (!= *pc-waiting-on-rpc?* #t) (-> *bigmap* progress-minimap))
(let ((play-sound? #f))
(cond
((or (cpad-pressed? 0 right l-analog-right)
(and (cpad-hold? 0 right l-analog-right) (>= (- (current-time) (-> this last-move)) (seconds 0.2))))
(when (< 1 (get-num-highscores))
(set! (-> this last-move) (current-time))
(set! play-sound? #t)
(set! (-> this prev-page-index) (-> this page-index))
(set! (-> this page-index) (get-next-highscore (-> this page-index)))
;; ensure external data is fetched if applicable
(progress-pc-fetch-external-times (-> this page-index))
(set! (-> *progress-pc-generic-store* current-highscore-page-index) 0)
(set! (-> progress sliding) 1.0)
(set! (-> progress sliding-off) 0.0)
(set! (-> this slide-dir) -1.0)))
((or (cpad-pressed? 0 left l-analog-left)
(and (cpad-hold? 0 left l-analog-left) (>= (- (current-time) (-> this last-move)) (seconds 0.2))))
(when (< 1 (get-num-highscores))
(set! (-> this last-move) (current-time))
(set! (-> this prev-page-index) (-> this page-index))
(set! (-> this page-index) (get-prev-highscore (-> this page-index)))
;; ensure external data is fetched if applicable
(progress-pc-fetch-external-times (-> this page-index))
(set! (-> *progress-pc-generic-store* current-highscore-page-index) 0)
(set! play-sound? #t)
(set! (-> progress sliding) -1.0)
(set! (-> progress sliding-off) 0.0)
(set! (-> this slide-dir) 1.0)))
((or (cpad-pressed? 0 down l-analog-down)
(and (cpad-hold? 0 down l-analog-down) (>= (- (current-time) (-> this last-move)) (seconds 0.2))))
(when (and (-> *pc-settings* speedrunner-mode?)
(< (* (inc (-> *progress-pc-generic-store* current-highscore-page-index)) 8) (progress-pc-max-highscore-rows (-> this page-index))))
(set! (-> this last-move) (current-time))
(sound-play "secrets-scroll")
(inc! (-> *progress-pc-generic-store* current-highscore-page-index))))
((or (cpad-pressed? 0 up l-analog-up)
(and (cpad-hold? 0 up l-analog-up) (>= (- (current-time) (-> this last-move)) (seconds 0.2))))
(when (and (-> *pc-settings* speedrunner-mode?)
(> (-> *progress-pc-generic-store* current-highscore-page-index) 0))
(set! (-> this last-move) (current-time))
(sound-play "secrets-scroll")
(dec! (-> *progress-pc-generic-store* current-highscore-page-index))))
((cpad-pressed? 0 triangle confirm)
(set! (-> *progress-pc-generic-store* current-highscore-page-index) 0)
(logclear! (-> *cpad-list* cpads 0 button0-abs 0) (pad-buttons triangle confirm))
(logclear! (-> *cpad-list* cpads 0 button0-rel 0) (pad-buttons triangle confirm))
(set! (-> progress sliding) 0.0)
(set! (-> progress sliding-off) 1.0)
(if (!= (-> *progress-state* starting-state) 'title)
(sound-play "window-contract")
(sound-play "generic-beep"))
(pop-state progress)))
(when play-sound?
(sound-play "score-slide"))))
0)
(defmethod respond-progress ((this menu-sub-menu-option) (arg0 progress) (arg1 symbol))
"Handle progress menu navigation logic."
(when (and (-> *progress-state* secrets-unlocked)
(not (memcard-unlocked-secrets? #f))
(or (= (-> arg0 current-options) *title-pc*)
(= (-> arg0 current-options) *unlocked-secrets*)
(= (-> arg0 current-options) *select-scene-options*)
(= (-> arg0 current-options) *select-start-options*)
(= (-> arg0 current-options) *save-options-title*)
)
)
(set! (-> *progress-state* secrets-unlocked) #f)
(set! (-> arg0 state-pos) 0)
(set-next-state arg0 'secrets-insufficient-space 0)
)
(when (= (-> this name) (text-id progress-continue-without-saving))
(let ((a1-3 (get-state-check-card arg0 (-> arg0 current))))
(set-next-state arg0 a1-3 0)
)
)
(when (and (= (-> this name) (text-id progress-root-secrets))
(= *title-pc* (-> arg0 current-options))
(not (memcard-unlocked-secrets? #f))
(= (-> arg0 option-index) 4)
)
(set! (-> arg0 option-index) 0)
0
)
(when (cpad-pressed? 0 confirm)
(cpad-clear! 0 confirm)
(cond
((= (-> this name) (text-id progress-demo-exit))
(case *kernel-boot-message*
(('demo-shared)
(set! *master-exit* 'force)
(set-master-mode 'game)
)
(('demo)
(set! (-> *game-info* mode) 'play)
(initialize! *game-info* 'game (the-as game-save #f) "demo-restart")
)
)
)
((= (-> this name) (text-id progress-continue-without-saving))
(progress-intro-start (logtest? (-> *game-info* purchase-secrets) (game-secrets hero-mode)))
)
((= (-> this next-state) 'back)
(pop-state arg0)
)
(else
(sound-play "generic-beep")
(push-state arg0)
(set-next-state arg0 (-> this next-state) 0)
)
)
)
0
)
(defmethod respond-progress ((this menu-secret-option) (arg0 progress) (arg1 symbol))
"Handle progress menu navigation logic."
(let* ((hero? (logtest? (-> *game-info* secrets) (game-secrets hero-mode)))
(min-item (if (not hero?)
0
(-> this num-items)
)
)
(max-item (if (not hero?)
(+ (-> this num-items) -1)
(+ (-> this num-items) -1 (-> this num-hero-items))
)
)
(num-pc-items (-> *pc-cheats-list* length)))
(seek-ease! (-> arg0 sliding) 0.0 (* 0.1 (-> self clock time-adjust-ratio)) 0.3 (* 0.001 (-> self clock time-adjust-ratio)))
(cond
((and hero? (< (-> this item-index) min-item))
(set! (-> this item-index) min-item)
(set! (-> this prev-item-index) min-item)
)
((and (not hero?) (< (+ max-item num-pc-items) (-> this item-index)))
(set! (-> this item-index) min-item)
(set! (-> this prev-item-index) min-item)
)
)
(menu-update-purchase-secrets this)
(when (-> *bigmap* progress-minimap)
(let ((scroll-sound? #f))
(cond
((= arg1 #t)
(when (cpad-pressed? 0 confirm)
(cpad-clear! 0 confirm)
(sound-play "generic-beep")
(set! (-> arg0 selected-option) #f)
)
)
(else
(cond
((or (cpad-pressed? 0 down l-analog-down)
(and (cpad-hold? 0 down l-analog-down) (time-elapsed? (-> this last-move) (seconds 0.2)))
)
(set-time! (-> this last-move))
(when (< (-> this item-index) (+ max-item num-pc-items))
(set! (-> this prev-item-index) (-> this item-index))
(set! scroll-sound? #t)
(+! (-> this item-index) 1)
(set! (-> arg0 sliding) 1.0)
(set! (-> arg0 sliding-off) 0.0)
)
)
((or (cpad-pressed? 0 up l-analog-up)
(and (cpad-hold? 0 up l-analog-up) (time-elapsed? (-> this last-move) (seconds 0.2)))
)
(set-time! (-> this last-move))
(when (< min-item (-> this item-index))
(set! (-> this prev-item-index) (-> this item-index))
(+! (-> this item-index) -1)
(set! scroll-sound? #t)
(set! (-> arg0 sliding) -1.0)
(set! (-> arg0 sliding-off) 0.0)
)
)
((cpad-pressed? 0 confirm)
(cpad-clear! 0 confirm)
(cond
((<= (-> this item-index) max-item)
(let* ((item (-> this item-index))
(cost (-> this secret-items item cost))
(flag (-> this secret-items item flag))
(on-off? (= (-> this secret-items item can-toggle) #t))
(avail-after (-> this secret-items item avail-after))
(skill (the int (-> *game-info* skill))))
(cond
((and (logtest? (-> *game-info* purchase-secrets) flag) on-off?)
(set! (-> arg0 selected-option) #t)
(sound-play "generic-beep")
)
((= (-> this secret-items item can-toggle) 'auto)
)
((logtest? (-> *game-info* purchase-secrets) flag)
(set! (-> arg0 selected-option) #t)
(sound-play "generic-beep")
)
)
)
)
(else
(let* ((cheat (-> *pc-cheats-list* (- (-> this item-index) max-item 1))))
(cond
((or (not (logtest? (-> *pc-settings* cheats-revealed) (-> cheat flag))) (not (logtest? (-> *pc-settings* cheats-purchased) (-> cheat flag))))
;; unknown cheat or not enough money. GET MORE!!
;; nothing happens
)
((not (logtest? (-> *pc-settings* cheats-unlocked) (-> cheat flag)))
;; known cheat, enough money, but LOCKED!
(set! (-> arg0 selected-option) #t)
(sound-play "generic-beep")
)
((= (-> cheat can-toggle) #t)
;; known cheat, unlocked, toggleable
(logxor! (-> *pc-settings* cheats) (-> cheat flag))
(sound-play "generic-beep")
)
((= (-> cheat can-toggle) 'auto)
)
(else
;; known cheat and unlocked! does something else automatically i guess
(set! (-> arg0 selected-option) #t)
(sound-play "generic-beep")
)
)
)
)
)
)
((cpad-pressed? 0 triangle)
(cpad-clear! 0 triangle)
(if (!= (-> *progress-state* starting-state) 'title)
(sound-play "window-contract")
(sound-play "generic-beep")
)
(pop-state arg0)
)
)
(if scroll-sound?
(sound-play "secrets-scroll")
)
)
)
)
)
)
(cpad-clear! 0 confirm)
0
)
(defmethod respond-progress ((this menu-exit-game-option) (arg0 progress) (selected? symbol))
"Handle progress menu navigation logic."
(let ((choice (&-> *progress-state* yes-no-choice))
(gp-0 #f)
)
(when selected?
(cond
((cpad-pressed? 0 left l-analog-left)
(when (not (-> choice 0))
(set! gp-0 #t)
(set! (-> choice 0) #t)
)
)
((cpad-pressed? 0 right l-analog-right)
(set! gp-0 (-> choice 0))
(set! (-> choice 0) #f)
)
((cpad-pressed? 0 confirm)
(if (-> choice 0)
(kernel-shutdown (runtime-exit-status exit))
)
)
)
)
(if gp-0
(sound-play "generic-beep")
)
)
0
)