jak-project/goal_src/pc/pckernel.gc
Tyler Wilding 014da6f59d
game: auto-save pc-settings to user's home directory as well as memcard files (#1233)
* cmake: reduce warning spam especially from libs

* runtime: add FS helper functions

* game: save/restore pc-settings | add original aspect option

* game: overwrite unloadable settings with defaults

* temp: unable to set the games aspect-ratio in the boot else crash?

* runtime: save memcard files to user directory as well

* runtime: fix `pckernel` load order which resolves setting the orig aspect ratio

* lint: format

* cmake: revert warning suppression, it's just causing problems it seems

* fix the order of the rest of `pckernel` and creation of obj file paths

* lint: formatting

* game: don't save settings on startup even if they are corrupted
2022-03-20 20:29:44 -04:00

908 lines
35 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
#|
This file contains code that we need for the PC port of the game specifically.
It should be included as part of the game engine package (engine.cgo).
This file contains various types and functions to store PC-specific information
and also to communicate between the game (GOAL) and the operating system.
This way we can poll, change and display information about the system the game
is running on, such as:
- display devices and their settings, such as fullscreen, DPI, refresh rate, etc.
- audio devices and their settings, such as audio latency, channel number, etc.
- graphics devices and their settings, such as resolution, FPS, anisotropy, shaders, etc.
- input devices and their settings, such as controllers, keyboards, mice, etc.
- information about the game window (position, size)
- PC-specific goodies, enhancements, fixes and settings.
- whatever else.
If you do not want to include these PC things, you should exclude it from the build system.
|#
(#when PC_PORT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; updates
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmethod set-display-mode! pc-settings ((obj pc-settings) (mode symbol))
"sets the game's display mode"
;; changing to same mode, no-op
(if (= (-> obj display-mode) mode)
(return 0))
;; else change it and update it
(set! (-> obj display-mode) mode)
(cond
((= mode 'borderless)
(pc-set-fullscreen 2 0))
((= mode 'fullscreen)
(pc-set-fullscreen 1 0))
(else ;; default to windowed
(pc-set-fullscreen 0 0)))
(none))
(defmethod set-size! pc-settings ((obj pc-settings) (width int) (height int))
"sets the size of the display window"
(pc-set-window-size width height)
(none))
(defmethod set-aspect! pc-settings ((obj pc-settings) (aw int) (ah int))
"set the aspect ratio used for rendering. this forces native widescreen and takes width and height ratios."
(let ((aspect (/ (the float aw) (the float ah))))
(set-aspect-ratio! obj aspect)
(set! (-> obj aspect-ratio-auto?) #f)
(set! (-> obj use-vis?) #f)
)
(none))
(defmethod use-orig-aspect-ratio! pc-settings ((obj pc-settings) (val symbol))
"whether to use the pc port's aspect ratio, or the original games 4:3/16:9"
(if (= (-> obj use-original-aspect-ratio?) val)
(return 0))
(set! (-> obj use-original-aspect-ratio?) val)
;; default to the simplist resolution if we are changing
(if val
(set-aspect-ratio-mode! obj 'orig-aspect-4x3)
(set-aspect-ratio-mode! obj 'pc-aspect-4x3))
(set! (-> *pc-settings* use-vis?) val)
(none))
(defmethod set-aspect-ratio! pc-settings ((obj pc-settings) (aspect float))
"set the aspect ratio used for rendering."
(set! (-> obj aspect-ratio) aspect)
(set! (-> obj aspect-ratio-scale) (/ aspect ASPECT_4X3))
(set! (-> obj aspect-ratio-reciprocal) (/ ASPECT_4X3 aspect))
(none))
(defmethod set-aspect-ratio-mode! pc-settings ((obj pc-settings) (mode symbol))
"sets the game's aspect ratio mode"
;; changing to same mode, no-op
(if (= (-> obj aspect-ratio-mode) mode)
(return 0))
;; else change it and update it
(set! (-> obj aspect-ratio-mode) mode)
;; also default to the lowest resolution option at the same time
(case mode
(('orig-aspect-4x3)
(set-resolution! obj (-> *pc-graphics-4x3-valid-resolutions* 0)))
(('orig-aspect-16x9)
(set-resolution! obj (-> *pc-graphics-16x9-valid-resolutions* 0)))
(('pc-aspect-4x3)
(set-aspect! obj 4 3)
(set-resolution! obj (-> *pc-graphics-4x3-valid-resolutions* 0)))
(('pc-aspect-5x4)
(set-aspect! obj 5 4)
(set-resolution! obj (-> *pc-graphics-5x4-valid-resolutions* 0)))
(('pc-aspect-16x9)
(set-aspect! obj 16 9)
(set-resolution! obj (-> *pc-graphics-16x9-valid-resolutions* 0)))
(('pc-aspect-21x9)
(set-aspect! obj 21 9)
(set-resolution! obj (-> *pc-graphics-21x9-valid-resolutions* 0)))
(('pc-aspect-32x9)
(set-aspect! obj 32 9)
(set-resolution! obj (-> *pc-graphics-32x9-valid-resolutions* 0))))
;; NOTE - i believe this is a temporary workaround to get the hud looking decent on pc aspect ratios
;; eventually i assume this will only be required for the original ones!
(case mode
(('orig-aspect-4x3 'pc-aspect-4x3)
(set! (-> *setting-control* default aspect-ratio) 'aspect4x3))
(else
(set! (-> *setting-control* default aspect-ratio) 'aspect16x9)))
;; NOTE - it should not be necessarily to call `set-aspect-ratio` as that is
;; done on a per frame basis as long as it differs from the "current" setting-control value
;;
;; However, if I'm wrong, then that needs to be fixed at the build/load level again
;; as that function is defined in `video` later in the order.
(none))
(defmethod set-resolution! pc-settings ((obj pc-settings) (mode symbol))
"sets the game's resolution"
;; TODO - implement a custom resolution mode which will enable resizing and use the values stored
;; changing to same mode, no-op
(if (= (-> obj resolution) mode)
(none))
;; else change it and update it
(set! (-> obj resolution) mode)
(case mode
(('640x480) (set-size! obj 640 480))
(('800x600) (set-size! obj 800 600))
(('1024x768) (set-size! obj 1024 768))
(('1280x960) (set-size! obj 1280 960))
(('1600x1200) (set-size! obj 1600 1200))
(('960x768) (set-size! obj 960 768))
(('1280x1024) (set-size! obj 1280 1024))
(('1500x1200) (set-size! obj 1500 1200))
(('854x480) (set-size! obj 854 480))
(('1280x720) (set-size! obj 1280 720))
(('1920x1080) (set-size! obj 1920 1080))
(('2560x1440) (set-size! obj 2560 1440))
(('2880x1620) (set-size! obj 2880 1620))
(('3840x2160) (set-size! obj 3840 2160))
(('5120x2880) (set-size! obj 5120 2880))
(('2560x1080) (set-size! obj 2560 1080))
(('3120x1440) (set-size! obj 3120 1440))
(('3200x1440) (set-size! obj 3200 1440))
(('3440x1440) (set-size! obj 3440 1440))
(('3840x1600) (set-size! obj 3840 1600))
(('5120x2160) (set-size! obj 5120 2160))
(('5120x1440) (set-size! obj 5120 1440)))
(none))
(defmethod commit-to-file pc-settings ((obj pc-settings))
"commits the current settings to the file"
;; auto load settings if available
(clear *pc-temp-string-1*)
(format *pc-temp-string-1* "~S/pc-settings.gc" *pc-settings-folder*)
(pc-mkdir-file-path *pc-temp-string-1*)
(write-to-file obj *pc-temp-string-1*)
(clear *pc-temp-string-1*)
(none))
(defmethod update-from-os pc-settings ((obj pc-settings))
"Update settings from the PC kernel to GOAL."
(set! (-> obj os) (pc-get-os))
(pc-get-window-size (&-> obj win-width) (&-> obj win-height))
(pc-get-window-scale (&-> obj dpi-x) (&-> obj dpi-y))
(when (-> obj use-vis?)
(if (= (-> *setting-control* default aspect-ratio) 'aspect4x3)
(set-aspect-ratio! obj ASPECT_4X3)
(set-aspect-ratio! obj ASPECT_16X9)
)
)
(let ((win-aspect (/ (the float (-> obj win-width)) (the float (-> obj win-height)))))
(cond
((and (not (-> obj use-vis?)) (-> obj aspect-ratio-auto?))
;; the window determines the resolution
(set-aspect-ratio! obj win-aspect)
(set! (-> obj width) (-> obj win-width))
(set! (-> obj height) (-> obj win-height))
)
((> win-aspect (-> obj aspect-ratio))
;; too wide
(set! (-> obj width) (the int (* (the float (-> obj win-height)) (-> obj aspect-ratio))))
(set! (-> obj height) (-> obj win-height))
)
((< win-aspect (-> obj aspect-ratio))
;; too tall
(set! (-> obj width) (-> obj win-width))
(set! (-> obj height) (the int (/ (the float (-> obj win-width)) (-> obj aspect-ratio))))
)
(else
;; just right
(set! (-> obj width) (-> obj win-width))
(set! (-> obj height) (-> obj win-height))
)
)
)
(none))
(defmethod update-to-os pc-settings ((obj pc-settings))
"Update settings from GOAL to the PC kernel."
(cond
((-> obj letterbox?)
(pc-set-letterbox (-> obj width) (-> obj height))
)
(else
(pc-set-letterbox (-> obj win-width) (-> obj win-height))
)
)
(cond
((-> obj discord-rpc?)
(pc-discord-rpc-set 1)
)
(else
(pc-discord-rpc-set 0)
)
)
(when #t ;; (not (-> obj ps2-lod-dist?))
(pc-renderer-tree-set-lod (pc-renderer-tree-type tfrag3) (-> obj lod-force-tfrag))
(pc-renderer-tree-set-lod (pc-renderer-tree-type tie3) (-> obj lod-force-tie))
)
;; TODO - save changes
(none))
(define *pc-cheat-temp* (the-as (pointer int32) (malloc 'global 24)))
(defmacro pc-cheat-toggle-and-tune (obj cheat)
`(begin
(cpad-clear-buttons! 0 r1)
(logxor! (-> ,obj cheats) (pc-cheats ,cheat))
(cheats-sound-play (logtest? (-> ,obj cheats) (pc-cheats ,cheat)))
)
)
(defmethod update pc-settings ((obj pc-settings))
"Update settings to/from PC kernel. Call this at the start of every frame.
This will update things like the aspect-ratio, which will be used for graphics code later."
(update-from-os obj)
(update-to-os obj)
(set! (-> obj movie?) (movie?))
(let ((info (new 'stack 'discord-info)))
(set! (-> info fuel) (&-> *game-info* fuel))
(set! (-> info money-total) (&-> *game-info* money-total))
(set! (-> info buzzer-total) (&-> *game-info* buzzer-total))
(set! (-> info status) "Playing Jak and Daxter: TPL")
(set! (-> info level) (if *target*
(symbol->string (-> *target* current-level name)) ;; use target's level if it exists
(symbol->string (-> (level-get-target-inside *level*) name)) ;; use camera's level otherwise
)
)
(set! (-> info cutscene?) (movie?))
(pc-discord-rpc-update info)
)
(when (not (-> obj use-vis?))
(set! (-> *video-parms* relative-x-scale) (-> obj aspect-ratio-reciprocal))
(set! (-> *video-parms* relative-x-scale-reciprical) (-> obj aspect-ratio-scale))
(set! (-> *font-default-matrix* vector 0 x) (-> *video-parms* relative-x-scale))
)
(when (not (-> obj use-vis?))
(set-hud-aspect-ratio 'aspect4x3 'ntsc) ;; set hud aspect ratios every frame because why not?
(when *progress-process*
;; adjust sizes for progress.
;; video.gc sets the sizes in the normal game.
(let ((pr (-> *progress-process*))
(wide-adjust (* 4.0 (- (/ (-> obj aspect-ratio-scale) ASPECT_16X9_SCALE) (1/ ASPECT_16X9_SCALE))))
)
(set! (-> pr sides-x-scale) 1.0)
(set! (-> pr sides-y-scale) 13.0)
;(set! (-> pr left-x-offset) (+ 59 (the int (* (-> obj aspect-ratio-scale) -59))))
;(set! (-> pr right-x-offset) 26)
;(set! (-> pr button-scale) (+ 1.0 (* wide-adjust 0.1)))
)
)
)
(cond
((actor-force-visible? obj)
(set! (-> *ACTOR-bank* birth-dist) (meters 10000))
(set! (-> *ACTOR-bank* pause-dist) (meters 10000))
(set! (-> *ACTOR-bank* birth-max) 1000)
)
((> (-> *ACTOR-bank* birth-dist) (meters 220))
(set! (-> *ACTOR-bank* birth-dist) (meters 220))
(set! (-> *ACTOR-bank* pause-dist) (meters 220))
))
;; cheats.
(update-cheats obj)
(none))
(defmethod update-cheats pc-settings ((obj pc-settings))
"run cheats."
(when (and (cpad-hold? 0 l2) (cpad-hold? 0 l1) (cpad-hold? 0 r2) (cpad-hold? 0 r1))
(pc-check-cheat-code (-> *pc-cheat-temp* 0) 0 (s p i r i t) :extra (x)
(logclear! (-> obj cheats) (pc-cheats eco-red eco-yellow eco-green))
(pc-cheat-toggle-and-tune obj eco-blue))
(pc-check-cheat-code (-> *pc-cheat-temp* 1) 0 (s p i r i t) :extra (circle)
(logclear! (-> obj cheats) (pc-cheats eco-blue eco-yellow eco-green))
(pc-cheat-toggle-and-tune obj eco-red))
(pc-check-cheat-code (-> *pc-cheat-temp* 2) 0 (s p i r i t) :extra (triangle)
(logclear! (-> obj cheats) (pc-cheats eco-red eco-yellow eco-blue))
(pc-cheat-toggle-and-tune obj eco-green))
(pc-check-cheat-code (-> *pc-cheat-temp* 3) 0 (s p i r i t) :extra (square)
(logclear! (-> obj cheats) (pc-cheats eco-red eco-blue eco-green))
(pc-cheat-toggle-and-tune obj eco-yellow))
(pc-check-cheat-code (-> *pc-cheat-temp* 4) 0 (s t e e l)
(logclear! (-> *target* state-flags) 16)
(pc-cheat-toggle-and-tune obj invinc))
(pc-check-cheat-code (-> *pc-cheat-temp* 5) 0 (l e a d s)
(pc-cheat-toggle-and-tune obj sidekick-blue))
)
(when *target*
(when (and (pc-cheats? obj eco-blue)
(or (= (-> *target* fact-info-target eco-type) (pickup-type eco-blue))
(<= (-> *target* fact-info-target eco-level) 0.0)))
(send-event *target* 'get-pickup (pickup-type eco-blue) (-> *FACT-bank* eco-full-inc)))
(when (and (pc-cheats? obj eco-yellow)
(or (= (-> *target* fact-info-target eco-type) (pickup-type eco-yellow))
(<= (-> *target* fact-info-target eco-level) 0.0)))
(send-event *target* 'get-pickup (pickup-type eco-yellow) (-> *FACT-bank* eco-full-inc)))
(when (and (pc-cheats? obj eco-red)
(or (= (-> *target* fact-info-target eco-type) (pickup-type eco-red))
(<= (-> *target* fact-info-target eco-level) 0.0)))
(send-event *target* 'get-pickup (pickup-type eco-red) (-> *FACT-bank* eco-full-inc)))
(when (and (pc-cheats? obj eco-green)
(or (= (-> *target* fact-info-target eco-type) (pickup-type eco-green))
(<= (-> *target* fact-info-target eco-level) 0.0)))
(with-pp
(define-extern vent type)
(protect ((-> (the basic pp) type) (-> *target* control root-prim prim-core action))
(set! (-> (the basic pp) type) vent)
(logior! (-> *target* control root-prim prim-core action) #x200)
(send-event *target* 'get-pickup (pickup-type eco-green) (-> *FACT-bank* eco-full-inc)))
))
(when (pc-cheats? obj invinc)
(logior! (-> *target* state-flags) 16)
)
)
0)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(when *debug-segment*
(defmethod draw pc-settings ((obj pc-settings) (buf dma-buffer))
"debug draw"
(clear *pc-temp-string*)
(format *pc-temp-string* "game resolution: ~D x ~D~%" (-> obj width) (-> obj height))
(format *pc-temp-string* "window size: ~D x ~D (~,,1f x ~,,1f)~%" (-> obj win-width) (-> obj win-height) (-> obj dpi-x) (-> obj dpi-y))
(format *pc-temp-string* "target aspect: ~,,3f/~,,3f A: ~A/~A L: ~A~%" (-> obj aspect-ratio) (/ (the float (-> obj win-width)) (the float (-> obj win-height))) (-> obj aspect-ratio-auto?) (-> obj use-vis?) (-> obj letterbox?))
(format *pc-temp-string* "display-type: ~A ~A~%" (-> obj display-mode) (-> obj vsync?))
(draw-string-xy *pc-temp-string* buf 0 (- 224 (* 8 4)) (font-color default) (font-flags shadow kerning))
(none))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; file IO
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro file-stream-seek-until (fs func-name)
`(let ((done? #f)
(tell -1))
(until done?
(let ((read (file-stream-read ,fs (-> *pc-temp-string* data) PC_TEMP_STRING_LEN)))
(cond
((zero? read)
(set! (-> *pc-temp-string* data read) 0)
(true! done?)
)
(else
(dotimes (i read)
(when (,func-name (-> *pc-temp-string* data i))
(true! done?)
(set! tell (+ i (- (file-stream-tell ,fs) read)))
(set! i read)
)
)
)
)
)
)
(if (!= tell -1)
(file-stream-seek ,fs tell SCE_SEEK_SET)
tell
)
)
)
(defmacro file-stream-read-until (fs func-name)
`(let ((read (file-stream-read ,fs (-> *pc-temp-string* data) PC_TEMP_STRING_LEN)))
(dotimes (i read)
(when (,func-name (-> *pc-temp-string* data i))
(set! (-> *pc-temp-string* data i) 0)
(file-stream-seek ,fs (+ i (- (file-stream-tell ,fs) read)) SCE_SEEK_SET)
(set! i read)
)
)
*pc-temp-string*
)
)
(defmacro is-whitespace-or-bracket? (c)
`(or (is-whitespace-char? ,c) (= #x28 ,c) (= #x29 ,c))
)
(defun file-stream-seek-past-whitespace ((file file-stream))
(file-stream-seek-until file not-whitespace-char?)
)
(defun file-stream-read-word ((file file-stream))
(file-stream-read-until file is-whitespace-or-bracket?)
;(format 0 "word ~A~%" *pc-temp-string*)
)
(defmacro file-stream-getc (fs)
`(let ((buf 255))
(file-stream-read ,fs (& buf) 1)
;(format 0 "getc got #x~X~%" buf)
buf
)
)
(defun file-stream-read-int ((file file-stream))
(file-stream-seek-past-whitespace file)
(file-stream-read-word file)
(string->int *pc-temp-string*)
)
(defun file-stream-read-float ((file file-stream))
(file-stream-seek-past-whitespace file)
(file-stream-read-word file)
(string->float *pc-temp-string*)
)
(defun file-stream-read-symbol ((file file-stream))
(file-stream-seek-past-whitespace file)
(file-stream-read-word file)
(string->symbol *pc-temp-string*)
)
(defmacro pc-settings-read-throw-error (fs msg)
"not an actual throw..."
`(begin
(format 0 "pc settings read error: ~S~%" ,msg)
(file-stream-close ,fs)
(return #f)
)
)
(defmacro with-settings-scope (bindings &rest body)
(let ((fs (first bindings)))
`(begin
(file-stream-seek-past-whitespace ,fs)
(when (!= #x28 (file-stream-getc ,fs))
(pc-settings-read-throw-error ,fs "invalid char, ( not found")
)
,@body
(file-stream-seek-past-whitespace ,fs)
(when (!= #x29 (file-stream-getc ,fs))
(pc-settings-read-throw-error ,fs "invalid char, ) not found")
)
)
)
)
(defmacro dosettings (bindings &rest body)
"iterate over a list of key-value pairs like so: (<key> <value>) (<key> <value>) ...
the name of key is stored in *pc-temp-string*"
(let ((fs (first bindings)))
`(let ((c -1))
(while (begin (file-stream-seek-past-whitespace ,fs) (set! c (file-stream-getc ,fs)) (= #x28 c))
(file-stream-read-word ,fs)
,@body
(file-stream-seek-past-whitespace ,fs)
(set! c (file-stream-getc ,fs))
(when (!= #x29 c)
(pc-settings-read-throw-error ,fs (string-format "invalid char, ) not found, got #x~X ~A" c *pc-temp-string*))
)
)
(file-stream-seek ,fs -1 SCE_SEEK_CUR)
)
)
)
(defmethod read-from-file pc-settings ((obj pc-settings) (filename string))
"read settings from a file"
(if (not filename)
(return #f))
(let ((file (new 'stack 'file-stream filename 'read)))
(when (not (file-stream-valid? file))
(return #f))
(let ((version PC_KERNEL_VERSION))
(with-settings-scope (file)
(file-stream-read-word file)
(case-str *pc-temp-string*
(("settings")
(set! version (file-stream-read-int file))
(dosettings (file)
(case-str *pc-temp-string*
(("fps") (set! (-> obj target-fps) (file-stream-read-int file)))
(("size")
(set! (-> obj width) (file-stream-read-int file))
(set! (-> obj height) (file-stream-read-int file))
(set-size! obj (-> obj width) (-> obj height))
(set-aspect! obj (-> obj width) (-> obj height))
)
(("use-original-aspect-ratio?")
(set! (-> obj use-original-aspect-ratio?) (file-stream-read-symbol file)))
(("aspect")
(set! (-> obj aspect-custom-x) (file-stream-read-int file))
(set! (-> obj aspect-custom-y) (file-stream-read-int file))
)
(("aspect-auto") (set! (-> obj aspect-ratio-auto?) (file-stream-read-symbol file)))
(("display-mode") (set-display-mode! obj (file-stream-read-symbol file)))
(("aspect-ratio-mode") (set-aspect-ratio-mode! obj (file-stream-read-symbol file)))
(("resolution") (set-resolution! obj (file-stream-read-symbol file)))
(("letterbox") (set! (-> obj letterbox?) (file-stream-read-symbol file)))
(("vsync") (set! (-> obj vsync?) (file-stream-read-symbol file)))
(("font-scale") (set! (-> obj font-scale) (file-stream-read-float file)))
(("audio-latency-ms") (set! (-> obj audio-latency-ms) (file-stream-read-int file)))
(("audio-pan-override") (set! (-> obj audio-pan-override) (file-stream-read-float file)))
(("audio-volume-override") (set! (-> obj audio-volume-override) (file-stream-read-float file)))
(("audio-channel-nb") (set! (-> obj audio-channel-nb) (file-stream-read-int file)))
(("gfx-renderer") (set! (-> obj gfx-renderer) (the-as pc-gfx-renderer (file-stream-read-int file))))
(("gfx-resolution") (set! (-> obj gfx-resolution) (file-stream-read-float file)))
(("gfx-anisotropy") (set! (-> obj gfx-anisotropy) (file-stream-read-float file)))
(("shrub-dist-mod") (set! (-> obj shrub-dist-mod) (file-stream-read-float file)))
(("lod-dist-mod") (set! (-> obj lod-dist-mod) (file-stream-read-float file)))
(("lod-force-tfrag") (set! (-> obj lod-force-tfrag) (file-stream-read-int file)))
(("lod-force-tie") (set! (-> obj lod-force-tie) (file-stream-read-int file)))
(("lod-force-ocean") (set! (-> obj lod-force-ocean) (file-stream-read-int file)))
(("lod-force-actor") (set! (-> obj lod-force-actor) (file-stream-read-int file)))
(("subtitle-language") (set! (-> obj subtitle-language) (the-as pc-subtitle-lang (file-stream-read-int file))))
(("subtitle-speaker") (set! (-> obj subtitle-speaker?) (file-stream-read-symbol file)))
(("stick-deadzone") (set! (-> obj stick-deadzone) (file-stream-read-float file)))
(("ps2-read-speed?") (set! (-> obj ps2-read-speed?) (file-stream-read-symbol file)))
(("ps2-parts?") (set! (-> obj ps2-parts?) (file-stream-read-symbol file)))
(("ps2-music?") (set! (-> obj ps2-music?) (file-stream-read-symbol file)))
(("ps2-se?") (set! (-> obj ps2-se?) (file-stream-read-symbol file)))
(("ps2-hints?") (set! (-> obj ps2-hints?) (file-stream-read-symbol file)))
(("ps2-lod-dist?") (set! (-> obj ps2-lod-dist?) (file-stream-read-symbol file)))
(("force-actors?") (set! (-> obj force-actors?) (file-stream-read-symbol file)))
(("music-fade?") (set! (-> obj music-fade?) (file-stream-read-symbol file)))
(("use-vis?") (set! (-> obj use-vis?) (file-stream-read-symbol file)))
(("skip-movies?") (set! (-> obj skip-movies?) (file-stream-read-symbol file)))
(("subtitles?") (set! (-> obj subtitles?) (file-stream-read-symbol file)))
(("hinttitles?") (set! (-> obj hinttitles?) (file-stream-read-symbol file)))
(("discord-rpc?") (set! (-> obj discord-rpc?) (file-stream-read-symbol file)))
(("camera-hflip?") (set! (-> obj camera-hflip?) (file-stream-read-symbol file)))
(("camera-vflip?") (set! (-> obj camera-vflip?) (file-stream-read-symbol file)))
(("money-starburst?") (set! (-> obj money-starburst?) (file-stream-read-symbol file)))
(("scenes-seen")
(dotimes (i 197)
(set! (-> obj scenes-seen i) (file-stream-read-int file))
)
)
(("fixes")
(dosettings (file)
(case-str *pc-temp-string*
(("crash-sagecage") (set! (-> obj fixes crash-sagecage) (file-stream-read-symbol file)))
(("crash-dma") (set! (-> obj fixes crash-dma) (file-stream-read-symbol file)))
(("crash-light-eco") (set! (-> obj fixes crash-light-eco) (file-stream-read-symbol file)))
(("crash-moles") (set! (-> obj fixes crash-moles) (file-stream-read-symbol file)))
(("lockout-pelican") (set! (-> obj fixes lockout-pelican) (file-stream-read-symbol file)))
(("lockout-pipegame") (set! (-> obj fixes lockout-pipegame) (file-stream-read-symbol file)))
(("lockout-gambler") (set! (-> obj fixes lockout-gambler) (file-stream-read-symbol file)))
(("fix-movies") (set! (-> obj fixes fix-movies) (file-stream-read-symbol file)))
(("fix-credits") (set! (-> obj fixes fix-credits) (file-stream-read-symbol file)))
)
)
)
(("secrets")
(dosettings (file)
(case-str *pc-temp-string*
(("hard-rats?") (set! (-> obj secrets hard-rats?) (file-stream-read-symbol file)))
(("hero-mode?") (set! (-> obj secrets hero-mode?) (file-stream-read-symbol file)))
(("hud-map?") (set! (-> obj secrets hud-map?) (file-stream-read-symbol file)))
(("hud-counters?") (set! (-> obj secrets hud-counters?) (file-stream-read-symbol file)))
(("hud-watch?") (set! (-> obj secrets hud-watch?) (file-stream-read-symbol file)))
(("watch-12hr?") (set! (-> obj secrets watch-12hr?) (file-stream-read-symbol file)))
(("art") (set! (-> obj secrets art) (the-as pc-jak1-concept-art (file-stream-read-int file))))
(("hard-fish-hiscore") (set! (-> obj secrets hard-fish-hiscore) (file-stream-read-int file)))
(("hard-rats-hiscore") (set! (-> obj secrets hard-rats-hiscore) (file-stream-read-int file)))
(("hard-rats-hiwave") (set! (-> obj secrets hard-rats-hiwave) (file-stream-read-int file)))
(("music")
(dotimes (i 30)
(set! (-> obj secrets music i) (file-stream-read-int file))
)
)
)
)
)
(("panic")
(when (file-stream-read-symbol file)
(file-stream-close file)
(reset obj)
(write-to-file obj filename)
(set-display-mode! obj #f)
(return #f)
)
)
)
)
)
)
)
(when (!= PC_KERNEL_VERSION version)
(cond
((= (logand version #xffffffff00000000) (logand PC_KERNEL_VERSION #xffffffff00000000))
;; minor difference
)
(else
;; major difference
(format 0 "PC kernel version mismatch! Got ~D.~D vs ~D.~D~%" PC_KERNEL_VERSION_MAJOR PC_KERNEL_VERSION_MINOR (bit-field int version 32 16) (bit-field int version 48 16))
)
)
)
)
(file-stream-close file)
)
(format 0 "pc settings file read: ~A~%" filename)
#t
)
(defmethod write-to-file pc-settings ((obj pc-settings) (filename string))
"write settings to a file"
(if (not filename)
(return #f))
(let ((file (new 'stack 'file-stream filename 'write)))
(if (not (file-stream-valid? file))
(return #f))
(format file "(settings #x~X~%" (-> obj version))
(format file " (fps ~D)~%" (-> obj target-fps))
(format file " (size ~D ~D)~%" (-> obj width) (-> obj height))
(format file " (use-original-aspect-ratio? ~A)~%" (-> obj use-original-aspect-ratio?))
(format file " (aspect ~D ~D)~%" (-> obj aspect-custom-x) (-> obj aspect-custom-y))
(format file " (aspect-auto ~A)~%" (-> obj aspect-ratio-auto?))
(format file " (display-mode ~A)~%" (-> obj display-mode))
(format file " (aspect-ratio-mode ~A)~%" (-> obj aspect-ratio-mode))
(format file " (resolution ~A)~%" (-> obj resolution))
(format file " (letterbox ~A)~%" (-> obj letterbox?))
(format file " (vsync ~A)~%" (-> obj vsync?))
(format file " (font-scale ~f)~%" (-> obj font-scale))
(format file " (audio-latency-ms ~D)~%" (-> obj audio-latency-ms))
(format file " (audio-pan-override ~f)~%" (-> obj audio-pan-override))
(format file " (audio-volume-override ~f)~%" (-> obj audio-volume-override))
(format file " (audio-channel-nb ~D)~%" (-> obj audio-channel-nb))
(format file " (gfx-renderer ~D)~%" (-> obj gfx-renderer))
(format file " (gfx-resolution ~f)~%" (-> obj gfx-resolution))
(format file " (gfx-anisotropy ~f)~%" (-> obj gfx-anisotropy))
(format file " (shrub-dist-mod ~f)~%" (-> obj shrub-dist-mod))
(format file " (lod-dist-mod ~f)~%" (-> obj lod-dist-mod))
(format file " (lod-force-tfrag ~D)~%" (-> obj lod-force-tfrag))
(format file " (lod-force-tie ~D)~%" (-> obj lod-force-tie))
(format file " (lod-force-ocean ~D)~%" (-> obj lod-force-ocean))
(format file " (lod-force-actor ~D)~%" (-> obj lod-force-actor))
(format file " (stick-deadzone ~f)~%" (-> obj stick-deadzone))
(format file " (ps2-read-speed? ~A)~%" (-> obj ps2-read-speed?))
(format file " (ps2-parts? ~A)~%" (-> obj ps2-parts?))
(format file " (ps2-music? ~A)~%" (-> obj ps2-music?))
(format file " (ps2-se? ~A)~%" (-> obj ps2-se?))
(format file " (ps2-hints? ~A)~%" (-> obj ps2-hints?))
(format file " (ps2-lod-dist? ~A)~%" (-> obj ps2-lod-dist?))
(format file " (music-fade? ~A)~%" (-> obj music-fade?))
(format file " (use-vis? ~A)~%" (-> obj use-vis?))
(format file " (skip-movies? ~A)~%" (-> obj skip-movies?))
(format file " (discord-rpc? ~A)~%" (-> obj discord-rpc?))
(format file " (camera-hflip? ~A)~%" (-> obj camera-hflip?))
(format file " (camera-vflip? ~A)~%" (-> obj camera-vflip?))
(format file " (money-starburst? ~A)~%" (-> obj money-starburst?))
(format file " (force-actors? ~A)~%" (-> obj force-actors?))
(format file " (subtitles? ~A)~%" (-> obj subtitles?))
(format file " (hinttitles? ~A)~%" (-> obj hinttitles?))
(format file " (subtitle-language ~D)~%" (-> obj subtitle-language))
(format file " (subtitle-speaker ~A)~%" (-> obj subtitle-speaker?))
(format file " (scenes-seen")
(dotimes (i 197)
(if (zero? (mod i 16))
(format file "~% ")
)
(format file " ~D" (-> obj scenes-seen i))
)
(format file "~% )~%")
(format file " (fixes~%")
(format file " (crash-sagecage ~A)~%" (-> obj fixes crash-sagecage))
(format file " (crash-dma ~A)~%" (-> obj fixes crash-dma))
(format file " (crash-light-eco ~A)~%" (-> obj fixes crash-light-eco))
(format file " (crash-moles ~A)~%" (-> obj fixes crash-moles))
(format file " (lockout-pelican ~A)~%" (-> obj fixes lockout-pelican))
(format file " (lockout-pipegame ~A)~%" (-> obj fixes lockout-pipegame))
(format file " (lockout-gambler ~A)~%" (-> obj fixes lockout-gambler))
(format file " (fix-movies ~A)~%" (-> obj fixes fix-movies))
(format file " (fix-credits ~A)~%" (-> obj fixes fix-credits))
(format file " )~%")
(format file " (secrets~%")
(format file " (art #x~X)~%" (-> obj secrets art))
(format file " (hard-rats? ~A)~%" (-> obj secrets hard-rats?))
(format file " (hero-mode? ~A)~%" (-> obj secrets hero-mode?))
(format file " (hud-map? ~A)~%" (-> obj secrets hud-map?))
(format file " (hud-counters? ~A)~%" (-> obj secrets hud-counters?))
(format file " (hard-fish-hiscore ~D)~%" (-> obj secrets hard-fish-hiscore))
(format file " (hard-rats-hiscore ~D)~%" (-> obj secrets hard-rats-hiscore))
(format file " (hard-rats-hiwave ~D)~%" (-> obj secrets hard-rats-hiwave))
(format file " (music")
(dotimes (i 30)
(if (zero? (mod i 1))
(format file "~% ")
)
(format file " #x~X" (-> obj secrets music i))
)
(format file "~% )~%")
(format file " )~%")
(format file " )~%")
(file-stream-close file)
)
(format 0 "pc settings file write: ~A~%" filename)
#t
)
(defmethod new pc-settings ((allocation symbol) (type-to-make type))
"make a new pc-settings"
(let ((obj (object-new allocation type-to-make (the-as int (-> type-to-make size)))))
(reset obj)
;; auto load settings if available
;; if saved settings are corrupted or not found, use defaults
(clear *pc-temp-string-1*)
(format *pc-temp-string-1* "~S/pc-settings.gc" *pc-settings-folder*)
(if (pc-filepath-exists? *pc-temp-string-1*)
(begin
(format 0 "[PC] PC Settings found at '~S'...loading!~%" *pc-temp-string-1*)
(unless (read-from-file obj *pc-temp-string-1*)
(begin
(format 0 "[PC] PC Settings found at '~S' but could not be loaded, using defaults!~%" *pc-temp-string-1*)
(reset obj))))
(format 0 "[PC] PC Settings not found at '~S'...initializing with defaults!~%" *pc-temp-string-1*))
(clear *pc-temp-string-1*)
obj))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; PC settings
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define *pc-settings* (new 'global 'pc-settings))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; entity debugging
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(when *debug-segment*
(deftype entity-debug-inspect (basic)
(
(scroll-y int16)
(scroll-y-max int16)
(entity entity)
(show-actor-info symbol)
)
(:methods
(new (symbol type) _type_)
(set-entity! (_type_ entity) entity)
(update-pad (_type_ int) none)
)
)
(defmethod new entity-debug-inspect ((allocation symbol) (type-to-make type))
"make a new entity-debug-inspect object"
(let ((obj (object-new allocation type-to-make (the-as int (-> type-to-make size)))))
(set! (-> obj scroll-y) 0)
(set! (-> obj scroll-y-max) 0)
(set! (-> obj entity) (the entity #f))
(set! (-> obj show-actor-info) #f)
obj
)
)
(defmethod set-entity! entity-debug-inspect ((obj entity-debug-inspect) (e entity))
"set the entity to inspect"
(set! (-> obj entity) e)
(unless e
(set! *display-actor-anim* (the string #f)))
(set! (-> obj scroll-y) 0)
e
)
(defmethod update-pad entity-debug-inspect ((obj entity-debug-inspect) (pad-idx int))
"respond to pad inputs"
;; scroll up
(if (cpad-pressed? pad-idx l1)
(1-! (-> obj scroll-y)))
;; scroll down
(if (cpad-pressed? pad-idx r1)
(1+! (-> obj scroll-y)))
;; toggle actor info
(if (cpad-pressed? pad-idx l3)
(not! (-> obj show-actor-info)))
(minmax! (-> obj scroll-y) 0 (-> obj scroll-y-max))
(none))
(define *entity-debug-inspect* (new 'debug 'entity-debug-inspect))
)
)