mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 21:27:52 -04:00
939 lines
33 KiB
Common Lisp
939 lines
33 KiB
Common Lisp
;;-*-Lisp-*-
|
|
(in-package goal)
|
|
|
|
#|
|
|
|
|
This file contains new 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.
|
|
|
|
|#
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; global variables
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
;; collision renderer things. debug only.
|
|
(define *collision-renderer* #f)
|
|
(define *collision-wireframe* #f)
|
|
(define *collision-mode* (pc-collision-mode mode))
|
|
|
|
;; todo
|
|
(defenum pc-pat-skip-hack
|
|
:bitfield #t
|
|
(noentity 0)
|
|
(nocamera 1)
|
|
(noedge 2)
|
|
(nolineofsight 12)
|
|
(unknowncamera 13)
|
|
(unknown 15)
|
|
)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; updates
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(defmethod set-display-mode! pc-settings ((obj pc-settings) (mode symbol))
|
|
"sets the game's display mode"
|
|
;; change the display mode.
|
|
(set! (-> obj display-mode) mode)
|
|
;; if windowed mode, set the size properly
|
|
(when (= (-> obj display-mode) 'windowed)
|
|
(pc-set-window-size (max PC_MIN_WIDTH (-> obj win-width)) (max PC_MIN_HEIGHT (-> obj win-height))))
|
|
0)
|
|
|
|
(defmethod set-size! pc-settings ((obj pc-settings) (width int) (height int))
|
|
"sets the size of the display window"
|
|
(format 0 "Setting ~A size to ~D x ~D~%" (-> obj display-mode) width height)
|
|
(cond
|
|
((= 'windowed (-> obj display-mode))
|
|
(set! (-> obj win-width) width)
|
|
(set! (-> obj win-height) height)
|
|
(pc-set-window-size (max PC_MIN_WIDTH (-> obj win-width)) (max PC_MIN_HEIGHT (-> obj win-height)))
|
|
)
|
|
(else
|
|
(set! (-> obj width) width)
|
|
(set! (-> obj height) 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-custom-x) aw)
|
|
(set! (-> obj aspect-custom-y) ah)
|
|
(set! (-> obj aspect-ratio-auto?) #f)
|
|
(set! (-> obj use-vis?) #f)
|
|
)
|
|
(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-window-lock! pc-settings ((obj pc-settings) (lock symbol))
|
|
"set the aspect ratio used for rendering."
|
|
(pc-set-window-lock lock)
|
|
(set! (-> obj window-lock?) lock))
|
|
|
|
(defmethod set-frame-rate! pc-settings ((obj pc-settings) (rate int))
|
|
"set the target framerate."
|
|
(pc-set-frame-rate rate)
|
|
(if (and (!= 'fullscreen (-> obj display-mode))
|
|
(!= (pc-get-screen-rate -1) rate))
|
|
(set! (-> obj vsync?) #f))
|
|
(case rate
|
|
((50)
|
|
(set! (-> obj target-fps) rate)
|
|
(set-game-setting! obj 'video-mode 'pal)
|
|
)
|
|
((60)
|
|
(set! (-> obj target-fps) rate)
|
|
(set-game-setting! obj 'video-mode 'ntsc)
|
|
)
|
|
(else
|
|
(set! (-> obj target-fps) rate)
|
|
(set-game-setting! obj 'video-mode 'custom)
|
|
)
|
|
)
|
|
|
|
rate)
|
|
|
|
(defmethod set-monitor! pc-settings ((obj pc-settings) (monitor int))
|
|
"set the monitor to use when in fullscreen/borderless"
|
|
(set! (-> obj monitor) monitor)
|
|
(none))
|
|
|
|
(defmethod commit-to-file pc-settings ((obj pc-settings))
|
|
"commits the current settings to the file"
|
|
;; auto load settings if available
|
|
|
|
(format (clear *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*)
|
|
(none))
|
|
|
|
(defmethod update-from-os pc-settings ((obj pc-settings))
|
|
"Update settings from the C kernel to GOAL."
|
|
|
|
(set! (-> obj os) (pc-get-os))
|
|
(pc-get-window-size (&-> obj real-width) (&-> obj real-height))
|
|
(pc-get-window-scale (&-> obj dpi-x) (&-> obj dpi-y))
|
|
|
|
(when (-> obj use-vis?)
|
|
(if (= (get-game-setting obj 'aspect-ratio) 'aspect4x3)
|
|
(set-aspect-ratio! obj ASPECT_4X3)
|
|
(set-aspect-ratio! obj ASPECT_16X9)
|
|
)
|
|
)
|
|
|
|
(unless (or (zero? (-> obj real-width)) (zero? (-> obj real-height)))
|
|
(let ((win-aspect (/ (the float (-> obj real-width)) (the float (-> obj real-height)))))
|
|
(cond
|
|
((and (not (-> obj use-vis?)) (-> obj aspect-ratio-auto?))
|
|
;; the window determines the resolution
|
|
(set-aspect-ratio! obj win-aspect)
|
|
(set! (-> obj lbox-width) (-> obj real-width))
|
|
(set! (-> obj lbox-height) (-> obj real-height))
|
|
)
|
|
((> win-aspect (-> obj aspect-ratio))
|
|
;; too wide
|
|
(set! (-> obj lbox-width) (the int (* (the float (-> obj real-height)) (-> obj aspect-ratio))))
|
|
(set! (-> obj lbox-height) (-> obj real-height))
|
|
)
|
|
((< win-aspect (-> obj aspect-ratio))
|
|
;; too tall
|
|
(set! (-> obj lbox-width) (-> obj real-width))
|
|
(set! (-> obj lbox-height) (the int (/ (the float (-> obj real-width)) (-> obj aspect-ratio))))
|
|
)
|
|
(else
|
|
;; just right
|
|
(set! (-> obj lbox-width) (-> obj real-width))
|
|
(set! (-> obj lbox-height) (-> obj real-height))
|
|
)
|
|
)
|
|
))
|
|
|
|
|
|
(none))
|
|
|
|
(defmethod update-to-os pc-settings ((obj pc-settings))
|
|
"Update settings from GOAL to the C kernel."
|
|
|
|
(cond
|
|
((-> obj letterbox?)
|
|
(pc-set-letterbox (-> obj lbox-width) (-> obj lbox-height))
|
|
)
|
|
(else
|
|
(pc-set-letterbox (-> obj real-width) (-> obj real-height))
|
|
)
|
|
)
|
|
|
|
;; if monitor selection is out of bounds (e.g. if a monitor got disconnected),
|
|
;; then default to the primary monitor
|
|
(when (>= (-> obj monitor) (pc-get-monitor-count))
|
|
(format 0 "Monitor selection out of bounds, defaulting to primary monitor.~%")
|
|
(set! (-> obj monitor) 0)
|
|
)
|
|
|
|
;; set fullscreen to what we want
|
|
(pc-set-fullscreen (-> obj display-mode) (-> obj monitor))
|
|
|
|
;; set window size and fps automatically if the window lock is enabled.
|
|
(when (-> obj window-lock?)
|
|
(pc-set-vsync (-> obj vsync?))
|
|
|
|
(when (!= 'fullscreen (-> obj display-mode))
|
|
(if (< (pc-get-screen-rate -1) (-> obj target-fps))
|
|
(pc-set-vsync #f))
|
|
(pc-set-frame-rate (-> obj target-fps)))
|
|
)
|
|
;; do game resolution
|
|
(if (= (-> obj display-mode) 'windowed)
|
|
(pc-set-game-resolution (-> obj real-width) (-> obj real-height))
|
|
(pc-set-game-resolution (-> obj width) (-> obj height)))
|
|
|
|
;; set msaa sample rate. if invalid, just reset to 4.
|
|
(let ((valid? #f))
|
|
(dotimes (i 31)
|
|
(if (= (-> obj gfx-msaa) (ash 1 i))
|
|
(true! valid?))
|
|
)
|
|
|
|
(if (not valid?) (set! (-> obj gfx-msaa) 4))
|
|
(pc-set-msaa (-> obj gfx-msaa))
|
|
)
|
|
|
|
(pc-discord-rpc-set (if (-> obj discord-rpc?) 1 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))
|
|
)
|
|
|
|
(when *debug-segment*
|
|
(pc-set-collision *collision-renderer*)
|
|
(pc-set-collision-wireframe *collision-wireframe*)
|
|
(pc-set-collision-mode *collision-mode*)
|
|
)
|
|
|
|
(pc-sound-set-flava-hack (-> obj flava-hack))
|
|
(let ((fade-hack 0))
|
|
(unless (-> obj music-fadein?) (logior! fade-hack 1))
|
|
(unless (-> obj music-fadeout?) (logior! fade-hack 2))
|
|
(pc-sound-set-fade-hack fade-hack)
|
|
)
|
|
|
|
(none))
|
|
|
|
;; where we store the input progress for the cheat codes. make sure there's enough space for all cheats.
|
|
(define *pc-cheat-temp* (new 'global 'inline-array 'uint8 PC_CHEAT_MAX))
|
|
|
|
(defmacro pc-cheat-toggle-and-tune (cheats-var cheat)
|
|
"quickly toggle a cheat code and play an appropriate sound"
|
|
`(begin
|
|
(cpad-clear! 0 r1)
|
|
(logxor! ,cheats-var (pc-cheats ,cheat))
|
|
(cheats-sound-play (logtest? ,cheats-var (pc-cheats ,cheat)))
|
|
)
|
|
)
|
|
|
|
(defun bcd->dec ((bcd uint))
|
|
"Convert a number encoded in BCD to its decimal equivalent"
|
|
(+ (* (shr (logand bcd #xf0) 4) 10) (logand bcd #x0f))
|
|
)
|
|
|
|
(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?))
|
|
|
|
(update-discord-rpc obj)
|
|
|
|
;; update auto-splitter info
|
|
(when (-> *pc-settings* speedrunner-mode?)
|
|
(update-speedrun obj))
|
|
|
|
(when (not (-> obj use-vis?))
|
|
(update-video-hacks obj)
|
|
)
|
|
(cond
|
|
((-> obj force-actors?)
|
|
;; kinda overkill.
|
|
(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)) ;; the original caps at 220m, exceeding that means it was using our hacks
|
|
(set! (-> *ACTOR-bank* birth-dist) (meters 220))
|
|
(set! (-> *ACTOR-bank* pause-dist) (meters 220))
|
|
))
|
|
|
|
;; cheats.
|
|
(update-cheats obj)
|
|
;; music.
|
|
(update-music-log obj)
|
|
|
|
(none))
|
|
|
|
(defmethod update-cheats pc-settings ((obj pc-settings))
|
|
"run cheats."
|
|
0)
|
|
|
|
|
|
(defmethod add-to-music-log pc-settings ((obj pc-settings) (music symbol) (flava int))
|
|
"add music and flava information to the music log.
|
|
if music already exists, adds flava. if flava already exists, nothing happens."
|
|
|
|
;; go through our music log
|
|
(dotimes (i PC_MUSIC_LOG_LENGTH)
|
|
(cond
|
|
;; an empty log entry! place the currently playing music there, and fill flava.
|
|
((not (-> obj secrets music i name))
|
|
(set! (-> obj secrets music i name) music)
|
|
(set! (-> obj secrets music i flava-mask) (ash 1 flava))
|
|
(return 0)
|
|
)
|
|
;; an existing log entry for the current music. fill flava.
|
|
((= music (-> obj secrets music i name))
|
|
(logior! (-> obj secrets music i flava-mask) (ash 1 flava))
|
|
(return 0)
|
|
)
|
|
;; something else. maybe the wrong entry, in which case nothing to do.
|
|
)
|
|
)
|
|
|
|
0)
|
|
|
|
(defmethod update-music-log pc-settings ((obj pc-settings))
|
|
"update music log settings."
|
|
0)
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; functions
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
(defmethod get-current-game-width pc-settings ((obj pc-settings))
|
|
"return the current width in pixels of the visible portion of the game"
|
|
|
|
(cond
|
|
((= (-> obj display-mode) 'windowed)
|
|
(if (-> obj letterbox?)
|
|
(-> obj lbox-width)
|
|
(-> obj real-width)))
|
|
(else
|
|
(-> obj width))
|
|
)
|
|
)
|
|
(defmethod get-current-game-height pc-settings ((obj pc-settings))
|
|
"return the current height in pixels of the visible portion of the game"
|
|
|
|
(cond
|
|
((= (-> obj display-mode) 'windowed)
|
|
(if (-> obj letterbox?)
|
|
(-> obj lbox-height)
|
|
(-> obj real-height)))
|
|
(else
|
|
(-> obj height))
|
|
)
|
|
)
|
|
|
|
(when *debug-segment*
|
|
|
|
(defmethod draw pc-settings ((obj pc-settings) (buf dma-buffer))
|
|
"debug draw some things on-screen"
|
|
|
|
(when (-> obj debug?)
|
|
(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 real-width) (-> obj real-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 real-width)) (the float (-> obj real-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))
|
|
)
|
|
(when *display-actor-bank*
|
|
(draw-string-xy (string-format "Actor Bank: ~,,1m/~,,1m (~D)" (-> *ACTOR-bank* pause-dist) (-> *ACTOR-bank* birth-dist) (-> *ACTOR-bank* birth-max)) buf 512 (- 224 8) (font-color default) (font-flags shadow kerning right))
|
|
)
|
|
)
|
|
|
|
)
|
|
|
|
|
|
(defun find-music-log ((music symbol))
|
|
"return #t if the given music is logged into the *pc-settings*, #f otherwise."
|
|
(dotimes (i PC_MUSIC_LOG_LENGTH)
|
|
(if (= music (-> *pc-settings* secrets music i name))
|
|
(return #t)))
|
|
#f)
|
|
|
|
(defun find-flava-log ((music symbol) (flava-idx int))
|
|
"return #t if the given music's flava is logged into the *pc-settings*, #f otherwise."
|
|
(dotimes (i PC_MUSIC_LOG_LENGTH)
|
|
(if (= music (-> *pc-settings* secrets music i name))
|
|
(return (logtest? (-> *pc-settings* secrets music i flava-mask) (ash 1 flava-idx)))))
|
|
#f)
|
|
|
|
(defun-debug print-music-log ((out object))
|
|
"prints the *pc-settings* music log."
|
|
|
|
(dotimes (i PC_MUSIC_LOG_LENGTH)
|
|
(if (-> *pc-settings* secrets music i name)
|
|
(format out "music log ~D: ~A (f #x~x)~%" i (-> *pc-settings* secrets music i name) (-> *pc-settings* secrets music i flava-mask)))
|
|
)
|
|
|
|
0)
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; 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 file-stream-get-next-char-ret (fs)
|
|
`(begin
|
|
(file-stream-seek-past-whitespace ,fs)
|
|
(let ((c (file-stream-getc ,fs)))
|
|
(file-stream-seek ,fs -1 SCE_SEEK_CUR)
|
|
c))
|
|
)
|
|
|
|
(defmacro file-stream-get-next-char (fs)
|
|
`(begin
|
|
(file-stream-seek-past-whitespace ,fs)
|
|
(file-stream-getc ,fs)
|
|
)
|
|
)
|
|
|
|
(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
|
|
|
|
(set! c (file-stream-get-next-char ,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)
|
|
(case-str (file-stream-read-word file)
|
|
(("settings")
|
|
(set! version (the pckernel-version (file-stream-read-int file)))
|
|
(cond
|
|
((and (= (-> version major) PC_KERNEL_VER_MAJOR)
|
|
(= (-> version minor) PC_KERNEL_VER_MINOR))
|
|
;; minor or no difference
|
|
)
|
|
(else
|
|
;; major difference
|
|
(format 0 "PC kernel version mismatch! Got ~D.~D vs ~D.~D~%" PC_KERNEL_VER_MAJOR PC_KERNEL_VER_MINOR (-> version major) (-> version minor))
|
|
(file-stream-close file)
|
|
(return #f)
|
|
)
|
|
)
|
|
(dosettings (file)
|
|
(handle-input-settings obj file)
|
|
)
|
|
;; upgrade settings if minor changes
|
|
;; remember to delete this when major changes to the version number are made
|
|
(when (and (= PC_KERNEL_VER_MAJOR 1)
|
|
(= PC_KERNEL_VER_MINOR 10)
|
|
(or (!= PC_KERNEL_VER_BUILD (-> version build))
|
|
(!= PC_KERNEL_VER_REVISION (-> version revision))))
|
|
;; 1.10 upgrade: turn envmap on
|
|
(set! (-> obj force-envmap?) #t)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
)
|
|
|
|
(file-stream-close file)
|
|
)
|
|
|
|
(format 0 "pc settings file read: ~A~%" filename)
|
|
|
|
;; restore the windowed mode resolution properly
|
|
(when (= (-> obj display-mode) 'windowed)
|
|
(pc-set-window-size (max PC_MIN_WIDTH (-> obj win-width)) (max PC_MIN_HEIGHT (-> obj win-height))))
|
|
|
|
#t
|
|
)
|
|
|
|
(defmethod handle-input-settings pc-settings ((obj pc-settings) (file file-stream))
|
|
"handle the text parsing input for the 'settings' group"
|
|
|
|
(case-str *pc-temp-string*
|
|
(("fps") (set-frame-rate! obj (file-stream-read-int file)))
|
|
(("window-size")
|
|
(set! (-> obj win-width) (file-stream-read-int file))
|
|
(set! (-> obj win-height) (file-stream-read-int file))
|
|
)
|
|
(("game-size")
|
|
(set! (-> obj width) (file-stream-read-int file))
|
|
(set! (-> obj height) (file-stream-read-int file))
|
|
)
|
|
(("msaa") (set! (-> obj gfx-msaa) (file-stream-read-int file)))
|
|
(("aspect-state")
|
|
;; game aspect
|
|
(set-game-setting! obj 'aspect-ratio (file-stream-read-symbol file))
|
|
;; aspect ratio
|
|
(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))
|
|
|
|
(unless (-> obj aspect-ratio-auto?)
|
|
(set-aspect! obj (-> obj aspect-custom-x) (-> obj aspect-custom-y))
|
|
)
|
|
)
|
|
(("display-mode") (set-display-mode! obj (file-stream-read-symbol file)))
|
|
(("monitor") (set-monitor! obj (file-stream-read-int 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)))
|
|
(("game-language") (set-game-language! obj (the-as language-enum (file-stream-read-int file))))
|
|
(("text-language") (set! (-> obj text-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-envmap?") (set! (-> obj force-envmap?) (file-stream-read-symbol file)))
|
|
(("force-actors?") (set! (-> obj force-actors?) (file-stream-read-symbol file)))
|
|
(("music-fade?") (file-stream-read-symbol file)) ;; TODO remove
|
|
(("use-vis?") (set! (-> obj use-vis?) (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)))
|
|
(("speedrunner-mode?") (set! (-> obj speedrunner-mode?) (file-stream-read-symbol file)))
|
|
(("cutscene-skips?") (file-stream-read-symbol file)) ;; TODO remove
|
|
(("first-camera-h-inverted?") (set! (-> obj first-camera-h-inverted?) (file-stream-read-symbol file)))
|
|
(("first-camera-v-inverted?") (set! (-> obj first-camera-v-inverted?) (file-stream-read-symbol file)))
|
|
(("third-camera-h-inverted?") (set! (-> obj third-camera-h-inverted?) (file-stream-read-symbol file)))
|
|
(("third-camera-v-inverted?") (set! (-> obj third-camera-v-inverted?) (file-stream-read-symbol file)))
|
|
(("music-fadein?") (set! (-> obj music-fadein?) (file-stream-read-symbol file)))
|
|
(("music-fadeout?") (set! (-> obj music-fadeout?) (file-stream-read-symbol file)))
|
|
(("scenes-seen")
|
|
(dotimes (i PC_SPOOL_LOG_LENGTH)
|
|
(set! (-> obj scenes-seen i) (file-stream-read-int 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)))
|
|
(("cheats")
|
|
(set! (-> obj cheats-known) (the pc-cheats (file-stream-read-int file)))
|
|
(set! (-> obj cheats) (logand (-> obj cheats-known) (file-stream-read-int file)))
|
|
)
|
|
(("music")
|
|
(dotimes (i PC_MUSIC_LOG_LENGTH)
|
|
(when (!= #x29 (file-stream-get-next-char-ret file))
|
|
(with-settings-scope (file)
|
|
(set! (-> obj secrets music i name) (file-stream-read-symbol file))
|
|
(set! (-> obj secrets music i flava-mask) (file-stream-read-int file))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(("panic")
|
|
(when (file-stream-read-symbol file)
|
|
(reset obj)
|
|
(set-display-mode! obj #f)
|
|
(return #f)
|
|
)
|
|
)
|
|
)
|
|
0)
|
|
|
|
(defmethod handle-output-settings pc-settings ((obj pc-settings) (file file-stream))
|
|
"handle the text writing output for the 'settings' group"
|
|
|
|
(format file " (fps ~D)~%" (-> obj target-fps))
|
|
(format file " (msaa ~D)~%" (-> obj gfx-msaa))
|
|
(format file " (aspect-state ~A ~D ~D ~A)~%" (get-game-setting obj 'aspect-ratio)
|
|
(-> obj aspect-custom-x) (-> obj aspect-custom-y)
|
|
(-> obj aspect-ratio-auto?))
|
|
(format file " (display-mode ~A)~%" (-> obj display-mode))
|
|
(format file " (window-size ~D ~D)~%" (-> obj win-width) (-> obj win-height))
|
|
(format file " (game-size ~D ~D)~%" (-> obj width) (-> obj height))
|
|
(format file " (monitor ~D)~%" (-> obj monitor))
|
|
(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 " (force-envmap? ~A)~%" (-> obj force-envmap?))
|
|
(format file " (use-vis? ~A)~%" (-> obj use-vis?))
|
|
(format file " (discord-rpc? ~A)~%" (-> obj discord-rpc?))
|
|
(format file " (speedrunner-mode? ~A)~%" (-> obj speedrunner-mode?))
|
|
(format file " (first-camera-h-inverted? ~A)~%" (-> obj first-camera-h-inverted?))
|
|
(format file " (first-camera-v-inverted? ~A)~%" (-> obj first-camera-v-inverted?))
|
|
(format file " (third-camera-h-inverted? ~A)~%" (-> obj third-camera-h-inverted?))
|
|
(format file " (third-camera-v-inverted? ~A)~%" (-> obj third-camera-v-inverted?))
|
|
(format file " (force-actors? ~A)~%" (-> obj force-actors?))
|
|
(format file " (music-fadein? ~A)~%" (-> obj music-fadein?))
|
|
(format file " (music-fadeout? ~A)~%" (-> obj music-fadeout?))
|
|
(format file " (hinttitles? ~A)~%" (-> obj hinttitles?))
|
|
(format file " (game-language ~D)~%" (get-game-language obj))
|
|
(format file " (text-language ~D)~%" (-> obj text-language))
|
|
(format file " (subtitle-speaker ~A)~%" (-> obj subtitle-speaker?))
|
|
|
|
#|
|
|
(format file " (scenes-seen")
|
|
(dotimes (i PC_SPOOL_LOG_LENGTH)
|
|
(if (zero? (mod i 16))
|
|
(format file "~% ")
|
|
)
|
|
(format file " ~D" (-> obj scenes-seen i))
|
|
)
|
|
(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 " (cheats #x~x #x~x)~%" (-> obj cheats-known) (-> obj cheats))
|
|
|
|
(format file " (music~%")
|
|
(dotimes (i PC_MUSIC_LOG_LENGTH)
|
|
(if (-> obj secrets music i name)
|
|
(format file " (~A #x~X)~%" (-> obj secrets music i name) (-> obj secrets music i flava-mask))
|
|
)
|
|
)
|
|
|
|
(format file " )~%")
|
|
|
|
(format file " )~%")
|
|
0)
|
|
|
|
(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~%" PC_KERNEL_VERSION)
|
|
|
|
(handle-output-settings obj file)
|
|
|
|
(format file " )~%")
|
|
(file-stream-close file)
|
|
)
|
|
|
|
(format 0 "pc settings file write: ~A~%" filename)
|
|
|
|
#t
|
|
)
|
|
|
|
(defmethod load-settings pc-settings ((obj pc-settings))
|
|
"load"
|
|
|
|
(format (clear *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*)
|
|
(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*))
|
|
0)
|
|
|
|
(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
|
|
|
|
(load-settings obj)
|
|
|
|
obj))
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;; 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 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))
|
|
|
|
) ;; when debug_segment
|
|
|
|
|
|
|
|
|
|
|