diff --git a/Taskfile.yml b/Taskfile.yml index 1bcfb2b5c5..d6f33d051e 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -144,6 +144,9 @@ tasks: ignore_error: true - python ./scripts/update_decomp_reference.py ./failures ./test/decompiler/reference/ --game {{.GAME}} - task: offline-test-file + type-test-jak1: + cmds: + - cmd: '{{.GOALCTEST_BIN_RELEASE_DIR}}/goalc-test --gtest_brief=0 --gtest_filter="*Jak1TypeConsistency*" --gtest_break_on_failure' type-test: cmds: - cmd: '{{.GOALCTEST_BIN_RELEASE_DIR}}/goalc-test --gtest_brief=0 --gtest_filter="*Jak2TypeConsistency*" --gtest_break_on_failure' diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index f3d81290cb..51d55ba5e9 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -1611,6 +1611,35 @@ (hint-511 #x14ff) (speedrunner-mode #x1500) (cutscene-skips #x1501) + (checkpoint-select #x1502) + (speedrun-options-heading #x1503) + (speedrun-options-warning #x1504) + (speedrun-reset-current-run #x1505) + (speedrun-new-full-game #x1506) + ;; (speedrun-full-game-any #x1507) + ;; (speedrun-full-game-100 #x1508) + ;; (speedrun-full-game-nolts #x1509) + ;; (speedrun-full-game-nofcs #x150a) + ;; (speedrun-full-game-orbless #x150b) + ;; (speedrun-full-game-all-flies #x150c) + ;; (speedrun-full-game-all-orbs #x150d) + (speedrun-new-individual-level #x150e) + (speedrun-il-training #x150f) + (speedrun-il-village1 #x1510) + (speedrun-il-beach #x1511) + (speedrun-il-jungle #x1512) + (speedrun-il-misty #x1513) + (speedrun-il-firecanyon #x1514) + (speedrun-il-village2 #x1515) + (speedrun-il-sunken #x1516) + (speedrun-il-swamp #x1517) + (speedrun-il-rolling #x1518) + (speedrun-il-ogre #x1519) + (speedrun-il-village3 #x151a) + (speedrun-il-snow #x151b) + (speedrun-il-cave #x151c) + (speedrun-il-lavatube #x151d) + (speedrun-il-citadel #x151e) ;; GAME-TEXT-ID ENUM ENDS ) @@ -15763,6 +15792,9 @@ (memcard-disable-auto-save) (memcard-auto-save-disabled) (monitor) + (checkpoint-select) + (speedrun-options) + (speedrun-il-options) ;; the last one! (max) diff --git a/game/assets/jak1/text/game_text_en.gs b/game/assets/jak1/text/game_text_en.gs index 5e6ae9c9e7..e32a7c9f58 100644 --- a/game/assets/jak1/text/game_text_en.gs +++ b/game/assets/jak1/text/game_text_en.gs @@ -362,6 +362,65 @@ (#x1501 "CUTSCENE SKIPS" "CUTSCENE SKIPS") +(#x1502 "CHECKPOINT SELECT" + "CHECKPOINT SELECT") + +(#x1503 "SPEEDRUN OPTIONS" + "SPEEDRUN OPTIONS") + +(#x1504 "CAUTION: THESE OPTIONS WILL AUTO SAVE IN YOUR FIRST SAVE SLOT!" + "CAUTION: THESE OPTIONS WILL AUTO SAVE IN YOUR FIRST SAVE SLOT!") + +(#x1505 "RESET CURRENT SPEEDRUN" + "RESET CURRENT SPEEDRUN") + +(#x1506 "NEW FULL GAME RUN" + "NEW FULL GAME RUN") + +;; #x1507 any% +;; #x1508 100% +;; #x1509 nolts +;; #x150a nofcs +;; #x150b orbless +;; #x150c all flies +;; #x150d all orbs + +(#x150e "NEW INDIVIDUAL LEVEL RUN" + "NEW INDIVIDUAL LEVEL RUN") + +(#x150f "GEYSER ROCK IL" + "GEYSER ROCK IL") +(#x1510 "SANDOVER VILLAGE IL" + "SANDOVER VILLAGE IL") +(#x1511 "SENTINEL BEACH IL" + "SENTINEL BEACH IL") +(#x1512 "FORBIDDEN JUNGLE IL" + "FORBIDDEN JUNGLE IL") +(#x1513 "MISTY ISLAND IL" + "MISTY ISLAND IL") +(#x1514 "FIRE CANYON IL" + "FIRE CANYON IL") +(#x1515 "ROCK VILLAGE IL" + "ROCK VILLAGE IL") +(#x1516 "LOST PRECURSOR CITY IL" + "LOST PRECURSOR CITY IL") +(#x1517 "BOGGY SWAMP IL" + "BOGGY SWAMP IL") +(#x1518 "PRECURSOR BASIN IL" + "PRECURSOR BASIN IL") +(#x1519 "MOUNTAIN PASS IL" + "MOUNTAIN PASS IL") +(#x151a "VOLCANIC CRATER IL" + "VOLCANIC CRATER IL") +(#x151b "SNOWY MOUNTAIN IL" + "SNOWY MOUNTAIN IL") +(#x151c "SPIDER CAVE IL" + "SPIDER CAVE IL") +(#x151d "LAVA TUBE IL" + "LAVA TUBE IL") +(#x151e "GOL AND MAIA'S CITADEL IL" + "GOL AND MAIA'S CITADEL IL") + ;; ----------------- ;; test (DO NOT TRANSLATE) diff --git a/goal_src/jak1/dgos/game.gd b/goal_src/jak1/dgos/game.gd index 5535d06a9b..360581abb4 100644 --- a/goal_src/jak1/dgos/game.gd +++ b/goal_src/jak1/dgos/game.gd @@ -189,13 +189,13 @@ ("entity-table.o" "entity-table") ("loader.o" "loader") ("task-control-h.o" "task-control-h") + ("speedruns-h.o" "speedruns-h") ;; added ("game-info.o" "game-info") ("game-save.o" "game-save") ("settings.o" "settings") ("pc-anim-util.o" "pc-anim-util") ;; added ("autosplit-h.o" "autosplit-h") ;; added ("autosplit.o" "autosplit") ;; added - ("speedruns-h.o" "speedruns-h") ;; added ("speedruns.o" "speedruns") ;; added ("pckernel.o" "pckernel") ;; added ("mood-tables.o" "mood-tables") diff --git a/goal_src/jak1/engine/game/game-info.gc b/goal_src/jak1/engine/game/game-info.gc index cbcf62fdc7..90275e7d55 100644 --- a/goal_src/jak1/engine/game/game-info.gc +++ b/goal_src/jak1/engine/game/game-info.gc @@ -168,7 +168,7 @@ The cause can be 'dead if you die, or 'game to reset everything. If save-to-load is not #f will load data from that. If continue-point-override is not #f, will use that." - + (local-vars (v0-0 int) (sv-96 symbol)) (case cause (('dead) @@ -601,6 +601,10 @@ (((pickup-type money)) ;; get money. (when (< 0.0 amount) + (#when PC_PORT + ;; make sure any speedrun display is hidden + (hide-speedrun-display) + ) ;; play sound. (if (>= (- (-> *display* base-frame-counter) (-> obj money-pickup-time)) (seconds 0.05)) (sound-play "money-pickup") @@ -612,10 +616,14 @@ (((pickup-type fuel-cell)) ;; the amount is actually the index of the task. (let ((s4-2 (the int amount))) - (if (not (or (task-complete? (-> (the-as target (-> obj process)) game) (the-as game-task s4-2)) + (when (not (or (task-complete? (-> (the-as target (-> obj process)) game) (the-as game-task s4-2)) (>= (the-as uint 1) (the-as uint s4-2)) ) ) + (#when PC_PORT + ;; make sure any speedrun display is hidden + (hide-speedrun-display) + ) (set! (-> obj fuel-cell-pickup-time) (-> *display* base-frame-counter)) ) ) @@ -624,7 +632,11 @@ (((pickup-type buzzer)) ;; buzzer (let ((buzz-count (adjust (-> (the-as target (-> obj process)) game) 'buzzer amount source-handle))) - (if (!= buzz-count (-> obj buzzer)) + (when (!= buzz-count (-> obj buzzer)) + (#when PC_PORT + ;; make sure any speedrun display is hidden + (hide-speedrun-display) + ) (set! (-> obj buzzer-pickup-time) (-> *display* base-frame-counter)) ) (set! (-> obj buzzer) buzz-count) diff --git a/goal_src/jak1/engine/game/main.gc b/goal_src/jak1/engine/game/main.gc index a56716e030..f15e6ec924 100644 --- a/goal_src/jak1/engine/game/main.gc +++ b/goal_src/jak1/engine/game/main.gc @@ -140,7 +140,11 @@ ;; activate the progress menu. (when (not *progress-process*) - (activate-progress *dproc* (progress-screen fuel-cell)) + ;; 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)) + ) (if (not *progress-process*) (set-master-mode 'game) ) diff --git a/goal_src/jak1/engine/target/target-death.gc b/goal_src/jak1/engine/target/target-death.gc index 3df6095d27..5f99ad79d1 100644 --- a/goal_src/jak1/engine/target/target-death.gc +++ b/goal_src/jak1/engine/target/target-death.gc @@ -218,6 +218,7 @@ (or (= (get-task-status (game-task beach-ecorocks)) (task-status need-hint)) (= (get-task-status (game-task beach-ecorocks)) (task-status need-introduction)) ) + (#when PC_PORT (not (is-speedrun-category? 'il-village1))) ;; modified for PC port - skip green sage cutscene in Sandover IL speedrun ) (let ((s5-4 (entity-by-name "sage-23"))) (when s5-4 diff --git a/goal_src/jak1/engine/ui/progress/progress-h.gc b/goal_src/jak1/engine/ui/progress/progress-h.gc index 6dbbeef56b..93b50bc58b 100644 --- a/goal_src/jak1/engine/ui/progress/progress-h.gc +++ b/goal_src/jak1/engine/ui/progress/progress-h.gc @@ -123,6 +123,9 @@ (memcard-disable-auto-save) (memcard-auto-save-disabled) (monitor) + (checkpoint-select) + (speedrun-options) + (speedrun-il-options) ;; the last one! (max) diff --git a/goal_src/jak1/engine/ui/progress/progress.gc b/goal_src/jak1/engine/ui/progress/progress.gc index f478af1c0d..ffe01a1c58 100644 --- a/goal_src/jak1/engine/ui/progress/progress.gc +++ b/goal_src/jak1/engine/ui/progress/progress.gc @@ -817,6 +817,7 @@ (= a1-1 (progress-screen money)) (= a1-1 (progress-screen buzzer)) (= a1-1 (progress-screen title)) + (= a1-1 (progress-screen speedrun-options)) ) (#if (not PC_PORT) (or (= v1-2 (progress-screen settings)) @@ -840,9 +841,12 @@ (= v1-2 (progress-screen aspect-ratio)) (= v1-2 (progress-screen secrets)) (= v1-2 (progress-screen cheats)) + (= v1-2 (progress-screen checkpoint-select)) (= v1-2 (progress-screen music-player)) (= v1-2 (progress-screen flava-player)) (= v1-2 (progress-screen monitor)) + (= v1-2 (progress-screen speedrun-options)) + (= v1-2 (progress-screen speedrun-il-options)) ) ) ) @@ -1730,7 +1734,7 @@ (cond ;; Start a new game differently if speedrunning mode is active ((= (-> *pc-settings* speedrunner-mode?) #t) - (speedrun-start-run)) + (speedrun-start-full-game-run)) ;; start the game normally (else (initialize! *game-info* 'game (the-as game-save #f) "intro-start") diff --git a/goal_src/jak1/engine/ui/text-h.gc b/goal_src/jak1/engine/ui/text-h.gc index d62d32a72b..7f8642af6b 100644 --- a/goal_src/jak1/engine/ui/text-h.gc +++ b/goal_src/jak1/engine/ui/text-h.gc @@ -760,6 +760,35 @@ (hint-511 #x14ff) (speedrunner-mode #x1500) (cutscene-skips #x1501) + (checkpoint-select #x1502) + (speedrun-options-heading #x1503) + (speedrun-options-warning #x1504) + (speedrun-reset-current-run #x1505) + (speedrun-new-full-game #x1506) + ;; (speedrun-full-game-any #x1507) + ;; (speedrun-full-game-100 #x1508) + ;; (speedrun-full-game-nolts #x1509) + ;; (speedrun-full-game-nofcs #x150a) + ;; (speedrun-full-game-orbless #x150b) + ;; (speedrun-full-game-all-flies #x150c) + ;; (speedrun-full-game-all-orbs #x150d) + (speedrun-new-individual-level #x150e) + (speedrun-il-training #x150f) + (speedrun-il-village1 #x1510) + (speedrun-il-beach #x1511) + (speedrun-il-jungle #x1512) + (speedrun-il-misty #x1513) + (speedrun-il-firecanyon #x1514) + (speedrun-il-village2 #x1515) + (speedrun-il-sunken #x1516) + (speedrun-il-swamp #x1517) + (speedrun-il-rolling #x1518) + (speedrun-il-ogre #x1519) + (speedrun-il-village3 #x151a) + (speedrun-il-snow #x151b) + (speedrun-il-cave #x151c) + (speedrun-il-lavatube #x151d) + (speedrun-il-citadel #x151e) ;; GAME-TEXT-ID ENUM ENDS ) diff --git a/goal_src/jak1/game.gp b/goal_src/jak1/game.gp index 980d66a168..004914c029 100644 --- a/goal_src/jak1/game.gp +++ b/goal_src/jak1/game.gp @@ -1722,12 +1722,15 @@ (goal-src "pc/util/knuth-rand.gc" "settings-h") +(goal-src "pc/features/speedruns-h.gc") + (goal-src-sequence ;; prefix "engine/" :deps - ("$OUT/obj/settings-h.o") + ("$OUT/obj/settings-h.o" + "$OUT/obj/speedruns-h.o") "util/capture.gc" "debug/memory-usage-h.gc" @@ -2039,7 +2042,6 @@ ;; Custom or Modified Code (goal-src "pc/features/autosplit-h.gc") (goal-src "pc/features/autosplit.gc" "autosplit-h" "task-control-h") -(goal-src "pc/features/speedruns-h.gc") (goal-src "pc/features/speedruns.gc" "speedruns-h" "autosplit-h") (goal-src "pc/pckernel-h.gc" "dma-buffer") (goal-src "pc/util/pc-anim-util.gc" "target-h") diff --git a/goal_src/jak1/levels/ogre/ogreboss.gc b/goal_src/jak1/levels/ogre/ogreboss.gc index b7d0cede39..a95af1fa2e 100644 --- a/goal_src/jak1/levels/ogre/ogreboss.gc +++ b/goal_src/jak1/levels/ogre/ogreboss.gc @@ -1153,7 +1153,9 @@ (defstate ogreboss-intro (ogreboss) :code (behavior () - (when (zero? (-> self try-count)) + (when (and (zero? (-> self try-count)) + (not (and PC_PORT (is-speedrun-category? 'il-ogre))) ;; modified for PC port - skip cutscene in Mountain Pass IL speedrun + ) (process-drawable-delay-player (seconds 1)) (let ((gp-0 (get-process *default-dead-pool* pov-camera #x4000))) (ppointer->handle (when gp-0 diff --git a/goal_src/jak1/pc/features/speedruns-h.gc b/goal_src/jak1/pc/features/speedruns-h.gc index 15c9bc1c43..e60ddf4172 100644 --- a/goal_src/jak1/pc/features/speedruns-h.gc +++ b/goal_src/jak1/pc/features/speedruns-h.gc @@ -1,7 +1,52 @@ ;;-*-Lisp-*- (in-package goal) -(define-extern speedrun-mode-update (function none)) -(define-extern speedrun-start-run (function none)) -(define-extern speedrun-draw-settings (function none)) +(defenum speedrun-category + :type uint32 + ;; Main Categories + (full-game 0) ;; Full game run (any category for now, can repurpose as Any% if we split them out later) + ;; (full-game-100 1) ;; 100% + ;; (full-game-noLTS 2) ;; No Lava Tube skip + ;; (full-game-noFCS 3) ;; No Fire Canyon skip + ;; (full-game-orbless 4) ;; Orbless + ;; (full-game-all-flies 5) ;; All Flies + ;; (full-game-all-orbs 6) ;; All Orbs + + ;; Individual Levels + (il-training 100) ;; Geyser Rock IL + (il-village1 101) ;; Sandover Village IL + (il-beach 102) ;; Sentinel Beach IL + (il-jungle 103) ;; Forbidden Jungle IL + (il-misty 104) ;; Misty Island IL + (il-firecanyon 105) ;; Fire Canyon IL + (il-village2 106) ;; Rock Village IL + (il-sunken 107) ;; Lost Precursor City IL + (il-swamp 108) ;; Boggy Swamp IL + (il-rolling 109) ;; Precursor Basin IL + (il-ogre 110) ;; Mountain Pass IL + (il-village3 111) ;; Volcanic Crater IL + (il-snow 112) ;; Snowy Mountain IL + (il-cave 113) ;; Spider Cave IL + (il-lavatube 114) ;; Lava Tube IL + (il-citadel 115) ;; Gol and Maia's Citadel IL + + ;; Extension Categories (TBD) + ) + + +(deftype speedrun-info-jak1 (structure) + ( + (category speedrun-category) + (needs-post-blackout-setup? symbol) + (should-display? symbol) + ) + ) + +(define-extern start-speedrun (function speedrun-category none)) +(define-extern is-speedrun-category? (function symbol symbol)) +(define-extern hide-speedrun-display (function none)) +(define-extern speedrun-start-full-game-run (function none)) +(define-extern setup-speedrun-post-blackout (function none)) +(define-extern speedrun-mode-update (function none)) +(define-extern speedrun-draw-settings (function none)) diff --git a/goal_src/jak1/pc/features/speedruns.gc b/goal_src/jak1/pc/features/speedruns.gc index a871177baa..a31f727490 100644 --- a/goal_src/jak1/pc/features/speedruns.gc +++ b/goal_src/jak1/pc/features/speedruns.gc @@ -1,41 +1,258 @@ ;;-*-Lisp-*- (in-package goal) +(define *speedrun-info* (new 'static 'speedrun-info-jak1 :should-display? #t :needs-post-blackout-setup? #f)) + +(defun is-speedrun-category? ((category symbol)) + (and (-> *pc-settings* speedrunner-mode?) + (name= category (enum->string speedrun-category (-> *speedrun-info* category))) + ) + ) + +(defun start-speedrun ((category speedrun-category)) + ;; randomize game id so the autosplitter knows to restart + (update-autosplit-jak1-new-game) + ;; disable hints + (set! (-> *setting-control* default play-hints) #f) + ;; 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) + (if category + (set! (-> *speedrun-info* category) category) + ) + (case (-> *speedrun-info* category) + (((speedrun-category full-game)) + ;; spawn at the warp gate checkpoint + (initialize! *game-info* 'game (the-as game-save #f) "game-start") + ) + (((speedrun-category il-training)) + ;; spawn at the warp gate checkpoint + (initialize! *game-info* 'game (the-as game-save #f) "game-start") + ) + (((speedrun-category il-village1)) + ;; spawn at the green sage hut warp gate + (initialize! *game-info* 'game (the-as game-save #f) "village1-warp") + ) + (((speedrun-category il-beach)) + ;; spawn at beach + (initialize! *game-info* 'game (the-as game-save #f) "beach-start") + ) + (((speedrun-category il-jungle)) + ;; spawn at start of FJ + (initialize! *game-info* 'game (the-as game-save #f) "jungle-start") + ) + (((speedrun-category il-misty)) + ;; spawn at start of misty + (initialize! *game-info* 'game (the-as game-save #f) "misty-start") + ) + (((speedrun-category il-firecanyon)) + ;; spawn at start of fire canyon + (initialize! *game-info* 'game (the-as game-save #f) "firecanyon-start") + ) + (((speedrun-category il-village2)) + ;; spawn at rock village start + (initialize! *game-info* 'game (the-as game-save #f) "village2-start") + ) + (((speedrun-category il-sunken)) + ;; spawn at start of LPC + (initialize! *game-info* 'game (the-as game-save #f) "sunken-start") + ) + (((speedrun-category il-swamp)) + ;; spawn at start of boggy + (initialize! *game-info* 'game (the-as game-save #f) "swamp-start") + ) + (((speedrun-category il-rolling)) + ;; spawn at start of basin + (initialize! *game-info* 'game (the-as game-save #f) "rolling-start") + ) + (((speedrun-category il-ogre)) + ;; spawn before klaww + (initialize! *game-info* 'game (the-as game-save #f) "ogre-start") + ) + (((speedrun-category il-village3)) + ;; spawn at start of volcanic crater + (initialize! *game-info* 'game (the-as game-save #f) "village3-start") + ) + (((speedrun-category il-snow)) + ;; spawn at start of snowy + (initialize! *game-info* 'game (the-as game-save #f) "snow-start") + ) + (((speedrun-category il-cave)) + ;; spawn at start of spider cave + (initialize! *game-info* 'game (the-as game-save #f) "maincave-start") + ) + (((speedrun-category il-lavatube)) + ;; spawn at start of lava tube + (initialize! *game-info* 'game (the-as game-save #f) "lavatube-start") + ) + (((speedrun-category il-citadel)) + ;; spawn outside first citadel door + (initialize! *game-info* 'game (the-as game-save #f) "citadel-entrance") + ) + ) + ;; ensure `force actors` is not enabled + (set! (-> *pc-settings* force-actors?) #f) + ;; force FPS to `60` + (set-frame-rate! *pc-settings* 60) + ;; enable auto saving by default + (set! (-> *setting-control* default auto-save) #t) + (none) + ) + +(defun setup-speedrun-post-blackout () + (when (and (-> *speedrun-info* needs-post-blackout-setup?) (>= (-> *display* base-frame-counter) (-> *game-info* blackout-time))) + (set! (-> *speedrun-info* needs-post-blackout-setup?) #f) + (case (-> *speedrun-info* category) + (((speedrun-category full-game)) + ;; skip intro cutscene + (close-specific-task! (game-task intro) (task-status need-resolution)) + ) + (((speedrun-category il-training)) + ;; skip intro cutscene + (close-specific-task! (game-task intro) (task-status need-resolution)) + (mark-text-as-seen *game-info* (game-text-id training-level-name)) + ) + (((speedrun-category il-village1)) + ;; give enough orbs to buy all cells 120+120+90+90=420 + (set! (-> *game-info* money-total) 420.0) + (set! (-> *game-info* money) 420.0) + (mark-text-as-seen *game-info* (game-text-id village1-level-name)) + ) + (((speedrun-category il-beach)) + ;; unlock blue eco vent + (close-specific-task! (game-task jungle-eggtop) (task-status need-resolution)) + (send-event *target* 'get-pickup (pickup-type fuel-cell) (the float (game-task jungle-eggtop))) + (mark-text-as-seen *game-info* (game-text-id beach-level-name)) + ) + (((speedrun-category il-jungle)) + (mark-text-as-seen *game-info* (game-text-id jungle-level-name)) + ) + (((speedrun-category il-misty)) + ;; unlock fisherman's boat + (close-specific-task! (game-task jungle-fishgame) (task-status need-resolution)) + (send-event *target* 'get-pickup (pickup-type fuel-cell) (the float (game-task jungle-fishgame))) + (mark-text-as-seen *game-info* (game-text-id misty-level-name)) + ) + (((speedrun-category il-firecanyon)) + ;; skip keira intro cutscene + (close-specific-task! (game-task firecanyon-assistant) (task-status need-reward-speech)) + ;; unlock blue eco vent + (close-specific-task! (game-task jungle-eggtop) (task-status need-resolution)) + (send-event *target* 'get-pickup (pickup-type fuel-cell) (the float (game-task jungle-eggtop))) + (mark-text-as-seen *game-info* (game-text-id firecanyon-level-name)) + ) + (((speedrun-category il-village2)) + ;; give enough orbs to buy all cells 120+120+90+90+90=510 + (set! (-> *game-info* money-total) 510.0) + (set! (-> *game-info* money) 510.0) + ) + (((speedrun-category il-sunken)) + (mark-text-as-seen *game-info* (game-text-id sunken-level-name)) + ) + (((speedrun-category il-swamp)) + ;; unlock flutflut + (close-specific-task! (game-task beach-flutflut) (task-status need-resolution)) + (close-specific-task! (game-task village2-levitator) (task-status need-introduction)) + (send-event *target* 'get-pickup (pickup-type fuel-cell) (the float (game-task beach-flutflut))) + (mark-text-as-seen *game-info* (game-text-id swamp-level-name)) + ) + (((speedrun-category il-rolling)) + ;; unlock zoomer + (close-specific-task! (game-task village2-levitator) (task-status need-introduction)) + ;; unlock DMG + (close-specific-task! (game-task rolling-race) (task-status need-introduction)) + ;; unlock moles + (close-specific-task! (game-task rolling-moles) (task-status need-introduction)) + (mark-text-as-seen *game-info* (game-text-id rolling-level-name)) + ) + (((speedrun-category il-ogre)) + ;; skip klaww intro cutscene + (close-specific-task! (game-task ogre-boss) (task-status need-hint)) + ;; unlock yellow eco vent + (close-specific-task! (game-task snow-eggtop) (task-status need-resolution)) + (send-event *target* 'get-pickup (pickup-type fuel-cell) (the float (game-task snow-eggtop))) + (mark-text-as-seen *game-info* (game-text-id ogre-level-name)) + ) + (((speedrun-category il-village3)) + ;; give enough orbs to buy all cells 120+120+90+90+90+90=600 + (set! (-> *game-info* money-total) 600.0) + (set! (-> *game-info* money) 600.0) + (mark-text-as-seen *game-info* (game-text-id village3-level-name)) + ) + (((speedrun-category il-snow)) + ;; unlock flutflut + (close-specific-task! (game-task beach-flutflut) (task-status need-resolution)) + (send-event *target* 'get-pickup (pickup-type fuel-cell) (the float (game-task beach-flutflut))) + ;; unlock gondola + (close-specific-task! (game-task village3-button) (task-status need-introduction)) + (mark-text-as-seen *game-info* (game-text-id snow-level-name)) + ) + (((speedrun-category il-cave)) + ;; unlock yellow eco vent + (close-specific-task! (game-task snow-eggtop) (task-status need-resolution)) + (send-event *target* 'get-pickup (pickup-type fuel-cell) (the float (game-task snow-eggtop))) + (mark-text-as-seen *game-info* (game-text-id cave-level-name)) + ) + (((speedrun-category il-lavatube)) + ;; skip keira intro cutscene + (close-specific-task! (game-task lavatube-start) (task-status need-reward-speech)) + (mark-text-as-seen *game-info* (game-text-id lavatube-level-name)) + ) + (((speedrun-category il-citadel)) + ;; remove invisible wall + (close-specific-task! (game-task lavatube-end) (task-status need-resolution)) + (send-event *target* 'get-pickup (pickup-type fuel-cell) (the float (game-task lavatube-end))) + ;; unlock door + (close-specific-task! (game-task village4-button) (task-status need-reward-speech)) + (mark-text-as-seen *game-info* (game-text-id citadel-level-name)) + ) + ) + ;; reset speedrun display (gets hidden on first collectable pickup) + (set! (-> *speedrun-info* should-display?) #t) + ;; reset actors to ensure any above changes take effect + (reset-actors 'life) + ;; autosave any changes back to file + (auto-save-command 'auto-save 0 0 *default-pool*) + ) + (none) + ) + +(defun hide-speedrun-display () + (set! (-> *speedrun-info* should-display?) #f) + (none) + ) + (defun speedrun-mode-update () "A per frame update for speedrunning related stuff" (when (-> *pc-settings* speedrunner-mode?) ;; Update auto-splitter (update-autosplit-info-jak1) ;; Draw info to the screen - (speedrun-draw-settings)) + (speedrun-draw-settings) + ;;Disable any active cheats + (set! (-> *pc-settings* cheats) (the-as pc-cheats #x0)) + ;; Run after-blackout speedrun setup (if needed) + (setup-speedrun-post-blackout) + ) (none)) -(defun speedrun-start-run () - ;; randomize game id so the autosplitter knows to restart - (update-autosplit-jak1-new-game) - ;; spawn at the warp gate checkpoint - (initialize! *game-info* 'game (the-as game-save #f) "game-start") - ;; disable hints (this seems to be overriden by your slot 1 save though) - (set! (-> *setting-control* default play-hints) #f) - ;; ensure `force actors` is not enabled - (set! (-> *pc-settings* force-actors?) #f) - ;; force FPS to `60` - (set-frame-rate! *pc-settings* 60) - ;; skip intro cutscene - (close-specific-task! (game-task intro) (task-status need-resolution)) - ;; enable auto saving by default - (set! (-> *setting-control* default auto-save) #t) +(defun speedrun-start-full-game-run () + ;; start a full game speedrun, save file is already selected so don't default to first slot + (start-speedrun (speedrun-category full-game)) (none)) (defun speedrun-draw-settings () "Draw speedrun related settings in the bottom left corner" (when (and (-> *pc-settings* speedrunner-mode?) - (< (-> *autosplit-info-jak1* num-power-cells) 1)) + (not (paused?)) + (-> *speedrun-info* should-display?)) (with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) (bucket-id debug-no-zbuf)) - (draw-string-xy (string-format "OpenGOAL Version: ~S ~%Speedrun mode: ~A ~%Cutscene Skips ~A" + (draw-string-xy (string-format "OpenGOAL Version: ~S ~%Speedrun mode: ~A ~%Category: ~S ~%Cutscene Skips ~A" *pc-settings-built-sha* (-> *pc-settings* speedrunner-mode?) + (enum->string speedrun-category (-> *speedrun-info* category)) (-> *pc-settings* skip-movies?)) - buf 0 (- 224 (* 8 4)) (font-color flat-yellow) (font-flags shadow kerning)))) + buf 0 (- 220 (* 8 4)) (font-color flat-yellow) (font-flags shadow kerning)))) (none)) diff --git a/goal_src/jak1/pc/progress-pc.gc b/goal_src/jak1/pc/progress-pc.gc index ced647a1cc..65d551ac7f 100644 --- a/goal_src/jak1/pc/progress-pc.gc +++ b/goal_src/jak1/pc/progress-pc.gc @@ -50,6 +50,12 @@ (set! (-> *progress-scroll* transition) 0.0) (set! (-> *progress-scroll* direction) PROGRESS_SCROLL_DIR_DOWN) (1+! (-> *progress-scroll* start-index)))) +(defun progress-fast-save-and-start-speedrun ((category speedrun-category)) + "saves to first slot, updates last-slot-saved for cursor, then starts speedrun" + (set! (-> *progress-state* last-slot-saved) 0) + (auto-save-command 'save 0 0 *default-pool*) + (start-speedrun category) + ) ;; used in title logo @@ -230,6 +236,37 @@ ) ) +(define *speedrun-options* + (new 'static 'boxed-array :type game-option + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-reset-current-run) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-new-full-game) :scale #t) + (new 'static 'game-option :option-type (game-option-type menu) :name (game-text-id speedrun-new-individual-level) :scale #t :param3 (game-option-menu speedrun-il-options)) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id back) :scale #t) + ) + ) + +(define *speedrun-il-options* + (new 'static 'boxed-array :type game-option + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-training) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-village1) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-beach) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-jungle) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-misty) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-firecanyon) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-village2) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-sunken) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-swamp) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-rolling) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-ogre) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-village3) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-snow) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-cave) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-lavatube) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id speedrun-il-citadel) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id back) :scale #t) + ) + ) + (define *secrets-title* (new 'static 'boxed-array :type game-option (new 'static 'game-option :option-type (game-option-type menu) :name (game-text-id music-player) :scale #t :param3 (game-option-menu music-player)) (new 'static 'game-option :option-type (game-option-type menu) :name (game-text-id cheats) :scale #t :param3 (game-option-menu cheats)) @@ -239,6 +276,31 @@ (define *secrets* (new 'static 'boxed-array :type game-option (new 'static 'game-option :option-type (game-option-type menu) :name (game-text-id cheats) :scale #t :param3 (game-option-menu cheats)) + (new 'static 'game-option :option-type (game-option-type menu) :name (game-text-id checkpoint-select) :scale #t :param3 (game-option-menu checkpoint-select) + :option-disabled-func (lambda () (not (task-closed? (game-task finalboss-movies) (task-status need-reminder))))) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id back) :scale #t) + ) + ) + +(define *checkpoint-select-options* + (new 'static 'boxed-array :type game-option + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id training-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id village1-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id beach-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id jungle-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id misty-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id firecanyon-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id village2-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id sunken-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id swamp-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id rolling-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id ogre-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id village3-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id snow-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id cave-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id lavatube-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id citadel-level-name) :scale #t) + (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id finalboss-level-name) :scale #t) (new 'static 'game-option :option-type (game-option-type button) :name (game-text-id back) :scale #t) ) ) @@ -713,11 +775,15 @@ (set! (-> *options-remap* (progress-screen quit-title)) *yes-no-options*) (set! (-> *options-remap* (progress-screen secrets)) *secrets-title*) (set! (-> *options-remap* (progress-screen cheats)) *cheats*) + (set! (-> *options-remap* (progress-screen checkpoint-select)) *checkpoint-select-options*) (set! (-> *options-remap* (progress-screen music-player)) *music-player-options*) (set! (-> *options-remap* (progress-screen flava-player)) *temp-options*) (set! (-> *options-remap* (progress-screen memcard-disable-auto-save)) *yes-no-options*) (set! (-> *options-remap* (progress-screen memcard-auto-save-disabled)) *ok-options*) (set! (-> *options-remap* (progress-screen monitor)) *temp-options*) + (set! (-> *options-remap* (progress-screen speedrun-options)) *speedrun-options*) + (set! (-> *options-remap* (progress-screen speedrun-il-options)) *speedrun-il-options*) + ;; set default params (set! (-> *progress-state* aspect-ratio-choice) (get-aspect-ratio)) @@ -1182,6 +1248,133 @@ (reset-original-camera *pc-settings*) (sound-play "cursor-options") ) + ;; LEVEL SELECT + (((game-text-id training-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "game-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id village1-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "village1-warp")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id beach-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "beach-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id jungle-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "jungle-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id misty-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "misty-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id firecanyon-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "firecanyon-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id village2-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "village2-warp")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id sunken-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "sunken-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id swamp-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "swamp-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id rolling-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "rolling-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id ogre-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "ogre-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id village3-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "village3-warp")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id snow-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "snow-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id cave-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "maincave-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id lavatube-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "lavatube-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id citadel-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "citadel-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + (((game-text-id finalboss-level-name)) + (set! (-> *game-info* current-continue) (get-continue-by-name *game-info* "finalboss-start")) + (initialize! *game-info* 'die (the-as game-save #f) (the-as string #f)) + ) + ;; SPEEDRUNS + ;; Restart current run + (((game-text-id speedrun-reset-current-run)) + (progress-fast-save-and-start-speedrun (the-as speedrun-category #f)) + ) + ;; Full game runs + (((game-text-id speedrun-new-full-game)) + (progress-fast-save-and-start-speedrun (speedrun-category full-game)) + ) + ;; Individual Levels + (((game-text-id speedrun-il-training)) + (progress-fast-save-and-start-speedrun (speedrun-category il-training)) + ) + (((game-text-id speedrun-il-village1)) + (progress-fast-save-and-start-speedrun (speedrun-category il-village1)) + ) + (((game-text-id speedrun-il-beach)) + (progress-fast-save-and-start-speedrun (speedrun-category il-beach)) + ) + (((game-text-id speedrun-il-jungle)) + (progress-fast-save-and-start-speedrun (speedrun-category il-jungle)) + ) + (((game-text-id speedrun-il-misty)) + (progress-fast-save-and-start-speedrun (speedrun-category il-misty)) + ) + (((game-text-id speedrun-il-firecanyon)) + (progress-fast-save-and-start-speedrun (speedrun-category il-firecanyon)) + ) + (((game-text-id speedrun-il-village2)) + (progress-fast-save-and-start-speedrun (speedrun-category il-village2)) + ) + (((game-text-id speedrun-il-sunken)) + (progress-fast-save-and-start-speedrun (speedrun-category il-sunken)) + ) + (((game-text-id speedrun-il-swamp)) + (progress-fast-save-and-start-speedrun (speedrun-category il-swamp)) + ) + (((game-text-id speedrun-il-rolling)) + (progress-fast-save-and-start-speedrun (speedrun-category il-rolling)) + ) + (((game-text-id speedrun-il-ogre)) + (progress-fast-save-and-start-speedrun (speedrun-category il-ogre)) + ) + (((game-text-id speedrun-il-village3)) + (progress-fast-save-and-start-speedrun (speedrun-category il-village3)) + ) + (((game-text-id speedrun-il-snow)) + (progress-fast-save-and-start-speedrun (speedrun-category il-snow)) + ) + (((game-text-id speedrun-il-cave)) + (progress-fast-save-and-start-speedrun (speedrun-category il-cave)) + ) + (((game-text-id speedrun-il-lavatube)) + (progress-fast-save-and-start-speedrun (speedrun-category il-lavatube)) + ) + (((game-text-id speedrun-il-citadel)) + (progress-fast-save-and-start-speedrun (speedrun-category il-citadel)) + ) ) (commit-to-file *pc-settings*) ;; other behaviors are hardcoded elsewhere because screw you. @@ -1552,7 +1745,7 @@ (set! (-> *game-info* mode) 'play) ;; Start a new game differently if speedrunning mode is active (cond ((-> *pc-settings* speedrunner-mode?) - (speedrun-start-run)) + (speedrun-start-full-game-run)) ;; start the game normally (else (initialize! *game-info* 'game (the-as game-save #f) "intro-start"))) @@ -1571,7 +1764,7 @@ (set! (-> *game-info* mode) 'play) ;; Start a new game differently if speedrunning mode is active (cond ((-> *pc-settings* speedrunner-mode?) - (speedrun-start-run)) + (speedrun-start-full-game-run)) ;; start the game normally (else (initialize! *game-info* 'game (the-as game-save #f) "intro-start"))) @@ -1660,7 +1853,7 @@ (set! (-> *game-info* mode) 'play) ;; Start a new game differently if speedrunning mode is active (cond ((-> *pc-settings* speedrunner-mode?) - (speedrun-start-run)) + (speedrun-start-full-game-run)) ;; start the game normally (else (initialize! *game-info* 'game (the-as game-save #f) "intro-start"))) @@ -1787,10 +1980,16 @@ (set! option-str (lookup-text! *common-text* (-> options index name) #f)) (set! option-str #f) ) + ;; if autosave disabled, update text and lock it (when (and (not (-> *setting-control* default auto-save)) (= (game-text-id disable-auto-save) (-> options index name))) (set! option-str (lookup-text! *common-text* (game-text-id auto-save-disabled) #f)) (true! locked?)) + ;; checkpoint-select only unlocked after beating finalboss + (when (and (not (task-closed? (game-task finalboss-movies) (task-status need-reminder))) + (= (game-text-id checkpoint-select) (-> options index name))) + (set! option-str (lookup-text! *common-text* (game-text-id cheat-req-beat-game) #f)) + (true! locked?)) ) (((game-option-type button-music)) ;; a button for the music player. has the text "locked" sometimes! @@ -2098,6 +2297,24 @@ ) +(defun draw-memcard-speedrun-options ((obj progress) (arg0 font-context)) + (set-scale! arg0 0.85) + (set-flags! arg0 (font-flags shadow kerning middle left large)) + (set-origin! arg0 (- 20 (-> obj left-x-offset)) 30) + (set-width! arg0 360) + (set-color! arg0 (font-color lighter-lighter-blue)) + (set-height! arg0 20) + (print-game-text-scaled (lookup-text! *common-text* (game-text-id speedrun-options-heading) #f) + (-> obj transition-percentage-invert) arg0 128) + (set-scale! arg0 0.6) + (set-flags! arg0 (font-flags shadow kerning middle left large)) + (set-origin! arg0 (- 20 (-> obj left-x-offset)) 60) + (set-width! arg0 360) + (set-height! arg0 20) + (set-color! arg0 (font-color yellow-orange)) + (print-game-text-scaled (lookup-text! *common-text* (game-text-id speedrun-options-warning) #f) + (-> obj transition-percentage-invert) arg0 128) + 0) (defun draw-memcard-auto-save-disabled ((obj progress) (arg0 font-context)) (set-scale! arg0 0.6) @@ -2202,6 +2419,9 @@ (((progress-screen memcard-auto-save-disabled)) (draw-memcard-auto-save-disabled obj a1-1) ) + (((progress-screen speedrun-options)) + (draw-memcard-speedrun-options obj a1-1) + ) ) ) ) @@ -2272,7 +2492,12 @@ (hide-progress-icons) (draw-options self 128 21 0.82) ) - (((progress-screen camera-options)) + (((progress-screen speedrun-options)) + (hide-progress-icons) + (draw-notice-screen self) + (draw-options self 155 25 0.65) + ) + (((progress-screen camera-options) (progress-screen checkpoint-select) (progress-screen speedrun-il-options)) ;; camera options lines are a bit too big (hide-progress-icons) (draw-options self 115 25 0.65) @@ -2415,7 +2640,7 @@ ) (let ((gp-0 (-> *level-task-data* (-> self display-level-index) task-info (-> self task-index) task-id))) (close-specific-task! gp-0 (task-status need-resolution)) - (send-event *target* 'get-pickup 6 (the float gp-0)) + (send-event *target* 'get-pickup (pickup-type fuel-cell) (the float gp-0)) ) ) )