;;-*-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) (-> *pc-settings* memcard-vibration?)) (set! (-> *progress-state* game-options-subtitles) (-> *pc-settings* memcard-subtitles?)) (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) (&-> *pc-settings* memcard-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) (&-> *pc-settings* memcard-vibration?) ) (set! (-> (the-as menu-on-off-option (-> *game-options-demo* options 0)) value-to-modify) (&-> *pc-settings* memcard-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) ;; (&-> *pc-settings* memcard-volume-sfx) ;; ) ;; (set! (-> (the-as menu-slider-option (-> *sound-options* options 1)) value-to-modify) ;; (&-> *pc-settings* memcard-volume-music) ;; ) ;; (set! (-> (the-as menu-slider-option (-> *sound-options* options 2)) value-to-modify) ;; (&-> *pc-settings* memcard-volume-dialog) ;; ) (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-pc*) ) (('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-window-size! *pc-settings* select-w select-h) (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 )