From 4e28bd1eafe987aaaafccf7da9d02bfcb371b57c Mon Sep 17 00:00:00 2001 From: Matt Dallmeyer Date: Sat, 26 Apr 2025 14:23:55 -0700 Subject: [PATCH] [jak1] Speedrun mode misc fixes (#3902) Fixed up a few things for speedrun mode in Jak 1: - Changed autosplitter to start run in line with ruleset (first frame after blackout where jak is touching ground). Also tweaked the verification text in bottom left to show "Run Started: Yes/No" to go with this - Changed speedrun menu button combo to match Jak 2/3 (only need to hold L1+R1 and press Start/Select, no longer need to hold X) - Treat speedrun menu via Select the same as Start (no more potential for funny pause buffer where actors freeze) warp gate example: ![vlcsnap-2025-04-26-12h03m37s116](https://github.com/user-attachments/assets/3a06c3fe-0c60-4d8d-acaa-ec5f66145491) ![vlcsnap-2025-04-26-12h03m42s642](https://github.com/user-attachments/assets/e12439d4-1664-46a1-bfc0-56c737463603) already grounded example (run starts once partially out of blackout): ![vlcsnap-2025-04-26-12h04m02s085](https://github.com/user-attachments/assets/71659b45-b599-4ca1-b097-cf736f845933) --- goal_src/jak1/engine/game/main.gc | 76 ++++++++++++++---------- goal_src/jak1/pc/features/speedruns-h.gc | 1 + goal_src/jak1/pc/features/speedruns.gc | 39 ++++++++---- 3 files changed, 73 insertions(+), 43 deletions(-) diff --git a/goal_src/jak1/engine/game/main.gc b/goal_src/jak1/engine/game/main.gc index d06326de0a..ed98a83200 100644 --- a/goal_src/jak1/engine/game/main.gc +++ b/goal_src/jak1/engine/game/main.gc @@ -82,43 +82,55 @@ "Update pause masks for the given mode, and set *master-mode*" ;; og:preserve-this PAL patch here (let ((gp-0 *master-mode*)) - (set! *master-mode* new-mode) - (if *debug-segment* (menu-respond-to-pause)) - (case *master-mode* - (('pause) - ;; request the pause mask to be set in prevent-from-run. - ;; this will block any process with pause from running, pausing most game objects. - (if (not *debug-pause*) (logior! (-> *setting-control* default process-mask) (process-mask pause))) - ;; allow the menu to run. - (logclear! (-> *setting-control* default process-mask) (process-mask menu)) - ;; ?? - (set! *pause-lock* #f) - (sound-group-pause (sound-group sfx music dialog sog3 ambient sog5 sog6 sog7)) - ;; modified for PC port - show hidden speedrun progress menu if L1+R1+X are held - (if (and PC_PORT (-> *pc-settings* speedrunner-mode?) (cpad-hold? 0 l1) (cpad-hold? 0 r1) (cpad-hold? 0 x)) - (activate-progress *dproc* (progress-screen speedrun-options)) - (hide-progress-screen))) - (('menu) - ;; I believe these masks are just to make the progress go away work. - (logior! (-> *setting-control* default process-mask) (process-mask menu)) - (logclear! (-> *setting-control* default process-mask) (process-mask pause progress)) - (set! *pause-lock* #f) - (hide-progress-screen)) - (('progress) + ;; modified for PC port - show speedrun fast reset menu if L1+R1 held + (cond + ((and PC_PORT + (or (= new-mode 'pause) (= new-mode 'progress)) ;; pausing (as opposed to un-pausing) + (-> *pc-settings* speedrunner-mode?) + (cpad-hold? 0 l1) + (cpad-hold? 0 r1)) + ;; treat this as a 'progress pause to avoid funny 'pause buffers from Select button + (set! *master-mode* 'progress) + (if *debug-segment* (menu-respond-to-pause)) ;; allow menu to run while in progress. (logclear! (-> *setting-control* default process-mask) (process-mask menu)) ;; activate the progress menu. (when (not *progress-process*) - ;; modified for PC port - show hidden speedrun progress menu if L1+R1+X are held - (if (and PC_PORT (-> *pc-settings* speedrunner-mode?) (cpad-hold? 0 l1) (cpad-hold? 0 r1) (cpad-hold? 0 x)) - (activate-progress *dproc* (progress-screen speedrun-options)) - (activate-progress *dproc* (progress-screen fuel-cell))) + (activate-progress *dproc* (progress-screen speedrun-options)) (if (not *progress-process*) (set-master-mode 'game)))) - (('game) - ;; allow pausable/menu to run. - (logclear! (-> *setting-control* default process-mask) (process-mask pause menu)) - (if (!= gp-0 *master-mode*) (sound-group-continue (sound-group sfx music dialog sog3 ambient sog5 sog6 sog7))) - (hide-progress-screen)))) + (else + ;; vanilla logic + (set! *master-mode* new-mode) + (if *debug-segment* (menu-respond-to-pause)) + (case *master-mode* + (('pause) + ;; request the pause mask to be set in prevent-from-run. + ;; this will block any process with pause from running, pausing most game objects. + (if (not *debug-pause*) (logior! (-> *setting-control* default process-mask) (process-mask pause))) + ;; allow the menu to run. + (logclear! (-> *setting-control* default process-mask) (process-mask menu)) + ;; ?? + (set! *pause-lock* #f) + (sound-group-pause (sound-group sfx music dialog sog3 ambient sog5 sog6 sog7)) + (hide-progress-screen)) + (('menu) + ;; I believe these masks are just to make the progress go away work. + (logior! (-> *setting-control* default process-mask) (process-mask menu)) + (logclear! (-> *setting-control* default process-mask) (process-mask pause progress)) + (set! *pause-lock* #f) + (hide-progress-screen)) + (('progress) + ;; allow menu to run while in progress. + (logclear! (-> *setting-control* default process-mask) (process-mask menu)) + ;; activate the progress menu. + (when (not *progress-process*) + (activate-progress *dproc* (progress-screen fuel-cell)) + (if (not *progress-process*) (set-master-mode 'game)))) + (('game) + ;; allow pausable/menu to run. + (logclear! (-> *setting-control* default process-mask) (process-mask pause menu)) + (if (!= gp-0 *master-mode*) (sound-group-continue (sound-group sfx music dialog sog3 ambient sog5 sog6 sog7))) + (hide-progress-screen)))))) ;; apply settings now. (apply-settings *setting-control*) 0 diff --git a/goal_src/jak1/pc/features/speedruns-h.gc b/goal_src/jak1/pc/features/speedruns-h.gc index e00164962c..c3d77ee08a 100644 --- a/goal_src/jak1/pc/features/speedruns-h.gc +++ b/goal_src/jak1/pc/features/speedruns-h.gc @@ -38,6 +38,7 @@ (deftype speedrun-info-jak1 (structure) ((category speedrun-category) + (has-started? symbol) (needs-post-blackout-setup? symbol) (should-display? symbol))) diff --git a/goal_src/jak1/pc/features/speedruns.gc b/goal_src/jak1/pc/features/speedruns.gc index 6302daddef..1218293c08 100644 --- a/goal_src/jak1/pc/features/speedruns.gc +++ b/goal_src/jak1/pc/features/speedruns.gc @@ -4,7 +4,8 @@ (require "engine/game/task/game-task-h.gc") (require "pc/pckernel-common.gc") (require "pc/features/autosplit-h.gc") -(define *speedrun-info* (new 'static 'speedrun-info-jak1 :should-display? #t :needs-post-blackout-setup? #f)) +(define *speedrun-info* + (new 'static 'speedrun-info-jak1 :should-display? #t :needs-post-blackout-setup? #f :has-started? #f)) (define *hub1-cell-list* (new 'static @@ -144,14 +145,14 @@ (none)) (defun start-speedrun ((category speedrun-category)) - ;; randomize game id so the autosplitter knows to restart - (update-autosplit-jak1-new-game) ;; disable hints (turned back on later for all-cutscenes category) - (set! (-> *setting-control* default play-hints) #f) + (false! (-> *setting-control* default play-hints)) ;; turn on speedrun verification display and flip flag for setting up speedrun after initialize! - (set! (-> *speedrun-info* should-display?) #t) - (set! (-> *speedrun-info* needs-post-blackout-setup?) #t) - ;; start new game with specified checkpoint, if any (otherwise we're resetting current category) + (true! (-> *speedrun-info* should-display?)) + (true! (-> *speedrun-info* needs-post-blackout-setup?)) + ;; reset has-started? flag so we can flip it back to #t when jak touches ground + (false! (-> *speedrun-info* has-started?)) + ;; start new game with specified category, if any (otherwise we're resetting current category) (if category (set! (-> *speedrun-info* category) category)) (case (-> *speedrun-info* category) (((speedrun-category full-game)) @@ -387,6 +388,21 @@ (defun speedrun-mode-update () "A per frame update for speedrunning related stuff" (when (-> *pc-settings* speedrunner-mode?) + ;; Check if run/autosplitter should be started (out of blackout and player has control of jak) + (when (and (not (-> *speedrun-info* has-started?)) + *target* + ;; not in blackout + (>= (-> *display* base-frame-counter) (-> *game-info* blackout-time)) + (!= (-> *setting-control* current bg-a-force) 1.0) + ;; target has landed on ground/water, or we're about to enter target-hit-ground state + (or (logtest? (-> *target* control status) (cshape-moving-flags onground onsurf on-water)) + (= (-> *target* next-state name) 'target-hit-ground))) + (true! (-> *speedrun-info* has-started?)) + ;; spawn a process that resets autosplitter after suspending for 1 frame + (process-spawn-function process + (lambda () + (suspend) + (update-autosplit-jak1-new-game)))) ;; Update auto-splitter (update-autosplit-info-jak1) ;; Draw info to the screen @@ -405,13 +421,14 @@ "Draw speedrun related settings in the bottom left corner" (when (and (-> *pc-settings* speedrunner-mode?) (not (paused?)) (-> *speedrun-info* should-display?)) (with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) (bucket-id subtitle)) - (draw-string-xy (string-format "Speedrunner Mode ~%OpenGOAL Version: ~S ~%Category: ~S ~%Cutscene Skips ~A" + (draw-string-xy (string-format "Speedrunner Mode ~%OpenGOAL Version: ~S ~%Category: ~S ~S~%Run Started: ~S" *pc-settings-built-sha* (enum->string speedrun-category (-> *speedrun-info* category)) - (-> *pc-settings* skip-movies?)) + (if (-> *pc-settings* skip-movies?) "(CS Skips)" "(No CS Skips)") + (if (-> *speedrun-info* has-started?) "Yes" "No")) buf - 0 - (- 220 (* 8 4)) + 4 + (- 222 (* 8 4)) (font-color flat-yellow) (font-flags shadow kerning)))) (none))