From 9bed69353320edd4d48b6070e4b7c9a4d81f20ea Mon Sep 17 00:00:00 2001 From: ZedB0T <89345505+Zedb0T@users.noreply.github.com> Date: Sun, 30 Apr 2023 17:38:05 -0400 Subject: [PATCH] Initial Jak 2 Autosplit Support (#2239) Co-authored-by: Tyler Wilding Co-authored-by: Tyler Wilding --- game/kernel/jak2/kmachine.cpp | 8 ++ game/kernel/jak2/kmachine.h | 9 ++ goal_src/jak1/pc/features/autosplit-h.gc | 9 +- goal_src/jak1/pc/features/autosplit.gc | 3 + goal_src/jak1/pc/pckernel-h.gc | 4 +- goal_src/jak1/pc/pckernel.gc | 9 +- goal_src/jak2/dgos/engine.gd | 4 + goal_src/jak2/dgos/game.gd | 4 + goal_src/jak2/game.gp | 1 + goal_src/jak2/kernel-defs.gc | 3 +- goal_src/jak2/pc/features/autosplit-h.gc | 134 ++++++++++++++++++++++ goal_src/jak2/pc/features/autosplit.gc | 138 +++++++++++++++++++++++ goal_src/jak2/pc/features/speedruns-h.gc | 36 ++++++ goal_src/jak2/pc/features/speedruns.gc | 86 ++++++++++++++ goal_src/jak2/pc/pckernel.gc | 14 +-- 15 files changed, 439 insertions(+), 23 deletions(-) create mode 100644 goal_src/jak2/pc/features/autosplit-h.gc create mode 100644 goal_src/jak2/pc/features/autosplit.gc create mode 100644 goal_src/jak2/pc/features/speedruns-h.gc create mode 100644 goal_src/jak2/pc/features/speedruns.gc diff --git a/game/kernel/jak2/kmachine.cpp b/game/kernel/jak2/kmachine.cpp index c746c92ccf..34e701562b 100644 --- a/game/kernel/jak2/kmachine.cpp +++ b/game/kernel/jak2/kmachine.cpp @@ -355,6 +355,7 @@ void InitIOP() { } printf("InitIOP OK\n"); } +AutoSplitterBlock gAutoSplitterBlock; int InitMachine() { // heap_start = malloc(0x10); @@ -615,6 +616,11 @@ void set_fullscreen(u32 symptr, s64 screen) { } } +void init_autosplit_struct() { + gAutoSplitterBlock.pointer_to_symbol = + (u64)g_ee_main_mem + (u64)intern_from_c("*autosplit-info-jak2*")->value(); +} + void InitMachine_PCPort() { // PC Port added functions @@ -626,6 +632,8 @@ void InitMachine_PCPort() { make_function_symbol_from_c("__pc-get-mips2c", (void*)pc_get_mips2c); make_function_symbol_from_c("__pc-set-levels", (void*)pc_set_levels); make_function_symbol_from_c("__pc-get-tex-remap", (void*)lookup_jak2_texture_dest_offset); + make_function_symbol_from_c("pc-get-unix-timestamp", (void*)get_unix_timestamp); + make_function_symbol_from_c("pc-init-autosplitter-struct", (void*)init_autosplit_struct); // pad stuff make_function_symbol_from_c("pc-pad-get-mapped-button", (void*)Gfx::get_mapped_button); diff --git a/game/kernel/jak2/kmachine.h b/game/kernel/jak2/kmachine.h index 5ae15502ae..a8170e9981 100644 --- a/game/kernel/jak2/kmachine.h +++ b/game/kernel/jak2/kmachine.h @@ -63,5 +63,14 @@ struct DiscordInfo { u32 time_of_day; // (pointer float float percent_completed; // float }; +// To speedup finding the auto-splitter block in GOAL memory +// all this has is a marker for LiveSplit to find, and then the pointer +// to the symbol +struct AutoSplitterBlock { + const char marker[20] = "UnLiStEdStRaTs_JaK2"; + u64 pointer_to_symbol = 0; +}; + +extern AutoSplitterBlock gAutoSplitterBlock; } // namespace jak2 diff --git a/goal_src/jak1/pc/features/autosplit-h.gc b/goal_src/jak1/pc/features/autosplit-h.gc index 9d9b05e1f6..6a44b53aa1 100644 --- a/goal_src/jak1/pc/features/autosplit-h.gc +++ b/goal_src/jak1/pc/features/autosplit-h.gc @@ -45,7 +45,10 @@ (cave-num-scout-flies uint8) (lavatube-num-scout-flies uint8) (citadel-num-scout-flies uint8) - (padding-stats uint8 168) ;; padding for future growth + ;; Version Info (it's so far down because it was an after thought!) + (version-major uint16) + (version-minor uint16) + (padding-stats uint8 164) ;; padding for future growth ;; loading/cutscene/control related info (game-hash uint32) (in-cutscene? symbol) @@ -164,10 +167,6 @@ ;; end marker just to make things look nice in a memory view (end-marker uint8 4))) -(defmacro autosplit-flag-task-complete! (field-name task-name) - "Given a field name in the autosplitter struct, and a [[game-task]] name to check, sets either a 0 or a 1" - `(set! (-> *autosplit-info-jak1* ,field-name) (if (task-complete? *game-info* (game-task ,task-name)) 1 0))) - (define-extern *autosplit-info-jak1* autosplit-info-jak1) (define-extern update-autosplit-info-jak1 (function none)) (define-extern update-autosplit-jak1-new-game (function none)) diff --git a/goal_src/jak1/pc/features/autosplit.gc b/goal_src/jak1/pc/features/autosplit.gc index c4e3e9dcb0..4be7cf9613 100644 --- a/goal_src/jak1/pc/features/autosplit.gc +++ b/goal_src/jak1/pc/features/autosplit.gc @@ -8,6 +8,9 @@ (charp<-string (-> *autosplit-info-jak1* padding-stats) "padding-stats!") (charp<-string (-> *autosplit-info-jak1* padding-controls) "padding-controls!") +(defmacro autosplit-flag-task-complete! (field-name task-name) + "Given a field name in the autosplitter struct, and a [[game-task]] name to check, sets either a 0 or a 1" + `(set! (-> *autosplit-info-jak1* ,field-name) (if (task-complete? *game-info* (game-task ,task-name)) 1 0))) (defun update-autosplit-info-jak1 () ;; general statistics diff --git a/goal_src/jak1/pc/pckernel-h.gc b/goal_src/jak1/pc/pckernel-h.gc index 7c226265d6..e7ff7c5067 100644 --- a/goal_src/jak1/pc/pckernel-h.gc +++ b/goal_src/jak1/pc/pckernel-h.gc @@ -318,8 +318,8 @@ (update (_type_) none) (update-from-os (_type_) none) (update-to-os (_type_) none) - (update-discord-rpc (_type_) object) - (update-speedrun (_type_) object) + (update-discord-rpc (_type_) none) + (update-speedrun (_type_) none) (update-video-hacks (_type_) object) (reset (_type_) none) (reset-audio (_type_) none) diff --git a/goal_src/jak1/pc/pckernel.gc b/goal_src/jak1/pc/pckernel.gc index e09105870f..9d69c5a708 100644 --- a/goal_src/jak1/pc/pckernel.gc +++ b/goal_src/jak1/pc/pckernel.gc @@ -238,7 +238,6 @@ (defmethod update-discord-rpc pc-settings-jak1 ((obj pc-settings-jak1)) "update discord rpc module" - (let ((info (new 'stack 'discord-info))) (set! (-> info fuel) (&-> *game-info* fuel)) (set! (-> info money-total) (&-> *game-info* money-total)) @@ -288,16 +287,14 @@ 'target-flut-walk) #t)))) (set! (-> info time-of-day) (&-> *time-of-day-context* time)) - (with-profiler "discord-update" (pc-discord-rpc-update info)) - ) - 0) + (with-profiler "discord-update" (pc-discord-rpc-update info))) + (none)) (defmethod update-speedrun pc-settings-jak1 ((obj pc-settings-jak1)) "update speedrun module" - (with-profiler "speedrun-update-jak1" (speedrun-mode-update)) - 0) + (none)) (defmethod update-video-hacks pc-settings-jak1 ((obj pc-settings-jak1)) "update the graphics hacks used for sprites and other things. ugh." diff --git a/goal_src/jak2/dgos/engine.gd b/goal_src/jak2/dgos/engine.gd index b3171382a8..e4f2ebe108 100644 --- a/goal_src/jak2/dgos/engine.gd +++ b/goal_src/jak2/dgos/engine.gd @@ -234,6 +234,10 @@ "game-task.o" "game-save.o" "settings.o" + "autosplit-h.o" ;; added + "autosplit.o" ;; added + "speedruns-h.o" ;; added + "speedruns.o" ;; added "mood-tables.o" "mood-tables2.o" "mood.o" diff --git a/goal_src/jak2/dgos/game.gd b/goal_src/jak2/dgos/game.gd index 2e2f7fdab1..c2f7ba2163 100644 --- a/goal_src/jak2/dgos/game.gd +++ b/goal_src/jak2/dgos/game.gd @@ -234,6 +234,10 @@ "game-task.o" "game-save.o" "settings.o" + "autosplit-h.o" ;; added + "autosplit.o" ;; added + "speedruns-h.o" ;; added + "speedruns.o" ;; added "mood-tables.o" "mood-tables2.o" "mood.o" diff --git a/goal_src/jak2/game.gp b/goal_src/jak2/game.gp index 3698b3e4e8..2433540a08 100644 --- a/goal_src/jak2/game.gp +++ b/goal_src/jak2/game.gp @@ -369,3 +369,4 @@ "$OUT/iso/KERNEL.CGO" "$OUT/iso/GAME.CGO" ) + diff --git a/goal_src/jak2/kernel-defs.gc b/goal_src/jak2/kernel-defs.gc index 06664ce2b8..b714717dca 100644 --- a/goal_src/jak2/kernel-defs.gc +++ b/goal_src/jak2/kernel-defs.gc @@ -184,6 +184,7 @@ (declare-type discord-info structure) (define-extern pc-discord-rpc-update (function discord-info none)) (define-extern pc-discord-rpc-set (function int none)) +(define-extern pc-init-autosplitter-struct (function none)) (define-extern pc-filepath-exists? (function string symbol)) (define-extern pc-mkdir-file-path (function string none)) (define-extern pc-sound-set-flava-hack (function int none)) @@ -219,6 +220,7 @@ (define-extern rpc-busy? (function int uint)) (define-extern rpc-call (function int uint uint uint int uint int uint)) (define-extern string->symbol (function string symbol)) +(define-extern pc-get-unix-timestamp (function int)) (define-extern link-begin (function pointer (pointer uint8) int kheap link-flag int)) (define-extern link-reset (function none)) @@ -286,4 +288,3 @@ (define-extern *pc-settings-folder* string) (define-extern *pc-settings-built-sha* string) - diff --git a/goal_src/jak2/pc/features/autosplit-h.gc b/goal_src/jak2/pc/features/autosplit-h.gc new file mode 100644 index 0000000000..88f5c993d0 --- /dev/null +++ b/goal_src/jak2/pc/features/autosplit-h.gc @@ -0,0 +1,134 @@ +;;-*-Lisp-*- +(in-package goal) + +;; LiveSplit ASL requires all settings to initalized _before_ you connect the process +;; Therefore everything has to be laid out in a predictable fashion before hand +;; So this is a lot of hard-coding, but not too bad when just copied from the debug menu code +;; +;; DO NOT change the order, appending to the end is safe! + +(deftype autosplit-info-jak2 (structure) + (;; Version Info + (version-major uint16) + (version-minor uint16) + ;; General stats + (num-orbs uint32) + (num-skullgems uint32) + (padding-stats uint8 200) ;; padding for future growth + ;; loading/cutscene/control related info + (game-hash uint32) + (in-cutscene? uint8) + (is-loading? uint8) + (padding-controls uint8 200) ;; padding for future growth + ;; need-resolution tasks + (res-fortress-escape uint8) + (res-city-help-kid uint8) + (res-city-vehicle-training uint8) + (res-ruins-tower uint8) + (res-atoll-water uint8) + (res-fortress-dump uint8) + (res-city-krew-delivery uint8) + (res-city-red-gun-training uint8) + (res-atoll-sig uint8) + (res-sewer-enemy uint8) + (res-strip-rescue uint8) + (res-atoll-battle uint8) + (res-mountain-lens uint8) + (res-mountain-gear uint8) + (res-mountain-shard uint8) + (res-mountain-collection uint8) + (res-city-keira-delivery uint8) + (res-stadium-board1 uint8) + (res-city-krew-collection uint8) + (res-city-yellow-gun-training uint8) + (res-drill-eggs uint8) + (res-city-power uint8) + (res-palace-cable uint8) + (res-palace-boss uint8) + (res-city-shuttle uint8) + (res-ruins-enemy uint8) + (res-city-blue-gun-training uint8) + (res-forest-scouts uint8) + (res-city-escort-kid uint8) + (res-dig-knock-down uint8) + (res-strip-grenade uint8) + (res-drill-ship uint8) + (res-city-port-run uint8) + (res-city-meet-brutter uint8) + (res-sewer-board uint8) + (res-forest-hunt uint8) + (res-city-intercept-tanker uint8) + (res-stadium-race-class3 uint8) + (res-city-protect-water-slums uint8) + (res-dig-find-totem uint8) + (res-city-destroy-guard-vehicles uint8) + (res-city-play-onin-game uint8) + (res-canyon-insert-items uint8) + (res-tomb-poles uint8) + (res-tomb-water uint8) + (res-tomb-boss uint8) + (res-fortress-save-friends uint8) + (res-sewer-escort uint8) + (res-city-dark-gun-training uint8) + (res-stadium-race-class2 uint8) + (res-city-stop-bomb-bots uint8) + (res-city-errol-challenge uint8) + (res-strip-drop uint8) + (res-ruins-mech uint8) + (res-forest-protect uint8) + (res-drill-mech uint8) + (res-city-save-lurkers uint8) + (res-stadium-race-class uint8) + (res-palace-sneak-in uint8) + (res-castle-break-in uint8) + (res-castle-boss uint8) + (res-city-whack uint8) + (res-under-mech uint8) + (res-under-sig uint8) + (res-city-defend-stadium uint8) + (res-consite-find-baron uint8) + (res-nest-get-to-gun uint8) + (res-nest-enter uint8) + (res-nest-boss uint8) + (res-city-win uint8) + (res-city-oracle uint8) + (res-city-burning-bush-ring-1 uint8) + (res-city-burning-bush-get-to-1 uint8) + (res-city-burning-bush-get-to-2 uint8) + (res-city-burning-bush-get-to-3 uint8) + (res-city-burning-bush-get-to-4 uint8) + (res-city-burning-bush-collection-1 uint8) + (res-city-burning-bush-racepoint-1 uint8) + (res-city-burning-bush-ring-2 uint8) + (res-city-burning-bush-get-to-5 uint8) + (res-city-burning-bush-get-to-6 uint8) + (res-city-burning-bush-shuttle-1 uint8) + (res-city-burning-bush-get-to-7 uint8) + (res-city-burning-bush-get-to-8 uint8) + (res-city-burning-bush-get-to-9 uint8) + (res-city-burning-bush-collection-2 uint8) + (res-city-burning-bush-get-to-10 uint8) + (res-city-burning-bush-get-to-11 uint8) + (res-city-burning-bush-ring-3 uint8) + (res-city-burning-bush-get-to-12 uint8) + (res-city-burning-bush-bombbot-1 uint8) + (res-city-burning-bush-get-to-13 uint8) + (res-city-burning-bush-get-to-14 uint8) + (res-city-burning-bush-get-to-15 uint8) + (res-city-burning-bush-collection-3 uint8) + (res-city-burning-bush-race-errol uint8) + (res-city-burning-bush-race-port uint8) + (res-stadium-burning-bush-race-board uint8) + (res-stadium-burning-bush-race-class3 uint8) + (res-stadium-burning-bush-race-class2 uint8) + (res-stadium-burning-bush-race-class1 uint8) + (res-stadium-burning-bush-race-class3-r uint8) + (res-stadium-burning-bush-race-class2-r uint8) + (res-stadium-burning-bush-race-class1-r uint8) + ;; TODO - orbs in level X + ;; end marker just to make things look nice in a memory view + (end-marker uint8 4))) + +(define-extern *autosplit-info-jak2* autosplit-info-jak2) +(define-extern update-autosplit-info-jak2 (function none)) +(define-extern update-autosplit-jak2-new-game (function none)) diff --git a/goal_src/jak2/pc/features/autosplit.gc b/goal_src/jak2/pc/features/autosplit.gc new file mode 100644 index 0000000000..60e9ceb385 --- /dev/null +++ b/goal_src/jak2/pc/features/autosplit.gc @@ -0,0 +1,138 @@ +;;-*-Lisp-*- +(in-package goal) + +(define *autosplit-info-jak2* (new 'static 'autosplit-info-jak2)) +(pc-init-autosplitter-struct) +;; Setup Version +(set! (-> *autosplit-info-jak2* version-major) 0) +(set! (-> *autosplit-info-jak2* version-minor) 1) +;; Setup markers +(charp<-string (-> *autosplit-info-jak2* end-marker) "end") +;; Setup Padding +(charp<-string (-> *autosplit-info-jak2* padding-stats) "padding-stats!") +(charp<-string (-> *autosplit-info-jak2* padding-controls) "padding-controls!") + +(defmacro autosplit-flag-task-complete! (field-name task-name) + "Given a field name in the autosplitter struct, and a [[game-task]] name to check, sets either a 0 or a 1" + `(set! (-> *autosplit-info-jak2* ,field-name) (if (task-complete? *game-info* (game-task ,task-name)) 1 0))) + +(defun update-autosplit-info-jak2 () + ;; general statistics + (set! (-> *autosplit-info-jak2* num-orbs) (the int (-> *game-info* skill-total))) + (set! (-> *autosplit-info-jak2* num-skullgems) (the int (-> *game-info* gem-total))) + + ;; loading/cutscene related flags + (set! (-> *autosplit-info-jak2* in-cutscene?) (if (movie?) 1 0)) + + ;; need resolution flags + (autosplit-flag-task-complete! res-fortress-escape fortress-escape) + (autosplit-flag-task-complete! res-city-help-kid city-help-kid) + (autosplit-flag-task-complete! res-city-vehicle-training city-vehicle-training) + (autosplit-flag-task-complete! res-ruins-tower ruins-tower) + (autosplit-flag-task-complete! res-atoll-water atoll-water) + (autosplit-flag-task-complete! res-fortress-dump fortress-dump) + (autosplit-flag-task-complete! res-city-krew-delivery city-krew-delivery) + (autosplit-flag-task-complete! res-city-red-gun-training city-red-gun-training) + (autosplit-flag-task-complete! res-atoll-sig atoll-sig) + (autosplit-flag-task-complete! res-sewer-enemy sewer-enemy) + (autosplit-flag-task-complete! res-strip-rescue strip-rescue) + (autosplit-flag-task-complete! res-atoll-battle atoll-battle) + (autosplit-flag-task-complete! res-mountain-lens mountain-lens) + (autosplit-flag-task-complete! res-mountain-gear mountain-gear) + (autosplit-flag-task-complete! res-mountain-shard mountain-shard) + (autosplit-flag-task-complete! res-mountain-collection mountain-collection) + (autosplit-flag-task-complete! res-city-keira-delivery city-keira-delivery) + (autosplit-flag-task-complete! res-stadium-board1 stadium-board1) + (autosplit-flag-task-complete! res-city-krew-collection city-krew-collection) + (autosplit-flag-task-complete! res-city-yellow-gun-training city-yellow-gun-training) + (autosplit-flag-task-complete! res-drill-eggs drill-eggs) + (autosplit-flag-task-complete! res-city-power city-power) + (autosplit-flag-task-complete! res-palace-cable palace-cable) + (autosplit-flag-task-complete! res-palace-boss palace-boss) + (autosplit-flag-task-complete! res-city-shuttle city-shuttle) + (autosplit-flag-task-complete! res-ruins-enemy ruins-enemy) + (autosplit-flag-task-complete! res-city-blue-gun-training city-blue-gun-training) + (autosplit-flag-task-complete! res-forest-scouts forest-scouts) + (autosplit-flag-task-complete! res-city-escort-kid city-escort-kid) + (autosplit-flag-task-complete! res-dig-knock-down dig-knock-down) + (autosplit-flag-task-complete! res-strip-grenade strip-grenade) + (autosplit-flag-task-complete! res-drill-ship drill-ship) + (autosplit-flag-task-complete! res-city-port-run city-port-run) + (autosplit-flag-task-complete! res-city-meet-brutter city-meet-brutter) + (autosplit-flag-task-complete! res-sewer-board sewer-board) + (autosplit-flag-task-complete! res-forest-hunt forest-hunt) + (autosplit-flag-task-complete! res-city-intercept-tanker city-intercept-tanker) + (autosplit-flag-task-complete! res-stadium-race-class3 stadium-race-class3) + (autosplit-flag-task-complete! res-city-protect-water-slums city-protect-water-slums) + (autosplit-flag-task-complete! res-dig-find-totem dig-find-totem) + (autosplit-flag-task-complete! res-city-destroy-guard-vehicles city-destroy-guard-vehicles) + (autosplit-flag-task-complete! res-city-play-onin-game city-play-onin-game) + (autosplit-flag-task-complete! res-canyon-insert-items canyon-insert-items) + (autosplit-flag-task-complete! res-tomb-poles tomb-poles) + (autosplit-flag-task-complete! res-tomb-water tomb-water) + (autosplit-flag-task-complete! res-tomb-boss tomb-boss) + (autosplit-flag-task-complete! res-fortress-save-friends fortress-save-friends) + (autosplit-flag-task-complete! res-sewer-escort sewer-escort) + (autosplit-flag-task-complete! res-city-dark-gun-training city-dark-gun-training) + (autosplit-flag-task-complete! res-stadium-race-class2 stadium-race-class2) + (autosplit-flag-task-complete! res-city-stop-bomb-bots city-stop-bomb-bots) + (autosplit-flag-task-complete! res-city-errol-challenge city-errol-challenge) + (autosplit-flag-task-complete! res-strip-drop strip-drop) + (autosplit-flag-task-complete! res-ruins-mech ruins-mech) + (autosplit-flag-task-complete! res-forest-protect forest-protect) + (autosplit-flag-task-complete! res-drill-mech drill-mech) + (autosplit-flag-task-complete! res-city-save-lurkers city-save-lurkers) + (autosplit-flag-task-complete! res-stadium-race-class stadium-race-class) + (autosplit-flag-task-complete! res-palace-sneak-in palace-sneak-in) + (autosplit-flag-task-complete! res-castle-break-in castle-break-in) + (autosplit-flag-task-complete! res-castle-boss castle-boss) + (autosplit-flag-task-complete! res-city-whack city-whack) + (autosplit-flag-task-complete! res-under-mech under-mech) + (autosplit-flag-task-complete! res-under-sig under-sig) + (autosplit-flag-task-complete! res-city-defend-stadium city-defend-stadium) + (autosplit-flag-task-complete! res-consite-find-baron consite-find-baron) + (autosplit-flag-task-complete! res-nest-get-to-gun nest-get-to-gun) + (autosplit-flag-task-complete! res-nest-enter nest-enter) + (autosplit-flag-task-complete! res-nest-boss nest-boss) + (autosplit-flag-task-complete! res-city-win city-win) + (autosplit-flag-task-complete! res-city-oracle city-oracle) + (autosplit-flag-task-complete! res-city-burning-bush-ring-1 city-burning-bush-ring-1) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-1 city-burning-bush-get-to-1) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-2 city-burning-bush-get-to-2) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-3 city-burning-bush-get-to-3) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-4 city-burning-bush-get-to-4) + (autosplit-flag-task-complete! res-city-burning-bush-collection-1 city-burning-bush-collection-1) + (autosplit-flag-task-complete! res-city-burning-bush-racepoint-1 city-burning-bush-racepoint-1) + (autosplit-flag-task-complete! res-city-burning-bush-ring-2 city-burning-bush-ring-2) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-5 city-burning-bush-get-to-5) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-6 city-burning-bush-get-to-6) + (autosplit-flag-task-complete! res-city-burning-bush-shuttle-1 city-burning-bush-shuttle-1) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-7 city-burning-bush-get-to-7) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-8 city-burning-bush-get-to-8) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-9 city-burning-bush-get-to-9) + (autosplit-flag-task-complete! res-city-burning-bush-collection-2 city-burning-bush-collection-2) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-10 city-burning-bush-get-to-10) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-11 city-burning-bush-get-to-11) + (autosplit-flag-task-complete! res-city-burning-bush-ring-3 city-burning-bush-ring-3) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-12 city-burning-bush-get-to-12) + (autosplit-flag-task-complete! res-city-burning-bush-bombbot-1 city-burning-bush-bombbot-1) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-13 city-burning-bush-get-to-13) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-14 city-burning-bush-get-to-14) + (autosplit-flag-task-complete! res-city-burning-bush-get-to-15 city-burning-bush-get-to-15) + (autosplit-flag-task-complete! res-city-burning-bush-collection-3 city-burning-bush-collection-3) + (autosplit-flag-task-complete! res-city-burning-bush-race-errol city-burning-bush-race-errol) + (autosplit-flag-task-complete! res-city-burning-bush-race-port city-burning-bush-race-port) + (autosplit-flag-task-complete! res-stadium-burning-bush-race-board stadium-burning-bush-race-board) + (autosplit-flag-task-complete! res-stadium-burning-bush-race-class3 stadium-burning-bush-race-class3) + (autosplit-flag-task-complete! res-stadium-burning-bush-race-class2 stadium-burning-bush-race-class2) + (autosplit-flag-task-complete! res-stadium-burning-bush-race-class1 stadium-burning-bush-race-class1) + (autosplit-flag-task-complete! res-stadium-burning-bush-race-class3-r stadium-burning-bush-race-class3-r) + (autosplit-flag-task-complete! res-stadium-burning-bush-race-class2-r stadium-burning-bush-race-class2-r) + (autosplit-flag-task-complete! res-stadium-burning-bush-race-class1-r stadium-burning-bush-race-class1-r) + + (none)) + + +(defun update-autosplit-jak2-new-game () + (set! (-> *autosplit-info-jak2* game-hash) (pc-get-unix-timestamp)) + (none)) diff --git a/goal_src/jak2/pc/features/speedruns-h.gc b/goal_src/jak2/pc/features/speedruns-h.gc new file mode 100644 index 0000000000..0d1b523ae7 --- /dev/null +++ b/goal_src/jak2/pc/features/speedruns-h.gc @@ -0,0 +1,36 @@ +;;-*-Lisp-*- +(in-package goal) + + +(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-allMission 2) ;; All Missions + + ;; Individual Levels + (il-placeholder1 100) ;; Geyser Rock IL + (il-placeholdere3 101) ;; Sandover Village IL + (il-placeholder3 102) ;; Sentinel Beach IL + + + ;; Extension Categories (TBD) + ) + + +(deftype speedrun-info-jak2 (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/jak2/pc/features/speedruns.gc b/goal_src/jak2/pc/features/speedruns.gc new file mode 100644 index 0000000000..0ac753045c --- /dev/null +++ b/goal_src/jak2/pc/features/speedruns.gc @@ -0,0 +1,86 @@ +;;-*-Lisp-*- +(in-package goal) + +(define *speedrun-info* (new 'static 'speedrun-info-jak2 :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-jak2-new-game) + ;; turn on speedrun verification display and flip flag for setting up speedrun after initialize! + (set! (-> *speedrun-info* should-display?) #t) + ;; start new game with specified checkpoint, if any (otherwise we're resetting current category) + (when category + (set! (-> *speedrun-info* category) category)) + ;; TODO - ensure any required settings are enabled + (none) + ) + +;; TODO - fix me +(define post-blackout? #f) + +(defun setup-speedrun-post-blackout () + (when post-blackout? + (set! (-> *speedrun-info* needs-post-blackout-setup?) #f) + (case (-> *speedrun-info* category) + (((speedrun-category full-game)) + ;; setup a full-game run here + (none) + ) + (else + ;;speedrun-category was not recognized, print an error to the screen and maybe play a sound. + ) + ) + ;; 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* #f) + ) + (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-jak2) + ;; Draw info to the screen + (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-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?) + (not (paused?)) + (-> *speedrun-info* should-display?)) + (with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) + (bucket-id debug-no-zbuf1)) + (draw-string-xy (string-format "OpenGOAL Version: ~S ~%Speedrun mode: ~A ~%Category: ~S ~%Is fortress escaped: ~D" + *pc-settings-built-sha* + (-> *pc-settings* speedrunner-mode?) + (enum->string speedrun-category (-> *speedrun-info* category)) + (-> *autosplit-info-jak2* res-fortress-escape)) + buf 0 (- 220 (* 8 4)) (font-color #fef666) (font-flags shadow kerning)))) + (none)) diff --git a/goal_src/jak2/pc/pckernel.gc b/goal_src/jak2/pc/pckernel.gc index 9383da39d9..75e56ebcad 100644 --- a/goal_src/jak2/pc/pckernel.gc +++ b/goal_src/jak2/pc/pckernel.gc @@ -9,7 +9,6 @@ |# - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; methods ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -62,7 +61,6 @@ (defmethod update-discord-rpc pc-settings-jak2 ((obj pc-settings-jak2)) "update discord rpc module" - (let ((info (new 'stack 'discord-info))) (set! (-> info orb-count) (&-> *game-info* skill-total)) (set! (-> info gem-count) (&-> *game-info* gem-total)) @@ -75,17 +73,15 @@ (set! (-> info cutscene?) #f) ;; TODO - cutscenes don't work yet (set! (-> info time-of-day) (&-> *time-of-day-context* time)) (set! (-> info percent-complete) (calculate-percentage *game-info*)) - ;; TODO - wrapping in `with-profiler` causes an error, fix it - (pc-discord-rpc-update info) - ) - 0) + (pc-discord-rpc-update info)) + (none)) (defmethod update-speedrun pc-settings-jak2 ((obj pc-settings-jak2)) "update speedrun module" - - #f - ) + (when (-> *pc-settings* speedrunner-mode?) + (speedrun-mode-update)) + (none)) (defmethod update-video-hacks pc-settings-jak2 ((obj pc-settings-jak2)) "update the graphics hacks used for the progress menu. ugh."