From 044d4aea8e6bf3f5e1680f4aeae041936a35ba49 Mon Sep 17 00:00:00 2001 From: Nick0778 <149975116+Nick0778@users.noreply.github.com> Date: Tue, 12 May 2026 19:18:53 -0300 Subject: [PATCH 1/7] added `mods` folder stuff --- .../jak3/text/game_custom_text_en-US.json | 7 +- goal_src/jak3/dgos/game.gd | 6 + goal_src/jak3/engine/debug/default-menu.gc | 1 + goal_src/jak3/engine/game/main.gc | 2 + goal_src/jak3/engine/gfx/font.gc | 13 + goal_src/jak3/engine/mods/input-display.gc | 382 +++++++++++++++++ .../jak3/engine/mods/mod-common-functions.gc | 365 ++++++++++++++++ goal_src/jak3/engine/mods/mod-custom-code.gc | 119 ++++++ goal_src/jak3/engine/mods/mod-debug.gc | 34 ++ goal_src/jak3/engine/mods/mod-settings.gc | 50 +++ goal_src/jak3/engine/mods/orb-placer.gc | 402 ++++++++++++++++++ goal_src/jak3/engine/ui/text-h.gc | 6 +- 12 files changed, 1385 insertions(+), 2 deletions(-) create mode 100644 goal_src/jak3/engine/mods/input-display.gc create mode 100644 goal_src/jak3/engine/mods/mod-common-functions.gc create mode 100644 goal_src/jak3/engine/mods/mod-custom-code.gc create mode 100644 goal_src/jak3/engine/mods/mod-debug.gc create mode 100644 goal_src/jak3/engine/mods/mod-settings.gc create mode 100644 goal_src/jak3/engine/mods/orb-placer.gc diff --git a/game/assets/jak3/text/game_custom_text_en-US.json b/game/assets/jak3/text/game_custom_text_en-US.json index dba8b80529..70d1c1a215 100644 --- a/game/assets/jak3/text/game_custom_text_en-US.json +++ b/game/assets/jak3/text/game_custom_text_en-US.json @@ -260,5 +260,10 @@ "1369": "Light Regeneration", "136a": "Light Flight", "136b": "Flash Freeze", - "136c": "Light Shield" + "136c": "Light Shield", + + "2000": "", + "2001": "", + "2002": "", + "2003": "" } diff --git a/goal_src/jak3/dgos/game.gd b/goal_src/jak3/dgos/game.gd index 021a87b831..9ba8e1373f 100644 --- a/goal_src/jak3/dgos/game.gd +++ b/goal_src/jak3/dgos/game.gd @@ -363,6 +363,7 @@ "pckernel.o" ;; added "subtitle3-h.o" ;; added "subtitle3.o" ;; added + "input-display.o" ;;added ;;mod-base-change "main.o" "collide-cache.o" "collide-debug.o" @@ -490,4 +491,9 @@ "debris.o" "shield-sphere.o" "entity-debug.o" ;; added + "mod-settings.o" ;; added ;;mod-base-change + "mod-common-functions.o" ;; added + "orb-placer.o" ;; added + "mod-custom-code.o" ;; added + "mod-debug.o" ;; added )) diff --git a/goal_src/jak3/engine/debug/default-menu.gc b/goal_src/jak3/engine/debug/default-menu.gc index 3b0ca1a64a..9f5b25bc47 100644 --- a/goal_src/jak3/engine/debug/default-menu.gc +++ b/goal_src/jak3/engine/debug/default-menu.gc @@ -4024,6 +4024,7 @@ arg0 '(menu "Display" + (flag "Input Display" *show-input-display* dm-boolean-toggle-pick-func) ;; mod-base-change (flag "Profile" *display-profile* dm-boolean-toggle-pick-func) (flag "Ticks" *profile-ticks* dm-boolean-toggle-pick-func) (flag "File Info" *display-file-info* dm-boolean-toggle-pick-func) diff --git a/goal_src/jak3/engine/game/main.gc b/goal_src/jak3/engine/game/main.gc index 07d6ced349..5838eca40a 100644 --- a/goal_src/jak3/engine/game/main.gc +++ b/goal_src/jak3/engine/game/main.gc @@ -7,6 +7,7 @@ (define-extern menu-respond-to-pause (function symbol)) (define-extern anim-tester-add-object (function string none)) +(defun-extern runs-every-frame (none)) ;; mod-base-change ;; DECOMP BEGINS @@ -1493,6 +1494,7 @@ (if (-> *level* loading-level) (load-continue (-> *level* loading-level)) ) + (runs-every-frame) ;; mod-base-change ;; run the drawing system! ;; (note that this does a significant amount of non-drawing stuff, like collision callbacks, actors-update, diff --git a/goal_src/jak3/engine/gfx/font.gc b/goal_src/jak3/engine/gfx/font.gc index f42466b276..aad4fa1e16 100644 --- a/goal_src/jak3/engine/gfx/font.gc +++ b/goal_src/jak3/engine/gfx/font.gc @@ -79,3 +79,16 @@ ) (none) ) + +;; Added for PC port +(defun draw-string-xy-scaled ((str string) (buf dma-buffer) (x int) (y int) (color font-color) (flags font-flags) (scale float)) + "Draw a string at the given xy location, with the given scale." + (let ((font-ctxt (new 'stack 'font-context *font-default-matrix* x y 0.0 color flags))) + (*! (-> font-ctxt scale) scale) + (*! (-> font-ctxt width) scale) + (*! (-> font-ctxt height) scale) + (draw-string str buf font-ctxt) + ) + (none) + ) + \ No newline at end of file diff --git a/goal_src/jak3/engine/mods/input-display.gc b/goal_src/jak3/engine/mods/input-display.gc new file mode 100644 index 0000000000..4de6f0c71e --- /dev/null +++ b/goal_src/jak3/engine/mods/input-display.gc @@ -0,0 +1,382 @@ +;;-*-Lisp-*- +(in-package goal) + +#| +An input display written in GOAL + +Controller joystick locations have text coordinates and a grid display + +Face buttons were added to game_custom_text so they could be displayed with lookup-text! +Other buttons are displayed using text: "R3" "Select" + +Sections of the input display are anchored by an -origin vector +Individual buttons have an -offset vector relative to the origin + ie: the face buttons center is (90, 208) on-screen, and the Triangle button is 12 units to the left, and 18 units above + try (set-vector! stick-origin 60 20 0 0) + +Use L2 + L3 + Dpad to start editing the input display +The dpad press displays text and changes the edit mode +Down lets you edit buttons, left lets you edit the sticks, right for dpad, up to stop editing +|# + +;; *show-input-display* is the on/off switch controlling whether this is displayed + +; +;Button stuff +; +;Button center coordinates +(define button-origin (new 'static 'vector4w :x 90 :y 380 :z 0 :w 0)) +;Face buttons +(define triangle-offset (new 'static 'vector4w :x -12 :y -36 :z 0 :w 0)) +(define x-offset (new 'static 'vector4w :x -12 :y 4 :z 0 :w 0)) +(define circle-offset (new 'static 'vector4w :x 6 :y -16 :z 0 :w 0)) +(define square-offset (new 'static 'vector4w :x -30 :y -16 :z 0 :w 0)) + +(defun draw-face-buttons ((arg0 dma-buffer)) + ;Face buttons. Each button needed added to text-h.gc and english texts + (when (cpad-hold? 0 triangle) + (draw-string-xy (lookup-text! *common-text* (text-id pad-triangle) #f) arg0 (+ (-> button-origin x) (-> triangle-offset x)) (+ (-> button-origin y) (-> triangle-offset y)) (font-color green) (font-flags shadow kerning large)) ) + (when (cpad-hold? 0 circle) + (draw-string-xy (lookup-text! *common-text* (text-id pad-circle) #f) arg0 (+ (-> button-origin x) (-> circle-offset x)) (+ (-> button-origin y) (-> circle-offset y)) (font-color green) (font-flags shadow kerning large)) ) + (when (cpad-hold? 0 x) + (draw-string-xy (lookup-text! *common-text* (text-id pad-x) #f) arg0 (+ (-> button-origin x) (-> x-offset x)) (+ (-> button-origin y) (-> x-offset y)) (font-color green) (font-flags shadow kerning large)) ) + (when (cpad-hold? 0 square) + (draw-string-xy (lookup-text! *common-text* (text-id pad-square) #f) arg0 (+ (-> button-origin x) (-> square-offset x)) (+ (-> button-origin y) (-> square-offset y)) (font-color green) (font-flags shadow kerning large)) ) +) + +; +;Other buttons (LRs, select, start) +; +;(define R-x-offset 13) +;(define L-x-offset (- 28)) ;use a minus for negative numbers +;(define RL1-y-offset (- 16)) +;(define RL2-y-offset (- 23)) +;(define RL3-y-offset 8) + +(define r1-offset (new 'static 'vector4w :x 13 :y -32 :z 0 :w 0)) +(define r2-offset (new 'static 'vector4w :x 13 :y -46 :z 0 :w 0)) +(define r3-offset (new 'static 'vector4w :x 13 :y 16 :z 0 :w 0)) +(define l1-offset (new 'static 'vector4w :x -28 :y -32 :z 0 :w 0)) +(define l2-offset (new 'static 'vector4w :x -28 :y -46 :z 0 :w 0)) +(define l3-offset (new 'static 'vector4w :x -28 :y 16 :z 0 :w 0)) +; select uses l3 offset +; start uses r3 offset + +(defun draw-other-buttons ((arg0 dma-buffer)) + ;LR/Shoulder buttons + (when (cpad-hold? 0 r1) + (draw-string-xy "R1" arg0 (+ (-> button-origin x) (-> r1-offset x)) (+ (-> button-origin y) (-> r1-offset y)) (the font-color 13) (font-flags shadow kerning)) ) + (when (cpad-hold? 0 r2) + (draw-string-xy "R2" arg0 (+ (-> button-origin x) (-> r2-offset x)) (+ (-> button-origin y) (-> r2-offset y)) (the font-color 13) (font-flags shadow kerning)) ) + (when (cpad-hold? 0 r3) + (draw-string-xy "R3" arg0 (+ (-> button-origin x) (-> r3-offset x)) (+ (-> button-origin y) (-> r3-offset y)) (the font-color 13) (font-flags shadow kerning)) ) + (when (cpad-hold? 0 l1) + (draw-string-xy "L1" arg0 (+ (-> button-origin x) (-> l1-offset x)) (+ (-> button-origin y) (-> l1-offset y)) (the font-color 13) (font-flags shadow kerning)) ) + (when (cpad-hold? 0 l2) + (draw-string-xy "L2" arg0 (+ (-> button-origin x) (-> l2-offset x)) (+ (-> button-origin y) (-> l2-offset y)) (the font-color 13) (font-flags shadow kerning)) ) + (when (cpad-hold? 0 l3) + (draw-string-xy "L3" arg0 (+ (-> button-origin x) (-> l3-offset x)) (+ (-> button-origin y) (-> l3-offset y)) (the font-color 13) (font-flags shadow kerning)) ) + + ;Select/Start, aligned with L3/R3 + (when (cpad-hold? 0 start) + (draw-string-xy "Start" arg0 (+ (-> button-origin x) (-> r3-offset x)) (+ (-> button-origin y) (-> r3-offset y)) (the font-color 13) (font-flags shadow kerning)) ) + (when (cpad-hold? 0 select) + (draw-string-xy "Select" arg0 (+ (-> button-origin x) (-> l3-offset x)) (+ (-> button-origin y) (-> l3-offset y)) (the font-color 13) (font-flags shadow kerning)) ) + +) + + + +; +;D-Pad inputs +; +(define dpad-origin (new 'static 'vector4w :x 90 :y 380 :z 0 :w 0)) +(define up-offset (new 'static 'vector4w :x -12 :y -36 :z 0 :w 0)) +(define down-offset (new 'static 'vector4w :x -12 :y 4 :z 0 :w 0)) +(define left-offset (new 'static 'vector4w :x -30 :y -16 :z 0 :w 0)) +(define right-offset (new 'static 'vector4w :x 6 :y -16 :z 0 :w 0)) + +(defun draw-dpad ((arg0 dma-buffer)) + (when (cpad-hold? 0 up) + (draw-string-xy "up" arg0 (+ (-> dpad-origin x) (-> up-offset x)) (+ (-> dpad-origin y) (-> up-offset y)) (the font-color 13) (font-flags shadow kerning)) ) + (when (cpad-hold? 0 down) + (draw-string-xy "down" arg0 (+ (-> dpad-origin x) (-> down-offset x)) (+ (-> dpad-origin y) (-> down-offset y)) (the font-color 13) (font-flags shadow kerning)) ) + (when (cpad-hold? 0 left) + (draw-string-xy "left" arg0 (+ (-> dpad-origin x) (-> left-offset x)) (+ (-> dpad-origin y) (-> left-offset y)) (the font-color 13) (font-flags shadow kerning)) ) + (when (cpad-hold? 0 right) + (draw-string-xy "right" arg0 (+ (-> dpad-origin x) (-> right-offset x)) (+ (-> dpad-origin y) (-> right-offset y)) (the font-color 13) (font-flags shadow kerning)) ) +) + + + +; +;Joystick stuff +; +(define show-stick1? #t) +(define stick-origin (new 'static 'vector4w :x 30 :y 380 :z 0 :w 0)) +(define stick-text-offset (new 'static 'vector4w :x -20 :y -40 :z 0 :w 0)) + +;no idea how the draw scaling works, this seems good enough +;length of axes lines, started with 128 and adjusted until it looked good +(define height-idk (/ 256 5)) +(define width-idk (/ 128 3)) + +(defun draw-stick ((arg0 dma-buffer)) + (when show-stick1? + ;up/down axis + (draw-sprite2d-xy arg0 + (-> stick-origin x) ;the vertical line's x coordinate = stick center x coordinate + (- (-> stick-origin y) (/ height-idk 2)) ;we shift the line up, by half its height, so that the line midpoint = center y coordinate + 2 + height-idk + *color-black* + #x3fffff) + ;left/right axis + (draw-sprite2d-xy arg0 + (- (-> stick-origin x) (/ width-idk 2)) + (-> stick-origin y) + width-idk + 1 + *color-gray* + #x3fffff) + + ;Text for stick values + (draw-string-xy-scaled (string-format "~d ~d" (-> *cpad-list* cpads 0 leftx) (-> *cpad-list* cpads 0 lefty)) arg0 + (+ (-> stick-origin x) (-> stick-text-offset x)) + (+ (-> stick-origin y) (-> stick-text-offset y)) + (font-color green) (font-flags shadow kerning ) 0.75) + + ;raw stick location, nice for locating screen coordinates + ;(draw-sprite2d-xy testbuf (the int (-> *cpad-list* cpads 0 leftx)) (the int(-> *cpad-list* cpads 0 lefty)) 5 3 *color-red* #x3fffff) + + ;stick location scaled to picture + (draw-sprite2d-xy arg0 + ;analog-input takes left stick x int value and maps its min/max to negative/positive of the last argument + ;in our case we scale to half of the picture's width, so the stick can go full + (right) or full - (left) + (+ (-> stick-origin x) + (analog-input (the int (-> *cpad-list* cpads 0 leftx)) 128.0 0.0 128.0 (the float (/ width-idk 2)))) + ;repeat for y coordinate + (+ (-> stick-origin y) + (analog-input (the int (-> *cpad-list* cpads 0 lefty)) 128.0 0.0 128.0 (the float (/ height-idk 2)))) + 3 + 2 + *color-cyan* + #x3fffff) + ) +) + +; +;Second stick +; +(define show-stick2? #f) +(define stick2-origin (new 'static 'vector4w :x 150 :y 380 :z 0 :w 0)) +(define stick2-text-offset (new 'static 'vector4w :x -20 :y -40 :z 0 :w 0)) + +(defun draw-stick2 ((arg0 dma-buffer)) + (when show-stick2? + ;up/down axis + (draw-sprite2d-xy arg0 + (-> stick2-origin x) + (- (-> stick2-origin y) (/ height-idk 2)) + 2 + height-idk + *color-black* + #x3fffff) + ;left/right axis + (draw-sprite2d-xy arg0 + (- (-> stick2-origin x) (/ width-idk 2)) + (-> stick2-origin y) + width-idk + 1 + *color-gray* + #x3fffff) + + ;Text for stick values + (draw-string-xy-scaled (string-format "~d ~d" (-> *cpad-list* cpads 0 rightx) (-> *cpad-list* cpads 0 righty)) arg0 + (+ (-> stick2-origin x) (-> stick2-text-offset x)) + (+ (-> stick2-origin y) (-> stick2-text-offset y)) + (font-color cyan) (font-flags shadow kerning ) 0.75) + + ;stick location scaled to picture + (draw-sprite2d-xy arg0 + (+ (-> stick2-origin x) + (analog-input (the int (-> *cpad-list* cpads 0 rightx)) 128.0 0.0 128.0 (the float (/ width-idk 2)))) + (+ (-> stick2-origin y) + (analog-input (the int (-> *cpad-list* cpads 0 righty)) 128.0 0.0 128.0 (the float (/ height-idk 2)))) + 3 + 2 + *color-green* + #x3fffff) + ) +) + +; +;edit mode +; +(define button-edit-mode 0) +(define button-edit-strings (new 'static 'boxed-array :type string + "" + "Hold a button and use dpad to move" + "Editing Sticks" + "Editing Dpad" + )) + +(defun edit-mode-controls () + ;Hold L2 + L3 + dpad to change the edit mode + (when (and (cpad-hold? 0 l2) (cpad-hold? 0 l3)) + (when (cpad-pressed? 0 up) (set! button-edit-mode 0)) + (when (cpad-pressed? 0 down) (set! button-edit-mode 1)) + (when (cpad-pressed? 0 left) (set! button-edit-mode 2)) + (when (cpad-pressed? 0 right) (set! button-edit-mode 3)) + ) + + ;moves individual face buttons with dpad + (when (= button-edit-mode 1) + (when (cpad-hold? 0 triangle) ;when you hold triangle, you can move triangle's offset vector with the dpad + (when (cpad-hold? 0 up) (+! (-> triangle-offset y) -1)) + (when (cpad-hold? 0 down) (+! (-> triangle-offset y) 1)) + (when (cpad-hold? 0 left) (+! (-> triangle-offset x) -1)) + (when (cpad-hold? 0 right) (+! (-> triangle-offset x) 1)) + ) + (when (cpad-hold? 0 circle) + (when (cpad-hold? 0 up) (+! (-> circle-offset y) -1)) + (when (cpad-hold? 0 down) (+! (-> circle-offset y) 1)) + (when (cpad-hold? 0 left) (+! (-> circle-offset x) -1)) + (when (cpad-hold? 0 right) (+! (-> circle-offset x) 1)) + ) + (when (cpad-hold? 0 x) + (when (cpad-hold? 0 up) (+! (-> x-offset y) -1)) + (when (cpad-hold? 0 down) (+! (-> x-offset y) 1)) + (when (cpad-hold? 0 left) (+! (-> x-offset x) -1)) + (when (cpad-hold? 0 right) (+! (-> x-offset x) 1)) + ) + (when (cpad-hold? 0 square) + (when (cpad-hold? 0 up) (+! (-> square-offset y) -1)) + (when (cpad-hold? 0 down) (+! (-> square-offset y) 1)) + (when (cpad-hold? 0 left) (+! (-> square-offset x) -1)) + (when (cpad-hold? 0 right) (+! (-> square-offset x) 1)) + ) + ;LR buttons + (when (cpad-hold? 0 r1) + (when (cpad-hold? 0 up) (+! (-> r1-offset y) -1)) + (when (cpad-hold? 0 down) (+! (-> r1-offset y) 1)) + (when (cpad-hold? 0 left) (+! (-> r1-offset x) -1)) + (when (cpad-hold? 0 right) (+! (-> r1-offset x) 1)) + ) + (when (cpad-hold? 0 r2) + (when (cpad-hold? 0 up) (+! (-> r2-offset y) -1)) + (when (cpad-hold? 0 down) (+! (-> r2-offset y) 1)) + (when (cpad-hold? 0 left) (+! (-> r2-offset x) -1)) + (when (cpad-hold? 0 right) (+! (-> r2-offset x) 1)) + ) + (when (or (cpad-hold? 0 r3) (cpad-hold? 0 start)) ;use an or here since start/r3 share coords + (when (cpad-hold? 0 up) (+! (-> r3-offset y) -1)) + (when (cpad-hold? 0 down) (+! (-> r3-offset y) 1)) + (when (cpad-hold? 0 left) (+! (-> r3-offset x) -1)) + (when (cpad-hold? 0 right) (+! (-> r3-offset x) 1)) + ) + (when (cpad-hold? 0 l1) + (when (cpad-hold? 0 up) (+! (-> l1-offset y) -1)) + (when (cpad-hold? 0 down) (+! (-> l1-offset y) 1)) + (when (cpad-hold? 0 left) (+! (-> l1-offset x) -1)) + (when (cpad-hold? 0 right) (+! (-> l1-offset x) 1)) + ) + (when (cpad-hold? 0 l2) + (when (cpad-hold? 0 up) (+! (-> l2-offset y) -1)) + (when (cpad-hold? 0 down) (+! (-> l2-offset y) 1)) + (when (cpad-hold? 0 left) (+! (-> l2-offset x) -1)) + (when (cpad-hold? 0 right) (+! (-> l2-offset x) 1)) + ) + (when (or (cpad-hold? 0 l3) (cpad-hold? 0 select)) ;use an or here since select/l3 share coords + (when (cpad-hold? 0 up) (+! (-> l3-offset y) -1)) + (when (cpad-hold? 0 down) (+! (-> l3-offset y) 1)) + (when (cpad-hold? 0 left) (+! (-> l3-offset x) -1)) + (when (cpad-hold? 0 right) (+! (-> l3-offset x) 1)) + ) + ) + ;moves joysticks + (when (= button-edit-mode 2) + ;stick1 with dpad + (when (cpad-hold? 0 up) (+! (-> stick-origin y) -1)) + (when (cpad-hold? 0 down) (+! (-> stick-origin y) 1)) + (when (cpad-hold? 0 left) (+! (-> stick-origin x) -1)) + (when (cpad-hold? 0 right) (+! (-> stick-origin x) 1)) + (when (cpad-pressed? 0 l3) (not! show-stick1?)) + ;stick2 with face buttons + (when (cpad-hold? 0 triangle) (+! (-> stick2-origin y) -1)) + (when (cpad-hold? 0 x) (+! (-> stick2-origin y) 1)) + (when (cpad-hold? 0 square) (+! (-> stick2-origin x) -1)) + (when (cpad-hold? 0 circle) (+! (-> stick2-origin x) 1)) + (when (cpad-pressed? 0 r3) (not! show-stick2?)) + ) + ;moves dpad + (when (= button-edit-mode 3) + ;dpad-origin with dpad + (when (cpad-hold? 0 up) (+! (-> dpad-origin y) -1)) + (when (cpad-hold? 0 down) (+! (-> dpad-origin y) 1)) + (when (cpad-hold? 0 left) (+! (-> dpad-origin x) -1)) + (when (cpad-hold? 0 right) (+! (-> dpad-origin x) 1)) + ) +) + + + +; +; +;this is the main function/process +; +; + +(defun input-display-on () + (when (not (process-by-name "button-proc" *active-pool*)) + ;process-spawn-function, spawns a process that runs the function you give it + (process-spawn-function process :name "button-proc" + ;This lambda is our function + (lambda :behavior process () + ;Code before the loop runs once on process spawn + ; + ;Loop runs once per frame while process is active + (loop + + ;function that checks input to turn on editing + (edit-mode-controls) + + ;Start a bucket thing block so we can use draw functions + (with-dma-buffer-add-bucket ((testbuf (-> (current-frame) global-buf)) (bucket-id debug-no-zbuf1)) + ;Edit mode string draws + (when (and (cpad-hold? 0 l2) (cpad-hold? 0 l3)) + (draw-string-xy-scaled "L2+L3+Dpad to start editing input display" testbuf 5 170 (the font-color 12) (font-flags shadow kerning) 0.7) ) + (when (!= button-edit-mode 0) + (draw-string-xy-scaled (string-format "~s" (-> button-edit-strings button-edit-mode)) testbuf 5 177 (the font-color 12) (font-flags shadow kerning) 0.7) ) + + ;Other draw stuff + (draw-face-buttons testbuf) + + (draw-other-buttons testbuf) + + (draw-dpad testbuf) + + (draw-stick testbuf) + + (draw-stick2 testbuf) + ) + + ;Processes should suspend themselves, the loop will resume next frame + (suspend) + ) + ) + ) + ) + + ;Lisp returns the last form as the function return + (none) + ) + + +(defun input-display-off () + "Kill the button process" + (when (process-by-name "button-proc" *active-pool*) + (kill-by-name "button-proc" *active-pool*) + ) + (none) + ) \ No newline at end of file diff --git a/goal_src/jak3/engine/mods/mod-common-functions.gc b/goal_src/jak3/engine/mods/mod-common-functions.gc new file mode 100644 index 0000000000..9a825cd978 --- /dev/null +++ b/goal_src/jak3/engine/mods/mod-common-functions.gc @@ -0,0 +1,365 @@ +;;-*-Lisp-*- +(in-package goal) + +;; name: mod-common-functions.gc +;; name in dgo: mod-common-functions +;; dgos: TODO + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; What is this file for. +;;;;;;;;;;;;;;;;;;;;;;;;;; + +#| This file is a place where you can define custom functions and GOAL code + to call inside of mod-custom-code.gc for example I have defined a function that increases + the powercell count by one when it is called + |# + + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Useful GOAL modding documentation +;;;;;;;;;;;;;;;;;;;;;;;;;; + +#| +Checks the condition and if it is true it does first argument if false it does optional second argument +(if (condition) (do if true) (do if false)) + +Gives a random FLOAT or INT between the provided ranges when called +(rand-vu-float-range 0.0 2.0) +(rand-vu-int-range 0 10) + +if the result of rand-vu-int-range is 1, then DANCE! if it is not 1, then Don't dance +(if (= (rand-vu-int-range 0 10) 1) (DANCE!) (Don't dance)) + + +|# + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Define Custom Variables to use in mods +;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define *target-board-hold-tricks* 0) ;; used to detect if player is doing a jetboard hover (see board-states.gc) + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Define Custom Functions to call in mods +;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; add your own unique custom functions here! + +;; Macros can be used more-or-less just like functions +(defmacro current-cell-count () + `(-> *game-info* fuel) + ) + +(defmacro set-current-cell-count (count) + `(set! (-> *game-info* fuel) ,count) + ) + +(defun increase-power-cell-by-one () + (set-current-cell-count (+ (current-cell-count) 1)) + ;; with the two macros defined above, this is equivalent to + ;; (set! (-> *game-info* fuel) (+ (-> *game-info* fuel) 1)) + (none) + ) + +(defmacro board-hovering? () + `(and (logtest? (focus-status board) (-> *target* focus-status)) (> *target-board-hold-tricks* 1)) + ) + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Define Approved Custom Functions/Macros to call in all mods +;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; These are included with the mod base and you are welcome to use them in your mods! + +(defmacro current-checkpoint-name () + `(-> *game-info* current-continue name) + ) + +;;Might want to add #f as a customizable function arg later +(defun set-current-checkpoint-by-name ((name string)) + (set-continue! *game-info* name #f) + ) + +(defmacro current-level-name () + `(-> (level-get-target-inside *level*) name) + ) + +(defmacro current-orb-count () + `(-> *game-info* money) + ) + +(defmacro current-cutscene () + `(-> *art-control* active-stream) + ) + +;;This function moves an actor to the given coordinates +;;example (move-actor farmer-3 3.0 74.0 -120.0) +(defun move-actor ((actor-name string) (x float) (y float) (z float)) + (when (entity-by-name actor-name) + (let* ((entity-actor (entity-by-name actor-name)) + (actor (-> entity-actor extra process)) + ) + (when actor + (case (-> actor type) + ((skill) + + (set-vector! (-> entity-actor trans) (meters x) (meters y) (meters z) 1.0) + (set-vector! (-> entity-actor extra trans) (meters x) (meters y) (meters z) 1.0) + (set-vector! (-> (the process-drawable actor) root trans) (meters x) (meters y) (meters z) 1.0) + (set-vector! (-> (the money actor) base) (meters x) (meters y) (meters z) 1.0) + + + + ) + ((crate) + ;; only move crates if they're not jumping + (when (= (-> (the crate actor) smush amp) 0.0) + (set-vector! (-> entity-actor trans) (meters x) (meters y) (meters z) 1.0) + (set-vector! (-> entity-actor extra trans) (meters x) (meters y) (meters z) 1.0) + (set-vector! (-> (the process-drawable actor) root trans) (meters x) (meters y) (meters z) 1.0) + (set-vector! (-> (the crate actor) base) (meters x) (meters y) (meters z) 1.0) + ;; (set-vector! (-> (the crate actor) root trans) (meters x) (meters y) (meters z) 1.0) + ;; (set! (-> (the crate actor) root root-prim world-sphere x) (meters x)) + ;; (set! (-> (the crate actor) root root-prim world-sphere y) (meters y)) + ;; (set! (-> (the crate actor) root root-prim world-sphere z) (meters z)) + ) + ) + + (else + (format 0 "unexpected actor type ~S ~S ~S~%" actor-name (-> entity-actor type) (-> actor type)) + (set-vector! (-> entity-actor trans) (meters x) (meters y) (meters z) 1.0) + (set-vector! (-> entity-actor extra trans) (meters x) (meters y) (meters z) 1.0) + ;; (set-vector! (-> (the process-drawable actor) root trans) (meters x) (meters y) (meters z) 1.0) + ) + ) + ) + ) + ) + (none) + ) + +;;Draws a debug sphere on the actor, takes in a string actor name and a radius for the sphere in meters +(defun draw-debug-sphere-on-actor ((actorName string)(radius float)) + (when *debug-segment* + (when (process-by-ename actorName) + (add-debug-sphere #t (bucket-id debug) (-> (the-as process-drawable (process-by-ename actorName)) root trans) (meters radius) (static-rgba 0 #xff 0 #x40)) + ) + ) + (none) +) + + +;;This function moves a given actor to jaks current position, then prints a (move-actors) call in gk.exe +(defun move-to-jak ((arg0 string)) +(format #t "move-actor code: (move-actor ~a ~m ~m ~m)~%" arg0(-> (target-pos 0) x) (-> (target-pos 0) y) (-> (target-pos 0) z)) + (when (process-by-ename arg0) + (set-vector! (-> (-> (the process-drawable (process-by-ename arg0))root)trans) (-> (target-pos 0) x) (-> (target-pos 0) y) (-> (target-pos 0) z) 1.0) + (if (type-type? (-> (process-by-ename arg0) type) crate) + (begin + (set! (-> (the crate (process-by-ename arg0)) base y) (-> (target-pos 0) y)) + ) + (none) + ) + + (if (type-type? (-> (process-by-ename arg0) type) money) + (begin + (set! (-> (the money (process-by-ename arg0)) base y) (-> (target-pos 0) y)) + ) + (none) + ) + + + ) +) + +;; quick macro for setting vector xyz in meters, leaving w alone +(defmacro set-vector-meters! (dst x y z) + `(set-vector! ,dst (meters ,x) (meters ,y) (meters ,z) (-> ,dst w)) + ) + +;; quick macro for constructing static vector with w=1 +(defmacro static-vector-meters (x y z) + `(new 'static 'vector :x (meters ,x) :y (meters ,y) :z (meters ,z) :w 1.0) + ) + +;; prints vector xyz in meters +(defmacro print-vector-meters (vec &key (dst #t)) + `(format ,dst "~m ~m ~m~%" (-> ,vec x) (-> ,vec y) (-> ,vec z)) + ) + +;; takes a path-control and xyz values to offsets every node in the path by +(defmacro shift-path! (path x y z) + `(let ((voff (static-vector-meters ,x ,y ,z))) + (dotimes (idx (-> ,path num-cverts)) + (vector+! (-> ,path cverts idx) (-> ,path cverts idx) voff) + ) + ) + ) + +;; prints all the nodes in a path in meters +(defmacro path-print-meters (path) + `(dotimes (idx (-> ,path num-cverts)) + (print-vector-meters (-> ,path cverts idx)) + ) + ) + +;; prints the position (root trans) of a process-drawable +(defmacro pd-pos-m (procname) + `(let* ((obj (the process-drawable (process-by-ename ,procname))) + (vec (-> obj root trans))) + (format 0 "~m ~m ~m~%" (-> vec x) (-> vec y) (-> vec z)) + (none) + ) + ) + +;;This function moves an actor based on jaks position + an offset +(defun move-to-behind-jak ((arg0 string) (arg1 meters) (arg2 meters)) + (when (process-by-ename arg0) + (set-vector! (-> (-> (the process-drawable (process-by-ename arg0))root)trans) (-(-> (target-pos 0) x) (meters arg1)) (+ (-> (target-pos 0) y) (meters arg2)) (-(-> (target-pos 0) z)(meters arg1)) 1.0) + (if (type-type? (-> (process-by-ename arg0) type) money) + (begin + (set! (-> (the money (process-by-ename arg0)) base y) (-> (target-pos 0) y) ) + ) + (none) + ) + + ) +) + + + +;; ;;This turns on collision render when called +;; (defun turnonCollisionmode() +;; (set! *collision-renderer* #t) +;; (logclear! *vu1-enable-user-menu* (vu1-renderer-mask tfrag trans-tfrag tie tie-near)) +;; ) + +;; ;;This turns off collision render when called +;; (defun turnoffCollisionmode() +;; (set! *collision-renderer* #f) +;; (logior! *vu1-enable-user-menu* (vu1-renderer-mask tfrag trans-tfrag tie tie-near)) +;; ) + +;; ;;This makes it thunder in the current level +;; (defun thunderTime() +;; (set! (-> (level-get-target-inside *level*) mood-func)update-mood-village2) +;; (set! (-> (level-get-target-inside *level*) mood) *village2-mood*) +;; ) + +;; ;;This makes the current level dark when called +;; (defun DarkesetGlitchTime() +;; (set! (-> (level-get-target-inside *level*) mood-func)update-mood-finalboss ) +;; (set! (-> (level-get-target-inside *level*) mood) *finalboss-mood*) +;; ) + +;; ;;This needs fixed +;; (defun rainyTime() +;; (set! (-> (level-get-target-inside *level*) mood-func)update-mood-swamp) +;; (set! (-> (level-get-target-inside *level*) mood) *swamp-mood*) +;; ) + + +;; ;;This makes the current levels weather the same as village1 +;; (defun defaultWeatherTime() +;; (set! (-> (level-get-target-inside *level*) mood-func)update-mood-village1) +;; (set! (-> (level-get-target-inside *level*) mood) *village1-mood*) +;; ) + +;;This moves jak to a provided coordinate example call +;;(tp-jak 0.0 12.0 32.32) +(defun tp-jak ((arg0 float)(arg1 float)(arg2 float)) + (set! (-> (target-pos 0) x) (meters arg0)) + (set! (-> (target-pos 0) y) (meters arg1)) + (set! (-> (target-pos 0) z) (meters arg2)) +) + +;;This returns true or false depending on if jak is within a provided distance from an actor +(defun close? ((actor-ename string) (dist float)) + (and + (process-by-ename actor-ename) + (<= + (vector-vector-distance + (target-pos 0) + (-> (the process-drawable (process-by-ename actor-ename)) root trans) + ) + dist + ) + ) + ) + + +;;This returns true or false if jak is within a bubble defined by coordiantes and width +(defun in-bubble? ((x float) (y float) (z float) (w float)) + (<= + (vector-vector-distance + (target-pos 0) + (set-vector! (new-stack-vector0) x y z 1.0) + ) + (/ w 2.0) + ) + ) + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Jak Color functions +;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun draw-xyz ((jak target) (x float) (y float) (z float)) + (set! (-> jak draw color-mult x) x) + (set! (-> jak draw color-mult y) y) + (set! (-> jak draw color-mult z) z) +) +(defun draw-normal ((jak target)) + (draw-xyz jak 1.0 1.0 1.0) +) +(defun draw-white ((jak target)) + (draw-xyz jak 10.0 10.0 10.0) +) +(defun draw-black ((jak target)) + (draw-xyz jak 0.0 0.0 0.0) +) +(defun draw-red ((jak target)) + (draw-xyz jak 3.0 0.0 0.0) +) +(defun draw-green ((jak target)) + (draw-xyz jak 0.0 3.0 0.0) +) +(defun draw-blue ((jak target)) + (draw-xyz jak 0.0 0.0 3.0) +) +(defun draw-yellow ((jak target)) + (draw-xyz jak 3.0 3.0 0.0) +) +(defun draw-pink ((jak target)) + (draw-xyz jak 3.0 0.0 3.0) +) +(defun draw-light-blue ((jak target)) + (draw-xyz jak 0.0 3.0 3.0) +) + +;; Helper functions for spawning orbs (used by orb placer in debug mode) + +(defun spawn-skill ((vec vector) (amount float) (bob? symbol)) + (let ((fax (new 'static 'fact-info))) + (set! (-> fax pickup-type) (pickup-type skill)) + (set! (-> fax pickup-amount) amount) + (set! (-> fax pickup-spawn-amount) amount) + ;; make sure it doesn't timeout and disappear + (logior! (-> fax options) (actor-option fade-out)) + (set! (-> fax fade-time) (the-as time-frame 0)) + + (let ((proc (the skill (ppointer->process (birth-pickup-at-point vec (pickup-type skill) amount #t *active-pool* fax))))) + (when bob? + (set! (-> proc bob-amount) 1024.0) + ) + (format 0 "spawned ~A~%" proc) + ;; return handle to the orb + (process->handle proc) + ) + ) + ) + +(defun spawn-skill-meters ((x float) (y float) (z float) (amount float) (bob? symbol)) + (let ((vec (new 'stack-no-clear 'vector))) + (set-vector-meters! vec x y z) + (spawn-skill vec amount bob?) + ) + ) \ No newline at end of file diff --git a/goal_src/jak3/engine/mods/mod-custom-code.gc b/goal_src/jak3/engine/mods/mod-custom-code.gc new file mode 100644 index 0000000000..9aea3501e6 --- /dev/null +++ b/goal_src/jak3/engine/mods/mod-custom-code.gc @@ -0,0 +1,119 @@ + ;;-*-Lisp-*- + (in-package goal) + + ;; name: mod-custom-code.gc + ;; name in dgo: mod-custom-code + ;; dgos: TODO + + + ;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; What is this file for. + ;;;;;;;;;;;;;;;;;;;;;;;;;; + + #| This file contains function defenitions that are pre placed in the mod base, + so if you place custom code inside of these functions, it will exectue based on + the name of the function, for example, if you place (set! (-> *game-info* fuel) (+ (-> *game-info* fuel) 1)) + to the function named runs-on-orb-pickup, then jaks powercell count will increase each time you collect + an orb |# + + + ;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Begin function defintions. + ;;;;;;;;;;;;;;;;;;;;;;;;;; + + (defun runs-every-frame () + ;; (increase-power-cell-by-one) This is a call to increase-power-cell-by-one defined in mod-common-functions.gc + + ;; Sample code to turn jak pink whenever he's doing the jetboard hover glitch + ;; (when *target* + ;; (if (board-hovering?) + ;; (draw-pink *target*) + ;; (draw-normal *target*) + ;; ) + ;; ) + + (if *show-input-display* + (input-display-on) + (input-display-off) + ) + + (when *debug-segment* + (orb-placer-maintenance) + ) + + (none) + ) + + (defun runs-on-gem-pickup () + ;; Code here runs on any scout fly pickup + + (none) + ) + + (defun runs-on-task-close () + + + (none) + ) + + (defun runs-on-eco-pickup ((eco-type pickup-type) (parent process-tree)) + (let* ((from-vent? #f)) + ;; Code here runs as soon as you pickup ANY eco + + (case eco-type + (((pickup-type eco-yellow)) + ;; Code here runs as soon as you pickup yellow eco + + ) + (((pickup-type eco-red)) + ;; Code here runs as soon as you pickup red eco + + ) + (((pickup-type eco-blue)) + ;; Code here runs as soon as you pickup blue eco + + ) + + (((pickup-type eco-green)) + ;; Code here runs as soon as you pickup big green eco + + ) + ) + + (when from-vent? + ;; Code here runs only if the eco was picked up from a vent + + ) + ) + + (none) + ) + + (defun runs-on-jak-spawn () + ;; Code here runs every time jak spawns (loading a file new game or death) + + (none) + ) + + (defun runs-on-jak-death ((death-event symbol)) + (case death-event + (('dying) + ;; Code here runs immediately every time jak dies, before any death animation or death cutscene + + ) + (('blackout) + ;; Code here runs after jak dies (and any death cutscene finishes), during the blackout before he spawns + + ) + ) + + (none) + ) + + + ;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; deprecated function defintions. + ;;;;;;;;;;;;;;;;;;;;;;;;;; + + #| these are no longer recommended/supported however we include them anyways to not break anyones mods. + |# diff --git a/goal_src/jak3/engine/mods/mod-debug.gc b/goal_src/jak3/engine/mods/mod-debug.gc new file mode 100644 index 0000000000..feec7bb609 --- /dev/null +++ b/goal_src/jak3/engine/mods/mod-debug.gc @@ -0,0 +1,34 @@ +;;-*-Lisp-*- +(in-package goal) + +;; For debug-only additions to the mod-base. Anything defined in this file will be unavailable in retail mode. +(declare-file (debug)) + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Additional debug menu(s) +;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun-debug debug-menu-make-modding-tools-menu ((ctx debug-menu-context)) + (let ((modding-tools-menu (new 'debug 'debug-menu ctx "Modding Tools"))) + + ;; orb-placer menu + (let ((orb-placer-menu (new 'debug 'debug-menu ctx "Orb Placer"))) + (debug-menu-append-item orb-placer-menu (new-dm-bool "Edit Mode?" *orb-placer-enabled?* dm-boolean-toggle-pick-func)) + (debug-menu-append-item orb-placer-menu (new-dm-func "Add Orb" #f orb-placer-add)) + (let ((select-orb-menu (new 'debug 'debug-menu ctx "Select Orb"))) + (set! *orb-placer-select-menu* select-orb-menu) + ;; populated on orb add + (debug-menu-append-item orb-placer-menu (new-dm-submenu "Select Orb" select-orb-menu)) + ) + (debug-menu-append-item orb-placer-menu (new-dm-func "Print Selected Orb Position" #f orb-placer-print-selected)) + (debug-menu-append-item orb-placer-menu (new-dm-func "Print All Orb Positions" #f orb-placer-print-all)) + + (debug-menu-append-item modding-tools-menu (new-dm-submenu "Orb Placer" orb-placer-menu)) + ) + (new-dm-submenu "Modding Tools" modding-tools-menu) + ) + ) + +(when (-> *debug-menu-context* root-menu) + (debug-menu-append-item (-> *debug-menu-context* root-menu) (debug-menu-make-modding-tools-menu *debug-menu-context*)) + ) \ No newline at end of file diff --git a/goal_src/jak3/engine/mods/mod-settings.gc b/goal_src/jak3/engine/mods/mod-settings.gc new file mode 100644 index 0000000000..58f3548ade --- /dev/null +++ b/goal_src/jak3/engine/mods/mod-settings.gc @@ -0,0 +1,50 @@ +;;-*-Lisp-*- +(in-package goal) + +;; name: mod-common-functions.gc +;; name in dgo: mod-common-functions +;; dgos: TODO + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; What is this file for. +;;;;;;;;;;;;;;;;;;;;;;;;;; + +#| This file is a place where you can define custom functions and GOAL code + to call inside of mod-custom-code.gc for example I have defined a function that increases + the powercell count by one when it is called + |# + + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Useful GOAL modding documentation +;;;;;;;;;;;;;;;;;;;;;;;;;; + +#| +Checks the condition and if it is true it does first argument if false it does optional second argument +(if (condition) (do if true) (do if false)) + +Gives a random FLOAT or INT between the provided ranges when called +(rand-vu-float-range 0.0 2.0) +(rand-vu-int-range 0 10) + +if the result of rand-vu-int-range is 1, then DANCE! if it is not 1, then Don't dance +(if (= (rand-vu-int-range 0 10) 1) (DANCE!) (Don't dance)) + + +|# + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Define Settings to use in mods +;;;;;;;;;;;;;;;;;;;;;;;;;; + + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Define Custom Settings Variables to use in mods +;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Change #f to #t here to show the input display by default +(define *show-input-display* #f) + +;; do NOT change %MODVERSIONPLACEHOLDER% below, otherwise the mod-bundling-tools +;; will be unable to automatically add version info to the speedrun display +(define *mod-version-text* "%MODVERSIONPLACEHOLDER%") \ No newline at end of file diff --git a/goal_src/jak3/engine/mods/orb-placer.gc b/goal_src/jak3/engine/mods/orb-placer.gc new file mode 100644 index 0000000000..03f469a2f3 --- /dev/null +++ b/goal_src/jak3/engine/mods/orb-placer.gc @@ -0,0 +1,402 @@ +(in-package goal) + +(declare-file (debug)) + +;; controls whether the orb-placer process will run +(define *orb-placer-enabled?* #f) + +;; number of orbs orb-placer has placed +(define *orb-placer-count* 0) + +;; max number of orbs +(defconstant ORB_PLACER_MAX 100) + +;; index of currently selected orb for placing +(define *orb-placer-selected-idx* -1) + +;; array of handles to orbs that have been spawned by orb-placer +(define *orb-placer-orbs* (new 'global 'boxed-array handle ORB_PLACER_MAX)) + +(define *orb-placer-temp-strs* (new 'static 'boxed-array :type string :length ORB_PLACER_MAX + "orba-00" + "orba-01" + "orba-02" + "orba-03" + "orba-04" + "orba-05" + "orba-06" + "orba-07" + "orba-08" + "orba-09" + "orba-10" + "orba-11" + "orba-12" + "orba-13" + "orba-14" + "orba-15" + "orba-16" + "orba-17" + "orba-18" + "orba-19" + "orba-20" + "orba-21" + "orba-22" + "orba-23" + "orba-24" + "orba-25" + "orba-26" + "orba-27" + "orba-28" + "orba-29" + "orba-30" + "orba-31" + "orba-32" + "orba-33" + "orba-34" + "orba-35" + "orba-36" + "orba-37" + "orba-38" + "orba-39" + "orba-40" + "orba-41" + "orba-42" + "orba-43" + "orba-44" + "orba-45" + "orba-46" + "orba-47" + "orba-48" + "orba-49" + "orba-50" + "orba-51" + "orba-52" + "orba-53" + "orba-54" + "orba-55" + "orba-56" + "orba-57" + "orba-58" + "orba-59" + "orba-60" + "orba-61" + "orba-62" + "orba-63" + "orba-64" + "orba-65" + "orba-66" + "orba-67" + "orba-68" + "orba-69" + "orba-70" + "orba-71" + "orba-72" + "orba-73" + "orba-74" + "orba-75" + "orba-76" + "orba-77" + "orba-78" + "orba-79" + "orba-80" + "orba-81" + "orba-82" + "orba-83" + "orba-84" + "orba-85" + "orba-86" + "orba-87" + "orba-88" + "orba-89" + "orba-90" + "orba-91" + "orba-92" + "orba-93" + "orba-94" + "orba-95" + "orba-96" + "orba-97" + "orba-98" + "orba-99" + )) + +;; global for this so we can repopulate it as needed +(define *orb-placer-select-menu* (the-as debug-menu #f)) + +(defun dm-orb-placer-select-func ((idx int) (msg debug-menu-msg)) + (when (= msg (debug-menu-msg press)) + (cond + ((= *orb-placer-selected-idx* idx) + ;; deselect + (set! *orb-placer-selected-idx* -1) + (set! *orb-placer-enabled?* #f) + ) + (else + ;; select + (set! *orb-placer-selected-idx* idx) + (set! *orb-placer-enabled?* #t) + ) + ) + ) + (= *orb-placer-selected-idx* idx) + ) + +(defun orb-placer-highlight ((orb skill) (highlight? symbol)) + (cond + (highlight? + (set-vector! (-> orb draw color-mult) 0.8 0.8 0.0 1.0) + (set-vector! (-> orb draw color-emissive) 0.0 1.0 0.2 1.0) + ) + (else + (set-vector! (-> orb draw color-mult) 0.8 0.8 0.8 1.0) + (set-vector! (-> orb draw color-emissive) 0.2 0.2 0.2 1.0) + ) + ) + (none) + ) + +(defun orb-placer-list-maintenace ((update-debug-list? symbol)) + (when update-debug-list? (debug-menu-remove-all-items *orb-placer-select-menu*)) + + (dotimes (i *orb-placer-count*) + (let ((orb-handle (-> *orb-placer-orbs* i)) + (is-selected? (and *orb-placer-enabled?* (= i *orb-placer-selected-idx*)))) + (when (and (nonzero? orb-handle) (handle->process orb-handle)) + (let ((orb-proc (the skill (handle->process orb-handle)))) + (when (and orb-proc (!= (-> orb-proc next-state name) 'dead-state)) + ;; ensure correct highlighting + (orb-placer-highlight + orb-proc + is-selected? + ) + + ;; draw z-debug text + (add-debug-text-3d + #t + (bucket-id debug-no-zbuf1) + (-> *orb-placer-temp-strs* i) + (-> orb-proc base) + (if is-selected? (font-color red) (font-color white)) + (new 'static 'vector2h :y 16) + ) + + (when update-debug-list? + ;; append to debug menu list + (let ((orb-menu-item (new-dm-flag (-> *orb-placer-temp-strs* i) i dm-orb-placer-select-func))) + (debug-menu-append-item *orb-placer-select-menu* orb-menu-item) + (when is-selected? + (set! (-> *orb-placer-select-menu* selected-item) orb-menu-item) + ) + ) + ) + ) + ) + ) + ) + ) + + (when update-debug-list? + (set! (-> *orb-placer-select-menu* items) (sort (-> *orb-placer-select-menu* items) debug-menu-node *target* root trans)) + (+! (-> vec y) (meters 2.0)) ;; dont spawn in ground + ) + (else + ;; use camera position + (vector-copy! vec (-> *math-camera* trans)) + ) + ) + ;; convert the camera angle from a matrix to a quaternion (???) + (matrix->quaternion camera-quat (-> *camera-combiner* inv-camera-rot)) + ;; convert the quaternion to a vector representing rotation around z axis (isnt it the y axis in GOAL tho?) + (vector-z-quaternion! camera-z-vector camera-quat) + ;; shift orb's position with camera angle, by 3m + (vector+! vec vec (vector-normalize! camera-z-vector (meters 3.0))) + + ;; spawn and update orb-placer data + (let ((orb-handle (spawn-skill vec 1.0 #t))) + (when (nonzero? orb-handle) + (set! (-> *orb-placer-orbs* *orb-placer-count*) orb-handle) + (set! *orb-placer-selected-idx* *orb-placer-count*) + (orb-placer-highlight (the skill (handle->process orb-handle)) #t) + (+! *orb-placer-count* 1) + (orb-placer-list-maintenace #t) + ) + ) + ) + ) + (none) + ) + +(defun orb-placer-print-selected () + (when (and (>= *orb-placer-selected-idx* 0) (nonzero? (-> *orb-placer-orbs* *orb-placer-selected-idx*))) + (let ((orb (the skill (handle->process (-> *orb-placer-orbs* *orb-placer-selected-idx*))))) + (when orb + (format 0 " ~m, ~m, ~m~%" (-> orb base x) (-> orb base y) (-> orb base z)) + ) + ) + ) + (none) + ) + +(defun orb-placer-print-all () + (format 0 "|------------orba start------------|~%") + (dotimes (i *orb-placer-count*) + (let ((orb-handle (-> *orb-placer-orbs* i))) + (when (and (nonzero? orb-handle) (handle->process orb-handle)) + (let ((orb (the skill (handle->process orb-handle)))) + (format 0 " ~m, ~m, ~m~%" (-> orb base x) (-> orb base y) (-> orb base z)) + ) + ) + ) + ) + (format 0 "|-------------orba end-------------|~%") + (none) + ) + +;; called from run-every-frame to ensure orb-placer is spawned/killed +(define *orb-offset-tmp-vec* (new 'global 'vector)) +(defun orb-placer-maintenance () + (when *debug-segment* + (orb-placer-list-maintenace #f) + + (when (and (not (paused?)) *orb-placer-enabled?*) + (with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf)) + (bucket-id debug-no-zbuf1)) + (let ((font-ctx (new 'stack 'font-context *font-default-matrix* 510 2 0.0 (font-color red) (font-flags right shadow kerning large)))) + (set! (-> font-ctx scale) 0.325) + (draw-string-adv "Orb Placer Edit Mode" buf font-ctx) + ) + ) + ) + + + (cond + ((process-by-name "orb-placer" *active-pool*) + ;; orb-placer exists + ;; if its not enabled, kill it + (when (not (and *debug-segment* *orb-placer-enabled?*)) + + (kill-by-name "orb-placer" *active-pool*) + + ;; make sure target is ungrabbed + (when (not (process-grab? *target* #f)) + (process-release? *target*) + ) + ;; release any camera modes + (remove-setting! 'mode-name) + ) + ) + (else + ;; orb-placer doesn't exist + ;; if its enabled, spawn it + (when (and *debug-segment* *orb-placer-enabled?*) + ;; process-spawn-function, spawns a process that runs the function you give it + (process-spawn-function process :name "orb-placer" + (lambda :behavior process () + (stack-size-set! (-> self top-thread) 512) + ;; Code before the loop runs once on process spawn + + (let ((pad (-> *cpad-list* cpads 0)) + (vec *orb-offset-tmp-vec*)) + (loop + ;; Loop runs once per frame while process is active + + ;; make sure target is grabbed + (when (and *target* (!= (-> *target* next-state name) 'target-grab)) + (send-event *target* 'change-mode 'grab) + ) + ;; lock freecam if no target + (when (and (not *target*) (not (send-event *camera* 'query-state cam-fixed))) + (set-setting! 'mode-name 'cam-fixed 0.0 0) + ) + ;; if we have an orb selected and the handle is nonzero... + (when (and (>= *orb-placer-selected-idx* 0) (nonzero? (-> *orb-placer-orbs* *orb-placer-selected-idx*))) + (let ((orb (the skill (handle->process (-> *orb-placer-orbs* *orb-placer-selected-idx*))))) + (when orb + ;; highlight it + (orb-placer-highlight orb #t) + + ;; respond to controller input + + ;; X/Z based on camera + (when (nonzero? (-> pad stick0-speed)) + (set! (-> vec x) (sin (-> pad stick0-dir))) + (set! (-> vec y) 0.0) + (set! (-> vec z) (cos (-> pad stick0-dir))) + (set! (-> vec w) 0.0) + ;; camera magic + (vector-matrix*! vec vec (matrix-local->world #t #f)) + (vector-flatten! vec vec (-> *camera* local-down)) + (vector-float*! vec vec (* (-> pad stick0-speed) 512.0)) + + ;; actually move orb + (vector+! (-> orb root trans) (-> orb root trans) vec) + (vector+! (-> orb base) (-> orb base) vec) + ) + + + (cond + ;; fine tune/axis-aligned X/Z + ((cpad-pressed? 0 down) + (+! (-> orb root trans z) (meters 0.03)) + (+! (-> orb base z) (meters 0.03)) + ) + ((cpad-pressed? 0 up) + (+! (-> orb root trans z) (meters -0.03)) + (+! (-> orb base z) (meters -0.03)) + ) + ((cpad-pressed? 0 right) + (+! (-> orb root trans x) (meters 0.03)) + (+! (-> orb base x) (meters 0.03)) + ) + ((cpad-pressed? 0 left) + (+! (-> orb root trans x) (meters -0.03)) + (+! (-> orb base x) (meters -0.03)) + ) + ;; Y (up/down) + ((cpad-hold? 0 r2) + (+! (-> orb root trans y) (meters 0.08)) + (+! (-> orb base y) (meters 0.08)) + ) + ((cpad-hold? 0 l2) + (+! (-> orb root trans y) (meters -0.08)) + (+! (-> orb base y) (meters -0.08)) + ) + ((cpad-pressed? 0 r1) + (+! (-> orb root trans y) (meters 0.03)) + (+! (-> orb base y) (meters 0.03)) + ) + ((cpad-pressed? 0 l1) + (+! (-> orb root trans y) (meters -0.03)) + (+! (-> orb base y) (meters -0.03)) + ) + ) + ) + ) + ) + + ;; Processes should suspend themselves, the loop will resume next frame + (suspend) + ) + ) + ) + ) + ) + ) + ) + ) + (none) + ) \ No newline at end of file diff --git a/goal_src/jak3/engine/ui/text-h.gc b/goal_src/jak3/engine/ui/text-h.gc index 6f4ed4e613..3701f5f02b 100644 --- a/goal_src/jak3/engine/ui/text-h.gc +++ b/goal_src/jak3/engine/ui/text-h.gc @@ -1612,7 +1612,11 @@ (trick-board-lightjak-swoop #x136a) (trick-board-lightjak-freeze #x136b) (trick-board-lightjak-shield #x136c) - + ;; mod text + (pad-triangle #x2000) + (pad-circle #x2001) + (pad-x #x2002) + (pad-square #x2003) ) ;; ---text-id From a590de377d47aa484696a5dc7b3d6a8c31848a2b Mon Sep 17 00:00:00 2001 From: Nick0778 <149975116+Nick0778@users.noreply.github.com> Date: Sun, 17 May 2026 22:08:56 -0300 Subject: [PATCH 2/7] air-train/warp-gate menu system implementation --- .../jak3/text/game_custom_text_en-US.json | 15 +- goal_src/jak3/dgos/game.gd | 7 +- .../mods/air-train-menu/air-train-menu-h.gc | 86 + .../mods/air-train-menu/air-train-menu.gc | 383 ++++ .../warp-gate-menu/warp-gate-menu-data.gc | 1712 +++++++++++++++++ .../mods/warp-gate-menu/warp-gate-menu-h.gc | 240 +++ .../mods/warp-gate-menu/warp-gate-menu.gc | 425 ++++ goal_src/jak3/engine/ui/text-h.gc | 16 + 8 files changed, 2882 insertions(+), 2 deletions(-) create mode 100644 goal_src/jak3/engine/mods/air-train-menu/air-train-menu-h.gc create mode 100644 goal_src/jak3/engine/mods/air-train-menu/air-train-menu.gc create mode 100644 goal_src/jak3/engine/mods/warp-gate-menu/warp-gate-menu-data.gc create mode 100644 goal_src/jak3/engine/mods/warp-gate-menu/warp-gate-menu-h.gc create mode 100644 goal_src/jak3/engine/mods/warp-gate-menu/warp-gate-menu.gc diff --git a/game/assets/jak3/text/game_custom_text_en-US.json b/game/assets/jak3/text/game_custom_text_en-US.json index 70d1c1a215..1efb97fcf6 100644 --- a/game/assets/jak3/text/game_custom_text_en-US.json +++ b/game/assets/jak3/text/game_custom_text_en-US.json @@ -265,5 +265,18 @@ "2000": "", "2001": "", "2002": "", - "2003": "" + "2003": "", + + "10000": "Haven City Port", + "10001": "Desert Wasteland", + "10002": "Volcano", + "10003": "Temple (Entrance)", + "10004": "Temple (Oracle)", + "10005": "Temple (Ruins)", + "10006": "Power Station", + + "100000": "Select Destination", + "100001": "No Menu Data", + "100002": "Next Page", + "100003": "Previous Page" } diff --git a/goal_src/jak3/dgos/game.gd b/goal_src/jak3/dgos/game.gd index 9ba8e1373f..671e2b0963 100644 --- a/goal_src/jak3/dgos/game.gd +++ b/goal_src/jak3/dgos/game.gd @@ -482,7 +482,12 @@ "simple-nav-sphere.o" "process-taskable.o" "scene-actor.o" - "warp-gate.o" + "warp-gate.o" ;; original warp-gate logic - be sure to comment this out if using the menu system logic below + ;"warp-gate-menu-h.o" ;; added - warp-gate menu definitions file (commented out by default) + ;"air-train-menu-h.o" ;; added - air-train menu definitions file (commented out by default) + ;"warp-gate-menu-data.o" ;; added - type definitions for warp-gate and air-train with menu logic (commented out by default) + ;"warp-gate-menu.o" ;; added - warp-gate menu logic (commented out by default) + ;"air-train-menu.o" ;; added - air-train menu logic (commented out by default) "guard-projectile.o" "metalhead-projectile.o" "los-control.o" diff --git a/goal_src/jak3/engine/mods/air-train-menu/air-train-menu-h.gc b/goal_src/jak3/engine/mods/air-train-menu/air-train-menu-h.gc new file mode 100644 index 0000000000..ea7ac82100 --- /dev/null +++ b/goal_src/jak3/engine/mods/air-train-menu/air-train-menu-h.gc @@ -0,0 +1,86 @@ +;;-*-Lisp-*- +(in-package goal) + +#| This file defines the air-train destination menu structure and its related lists. + Each menu list corresponds to a specific air-train entity and contains + destinations Jak can warp to, based on mission/task progress. + + Also, check the method `init-defaults!` of the `air-train` type in `warp-gate-menu-data.gc`, + which is responsible for assigning a menu entry list to a specific entity. Do this if you + want to add custom air-train menus in your own custom levels. + |# + +(deftype air-train-menu-entry (structure) + ((level-name symbol) ;; level name + (continue-name string) ;; name of the checkpoint Jak will be teleported to + (text-id text-id) ;; text ID that defines the name displayed for this destination in the menu + (allow-when (function symbol)) ;; optional: function that must return true for this entry to become available + (forbid-when (function symbol)) ;; optional: function that hides this entry if it returns true, regardless of `allow-when` + (on-activate pair) ;; optional: actions executed when the destination is selected (e.g., play scenes, load levels, close tasks) + ) + ) + +(defmacro static-air-train-menu-entry (&key level-name + &key continue-name + &key text-id + &key (allow-when #f) + &key (forbid-when #f) + &key (on-activate #f)) + `(new 'static 'air-train-menu-entry + :level-name ,level-name + :continue-name ,continue-name + :text-id ,text-id + :allow-when ,allow-when + :forbid-when ,forbid-when + :on-activate ,on-activate + ) + ) + +(deftype air-train-menu-data (structure) + ((visible-when (function symbol)) ;; optional: function to control visibility; if null or returns true, air-train is shown + (menu-list (array air-train-menu-entry)) ;; the list of menu entries + ) + ) + +(defmacro static-air-train-menu-data (&key (visible-when #f) &key menu-list) + `(new 'static 'air-train-menu-data + :visible-when ,visible-when + :menu-list (new 'static 'boxed-array :type air-train-menu-entry ,@menu-list) + ) + ) + +;; just an empty array. leave it at is. +;; used as a fallback when an entity doesn't have a defined menu. +(define *empty-air-train-menu-data* (static-air-train-menu-data :visible-when #f :menu-list ())) + +;; ctyport air-train +(define *air-train-1-menu-data* (static-air-train-menu-data + :visible-when #f ;; air-train will be always visible + :menu-list ( + (static-air-train-menu-entry + :level-name 'desertb + :continue-name "desert-warp" + :text-id (text-id desert-name) ;"Desert Wasteland" + :allow-when (lambda () (task-closed? "city-destroy-grid-resolution")) ;; jinx's mission required + :forbid-when #f + :on-activate '(scene-play '("city-air-train-in-desert" "desert-air-train-out")) + ) + ) + ) + ) + +;; desert air-train +(define *air-train-5-menu-data* (static-air-train-menu-data + :visible-when (lambda () (task-closed? "city-destroy-grid-resolution")) ;; air-train will be invisible until jinx's mission is completed + :menu-list ( + (static-air-train-menu-entry + :level-name 'ctyport + :continue-name "ctyport-warp" + :text-id (text-id ctyport-name) ;"Haven City Port" + :allow-when #f + :forbid-when #f + :on-activate '(scene-play '("desert-air-train-in" "city-air-train-out")) + ) + ) + ) + ) diff --git a/goal_src/jak3/engine/mods/air-train-menu/air-train-menu.gc b/goal_src/jak3/engine/mods/air-train-menu/air-train-menu.gc new file mode 100644 index 0000000000..13f46a76bf --- /dev/null +++ b/goal_src/jak3/engine/mods/air-train-menu/air-train-menu.gc @@ -0,0 +1,383 @@ +;;-*-Lisp-*- +(in-package goal) + +(define *wm-selected* -1) +(define *wm-at-items-per-page* 6) + +(defmethod warp-select-menu ((this air-train)) + (let* ((data (-> this menu-data)) + (menu (-> data menu-list)) + (list-length (-> menu length)) + (available-idxs (new 'static 'boxed-array :type int32)) ;; array to store the indexes of the options that are available for selection + (available-count 0) ;; stores the amount of options that are available for selection + ) + (dotimes (i list-length) + (let* ((allowed? (-> menu i allow-when)) + (forbidden? (-> menu i forbid-when))) + ;; include the option if `allowed?` is set and returns true, + ;; and `forbidden?` is either not set (not forbidden?) or does not return true (not (forbidden?)). + (when (and (or (not allowed?) (allowed?)) + (or (not forbidden?) (not (forbidden?)))) + (set! (-> available-idxs available-count) i) ;; store the available option indexes in `available-idxs` array + (+! available-count 1) + ) + ) + ) + + (let* ((page (-> this page)) ;; current page + (start-idx (* page *wm-at-items-per-page*)) ;; start index of the current page + (end-idx (+ start-idx *wm-at-items-per-page*)) ;; exclusive end index for the current page, used to check if there's a next page + (have-next-page? (< end-idx available-count)) ;; is there a next page? + (have-prev-page? (> page 0)) ;; is there a previous page? + (items-this-page (min *wm-at-items-per-page* (- available-count start-idx))) ;; amount of items in this page (only destination options is counted) + (extra-options (cond ((and have-prev-page? have-next-page?) 2) ;; add 2 if have next and previous pages + (have-prev-page? 1) ;; add 1 if only have previous page + (have-next-page? 1) ;; add 1 if only have next page + (else 0))) ;; no extra option + (total-items (+ items-this-page extra-options)) ;; total entries displayed on screen + ) + (when (not (paused?)) + (cond + ((and (cpad-pressed? 0 up l-analog-up) (> (-> this selected) 0)) + (seekl! (-> this selected) 0 1) + (sound-play "dmenu-move") + ) + ((and (cpad-pressed? 0 down l-analog-down) (< (-> this selected) (+ total-items -1))) + (seekl! (-> this selected) (+ total-items -1) 1) + (sound-play "dmenu-move") + ) + ((and (cpad-pressed? 0 confirm) (nonzero? available-count)) + (sound-play "menu-pick") + (cond + ((and have-prev-page? (= (-> this selected) items-this-page)) ;; go to the previous page + (+! (-> this page) -1) + (set! (-> this selected) 0) + ) + ((and have-next-page? (or (and have-prev-page? (= (-> this selected) (+ items-this-page 1))) ;; go to the next page + (and (not have-prev-page?) (= (-> this selected) items-this-page)))) + (+! (-> this page) 1) + (set! (-> this selected) 0) + ) + (else ;; warp to the selected destination + (set! *wm-selected* (-> available-idxs (+ start-idx (-> this selected)))) + (go air-train-warp) + ) + ) + ) + ) + (let* ((font-height 40) + (font-x 36) + (font-y (- 228 (* total-items (/ font-height 2)))) + (font-ctxt (new + 'stack + 'font-context + *font-default-matrix* + font-x + font-y + 0.0 + (font-color default) + (font-flags shadow kerning) + ) + ) + ) + (set! (-> font-ctxt flags) (font-flags shadow kerning middle middle-vert large)) + (set! (-> font-ctxt width) (the float 440)) + (set! (-> font-ctxt height) (the float 50)) + (set! (-> font-ctxt scale) 1.0) + (let ((a0-59 40)) + (set! (-> font-ctxt origin x) (the float font-x)) + (set! (-> font-ctxt origin y) (the float a0-59)) + ) + ;; print menu header + (set! (-> font-ctxt color) (font-color progress-old-yellow)) + (let ((select-text (lookup-text! *common-text* (text-id select-destination) #f))) + (format (clear *temp-string*) select-text) + ) + (print-game-text *temp-string* font-ctxt #f 44 (bucket-id hud-draw-hud-alpha)) + (set! (-> font-ctxt height) (the float font-height)) + ;; print menu options + (cond + ((nonzero? available-count) ;; menu have data, print the options on the screen. + (dotimes (i items-this-page) + (let ((valid-idx (-> available-idxs (+ start-idx i)))) + (set! (-> font-ctxt origin x) (the float font-x)) + (set! (-> font-ctxt origin y) (the float font-y)) + (set! (-> font-ctxt scale) (if (= (-> this selected) i) + 0.8 + 0.6 + ) + ) + (set! (-> font-ctxt color) (if (= (-> this selected) i) + (font-color progress-old-selected) + (font-color default) + ) + ) + (print-game-text (lookup-text! *common-text* (-> menu valid-idx text-id) #f) font-ctxt #f 44 (bucket-id hud-draw-hud-alpha)) + (+! font-y font-height) + ) + ) + (when have-prev-page? ;; print `Previous Page` if there is a previous page indeed + (set! (-> font-ctxt origin x) (the float font-x)) + (set! (-> font-ctxt origin y) (the float font-y)) + (set! (-> font-ctxt scale) (if (= (-> this selected) items-this-page) + 0.8 + 0.6 + ) + ) + (set! (-> font-ctxt color) (if (= (-> this selected) items-this-page) + (font-color progress-old-selected) + (font-color default) + ) + ) + (print-game-text (lookup-text! *common-text* (text-id previous-page) #f) font-ctxt #f 44 (bucket-id hud-draw-hud-alpha)) + (+! font-y font-height) + ) + (when have-next-page? ;; print `Next Page` if there is a next page indeed + (set! (-> font-ctxt origin x) (the float font-x)) + (set! (-> font-ctxt origin y) (the float font-y)) + (set! (-> font-ctxt scale) (if (= (-> this selected) (- total-items 1)) + 0.8 + 0.6 + ) + ) + (set! (-> font-ctxt color) (if (= (-> this selected) (- total-items 1)) + (font-color progress-old-selected) + (font-color default) + ) + ) + (print-game-text (lookup-text! *common-text* (text-id next-page) #f) font-ctxt #f 44 (bucket-id hud-draw-hud-alpha)) + (+! font-y font-height) + ) + ) + (else ;; no menu data, print an error message on the screen. + (set! (-> font-ctxt origin x) (the float font-x)) + (set! (-> font-ctxt origin y) (the float font-y)) + (set! (-> font-ctxt scale) 0.8) + (set! (-> font-ctxt color) (font-color default)) + (print-game-text (lookup-text! *common-text* (text-id no-menu-data) #f) font-ctxt #f 44 (bucket-id hud-draw-hud-alpha)) + ) + ) + ) + ) + ) + ) + (none) + ) + +(defmethod set-warp! ((this air-train) (idx int)) + (let ((menu (-> (-> this menu-data menu-list) idx))) + (set! (-> this level-name) (-> menu level-name)) + (set! (-> this continue) (get-continue-by-name *game-info* (-> menu continue-name))) + (set! (-> this on-activate) (the-as pair (-> menu on-activate))) + ) + (none) + ) + +(defmethod warp-to-continue ((this air-train)) + (kill-current-talker '() '() 'exit) + (set-time! (-> this state-time)) + (logclear! (-> this mask) (process-mask actor-pause)) + (when (not (-> this continue)) + (process-release? *target*) + (go (method-of-object this idle)) + ) + (set-setting! 'allow-progress #f 0.0 0) + (set! (-> *setting-control* user-default border-mode) #t) + (set! (-> *level* play?) #t) + (apply-settings *setting-control*) + (sound-stop (-> this hover-sound)) + (set! (-> this hover-sound) (new 'static 'sound-id)) + (when (-> this on-activate) + (script-eval (-> this on-activate)) + ) + (suspend-for (seconds 1.5)) + (when (not (real-movie?)) + (start 'play (-> this continue)) + ) + (sleep-code) + (none) + ) + +(defmethod available-to-use? ((this air-train)) + (let* ((data (-> this menu-data)) + (menu (-> data menu-list)) + (list-length (-> menu length)) + ) + (dotimes (i list-length) + (let* ((allowed? (-> menu i allow-when)) + (forbidden? (-> menu i forbid-when))) + ;; include the option if `allowed?` is set and returns true, + ;; and `forbidden?` is either not set (not forbidden?) or does not return true (not (forbidden?)). + (when (and (or (not allowed?) (allowed?)) + (or (not forbidden?) (not (forbidden?)))) + (return #t) + ) + ) + ) + (when (zero? list-length) + (return #t) ;; treat empty lists as available so that it can be displayed the "No Menu Data" error message instead of disabling interaction + ) + ) + #f + ) + +(defmethod hide-air-train? ((this air-train)) + (let ((data (-> this menu-data))) + (if (or (not data) (not (-> data visible-when))) + (return #f) + ) + (if (not ((-> data visible-when))) + #t + #f + ) + ) + ) + +(defstate idle (air-train) + :virtual #t + :code (behavior () + (remove-setting! 'allow-progress) + (set-time! (-> self state-time)) + (update-transforms (-> self root)) + (until #f + ;; checks whether the air-train should be hidden or not + (if (hide-air-train? self) + (logior! (-> self draw status) (draw-control-status no-draw)) + (logclear! (-> self draw status) (draw-control-status no-draw)) + ) + (when (and (and *target* + (and (>= (-> self distance) (vector-vector-distance (-> self root trans) (-> *target* control trans))) + (not (logtest? (focus-status teleporting) (-> *target* focus-status))) + ) + ) + (not (hide-air-train? self)) + (available-to-use? self) + (can-display-query? self "warp-gate" -99.0) + (-> *setting-control* user-current airlock) + (begin + (persist-with-delay *setting-control* 'lightjak (seconds 0.1) 'lightjak #f 0.0 0) + (persist-with-delay *setting-control* 'darkjak (seconds 0.1) 'darkjak #f 0.0 0) + (persist-with-delay *setting-control* 'board (seconds 0.1) 'board #f 0.0 0) + (not (logtest? (focus-status in-head edge-grab pole flut tube light board pilot mech dark indax) + (-> *target* focus-status) + ) + ) + ) + (not (-> *setting-control* user-current hint)) + (zero? (-> *target* ext-anim)) + ) + (let ((gp-0 (new 'stack 'font-context *font-default-matrix* 32 320 0.0 (font-color default) (font-flags shadow kerning)))) + (set-width! gp-0 340) + (set-height! gp-0 80) + (let ((v1-60 gp-0) + (a0-25 (-> *setting-control* user-default language)) + ) + (set! (-> v1-60 scale) (if (or (= a0-25 (language-enum korean)) (= a0-25 (language-enum russian))) + 0.9 + 0.7 + ) + ) + ) + (set! (-> gp-0 flags) (font-flags shadow kerning large)) + (print-game-text + (lookup-text! *common-text* (text-id text-0083) #f) + gp-0 + #f + 44 + (bucket-id hud-draw-hud-alpha) + ) + ) + (when (cpad-pressed? 0 triangle) + (logclear! (-> *cpad-list* cpads 0 button0-abs 0) (pad-buttons triangle)) + (logclear! (-> *cpad-list* cpads 0 button0-rel 0) (pad-buttons triangle)) + (go air-train-menu) + ) + ) + (ja-post) + (suspend) + ) + #f + ) + :post (behavior () + (let ((t9-0 (-> (method-of-type warp-gate idle) post))) + (if t9-0 + ((the-as (function none) t9-0)) + ) + ) + (set! (-> self root trans y) (+ (-> self base-pos y) + (* 696.32 (cos (* 66.19798 (the float (mod (current-time) 990))))) + (* 450.56 (cos (* 42.25403 (the float (mod (current-time) 1551))))) + ) + ) + (spawn-from-cspace (-> self part-exhaust-left) (joint-node air-train-lod0-jg thruster_l)) + (spawn-from-cspace (-> self part-exhaust-right) (joint-node air-train-lod0-jg thruster_r)) + (let ((f0-9 (-> self dust-y))) + (when (!= f0-9 (the-as float #x7f800000)) + (let ((a1-2 (new 'stack-no-clear 'vector))) + (vector-copy! a1-2 (-> self root trans)) + (set! (-> a1-2 y) f0-9) + (spawn (-> self part-dust) a1-2) + ) + ) + ) + (sound-play "air-train" :id (-> self hover-sound) :position (-> self root trans)) + ) + ) + +(defstate air-train-menu (air-train) + :enter (behavior () + (set-setting! 'minimap 'clear 0.0 (minimap-flag minimap)) + (set-time! (-> self state-time)) + ) + :exit (behavior () + (remove-setting! 'minimap) + (send-event *camera* 'change-target *target*) + (remove-setting! 'interp-time) + (remove-setting! 'mode-name) + ) + :trans (behavior () + ;(format *stdcon* "selected: ~D~%" *wm-selected*) + ;(format *stdcon* "page: ~D~%" (-> self page)) + (when (time-elapsed? (-> self state-time) (seconds 0.5)) + (warp-select-menu self) + (when (cpad-pressed? 0 triangle) + (when (and (not (process-grab? *target* #f)) (not (real-movie?))) + (process-release? *target*) + ) + (go-virtual idle) + ) + ) + ) + :code (behavior () + (set-setting! 'mode-name 'cam-really-fixed 0.0 0) + (suspend) + (until (process-grab? *target* #f) + (suspend) + ) + (sleep-code) + ) + :post (behavior () + (let ((t9-0 (-> (method-of-type air-train idle) post))) + (if t9-0 + ((the-as (function none) t9-0)) + ) + ) + ) + ) + +(defstate air-train-warp (air-train) + :enter (behavior () + (set-warp! self *wm-selected*) + ) + :code (behavior () + (warp-to-continue self) + ) + :post (behavior () + (let ((t9-0 (-> (method-of-type air-train idle) post))) + (if t9-0 + ((the-as (function none) t9-0)) + ) + ) + ) + ) + \ No newline at end of file diff --git a/goal_src/jak3/engine/mods/warp-gate-menu/warp-gate-menu-data.gc b/goal_src/jak3/engine/mods/warp-gate-menu/warp-gate-menu-data.gc new file mode 100644 index 0000000000..562f2fec0f --- /dev/null +++ b/goal_src/jak3/engine/mods/warp-gate-menu/warp-gate-menu-data.gc @@ -0,0 +1,1712 @@ +;;-*-Lisp-*- +(in-package goal) + +;; name: warp-gate-menu-data.gc +;; name in dgo: warp-gate-menu-data +;; dgos: GAME + +(define-extern v-marauder type) +(define-extern *range-warp-dust-color* curve-color-fast) +(define-extern *range-warp-dust-alpha* curve2d-fast) +(define-extern *range-warp-dust-scale-x* curve2d-fast) +(define-extern *range-warp-dust-scale-y* curve2d-fast) +(define-extern *curve-warp-dust-alpha* curve2d-fast) +(define-extern *curve-warp-dust-scale-x* curve2d-fast) +(define-extern *curve-warp-dust-scale-y* curve2d-fast) + +;; DECOMP BEGINS + +(defpartgroup group-warpgate + :id 202 + :duration (seconds 0.267) + :flags (sp0 sp6) + :bounds (static-bspherem 0 0 0 8) + :rotate ((degrees 90) (degrees 0) (degrees 0)) + :parts ((sp-item 825 :flags (is-3d sp3 sp7)) (sp-item 826 :flags (sp3)) (sp-item 827 :flags (sp7))) + ) + +(defpart 825 + :init-specs ((:texture (middot level-default-sprite)) + (:num 1.0) + (:scale-x (meters 4.75)) + (:scale-y :copy scale-x) + (:r 255.0) + (:g 255.0) + (:b 255.0) + (:a 196.0) + (:fade-a -3.1875) + (:timer (seconds 0.267)) + (:flags (sp-cpuinfo-flag-2)) + (:rotate-y (degrees 0)) + ) + ) + +(defpart 826 + :init-specs ((:texture (glow level-default-sprite)) + (:num 1.0) + (:scale-x (meters 14)) + (:rot-x (degrees 11.25)) + (:rot-z (degrees 0) (degrees 3600)) + (:scale-y :copy scale-x) + (:r 255.0) + (:g 255.0) + (:b 255.0) + (:a 48.0) + (:fade-a -0.8) + (:timer (seconds 0.267)) + (:flags (glow)) + (:userdata 4096.0) + ) + ) + +(defpart 827 + :init-specs ((:texture (hotdot level-default-sprite)) + (:num 16.0) + (:x (meters 0) (meters 2)) + (:scale-x (meters 0.1) (meters 0.1)) + (:scale-y :copy scale-x) + (:r 255.0) + (:g 255.0) + (:b 255.0) + (:a 255.0) + (:scalevel-x (meters -0.0025)) + (:scalevel-y :copy scalevel-x) + (:timer (seconds 0.267)) + (:flags (sp-cpuinfo-flag-0 sp-cpuinfo-flag-3)) + (:rotate-y (degrees 0) (degrees 3600)) + ) + ) + +(defpartgroup group-airtrain-dust-plume :id 203 :bounds (static-bspherem 0 0 0 15) :parts ((sp-item 828))) + +(defpart 828 + :init-specs ((:texture (bigpuff level-default-sprite)) + (:num 1.0 1.0) + (:x (meters 0) (meters 10)) + (:scale-x (meters 1) (meters 1)) + (:rot-z (degrees 0) (degrees 3600)) + (:scale-y (meters 1) (meters 1)) + (:r 128.0) + (:g 106.0 16.0) + (:b 64.0 32.0) + (:a 16.0 32.0) + (:vel-x (meters 0.033333335) (meters 0.033333335)) + (:scalevel-x (meters 0.033333335) (meters 0.006666667)) + (:rotvel-z (degrees -0.3) (degrees 0.6)) + (:scalevel-y :copy scalevel-x) + (:fade-a -0.04 -0.08) + (:accel-y (meters 0.00033333333)) + (:friction 0.95 0.03) + (:timer (seconds 4.335)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-13)) + (:rotate-y (degrees 0) (degrees 3600)) + ) + ) + +(defpartgroup group-airtrain-dust-hover :id 204 :bounds (static-bspherem 0 0 0 15) :parts ((sp-item 829))) + +(defpart 829 + :init-specs ((:texture (bigpuff level-default-sprite)) + (:num 1.0) + (:x (meters 0) (meters 5)) + (:scale-x (meters 1) (meters 1)) + (:rot-z (degrees 0) (degrees 3600)) + (:scale-y (meters 1) (meters 1)) + (:r 128.0) + (:g 106.0 16.0) + (:b 64.0 32.0) + (:a 16.0 16.0) + (:vel-x (meters 0.033333335) (meters 0.033333335)) + (:scalevel-x (meters 0.016666668) (meters 0.006666667)) + (:rotvel-z (degrees -0.3) (degrees 0.6)) + (:scalevel-y :copy scalevel-x) + (:fade-a -0.04 -0.08) + (:accel-y (meters 0.00033333333)) + (:friction 0.95 0.03) + (:timer (seconds 4.335)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-13)) + (:rotate-y (degrees 0) (degrees 3600)) + ) + ) + +(defpartgroup group-airtrain-thruster + :id 205 + :linger-duration (seconds 2) + :flags (sp4 sp6) + :bounds (static-bspherem 0 0 0 12) + :rotate ((degrees 180) (degrees 0) (degrees 0)) + :parts ((sp-item 830 :flags (sp6 sp7)) + (sp-item 831 :flags (sp6 sp7)) + (sp-item 832 :flags (sp7)) + (sp-item 833 :flags (sp7)) + (sp-item 834 :flags (sp7)) + ) + ) + +(defpartgroup group-airtrain-thruster-off + :id 206 + :linger-duration (seconds 2) + :flags (sp4 sp6) + :bounds (static-bspherem 0 0 0 12) + :rotate ((degrees 180) (degrees 0) (degrees 0)) + :parts ((sp-item 834 :fade-after (meters 120) :falloff-to (meters 90) :flags (sp7)) + (sp-item 835 :fade-after (meters 120) :falloff-to (meters 90) :flags (sp7)) + (sp-item 836 :flags (sp6 sp7)) + ) + ) + +(defpart 830 + :init-specs ((:texture (glow level-default-sprite)) + (:num 1.0) + (:y (meters 0.1)) + (:scale-x (meters 1) (meters 0.4)) + (:rot-x (degrees 2.25)) + (:scale-y :copy scale-x) + (:r 255.0) + (:g 64.0 128.0) + (:b 0.0) + (:a 64.0 8.0) + (:timer (seconds 0.017)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-3 glow)) + (:userdata 409.6) + (:rotate-y (degrees 0)) + ) + ) + +(defpart 831 + :init-specs ((:texture (glow-soft level-default-sprite)) + (:num 1.0) + (:y (meters 0.1)) + (:scale-x (meters 4.8) (meters 0.6)) + (:rot-x (degrees 2.25)) + (:scale-y :copy scale-x) + (:r 255.0) + (:g 64.0 128.0) + (:b 0.0) + (:a 16.0 2.0) + (:timer (seconds 0.017)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-3 glow)) + (:userdata 409.6) + (:rotate-y (degrees 0)) + ) + ) + +(defpart 832 + :init-specs ((:texture (bigpuff level-default-sprite)) + (:num 1.0 2.0) + (:scale-x (meters 1) (meters 1)) + (:rot-z (degrees 0) (degrees 3600)) + (:scale-y (meters 1) (meters 1)) + (:r 196.0) + (:g 128.0 64.0) + (:b :copy g) + (:a 16.0 16.0) + (:vel-x (meters -0.006666667) (meters 0.013333334)) + (:vel-y (meters -0.05) (meters -0.1)) + (:vel-z (meters -0.006666667) (meters 0.013333334)) + (:scalevel-x (meters 0.053333335) (meters 0.053333335)) + (:rotvel-z (degrees -1.2) (degrees 2.4)) + (:scalevel-y :copy scalevel-x) + (:fade-r 0.0) + (:fade-g 0.0) + (:fade-b 0.0) + (:fade-a -0.21333334 -0.42666668) + (:accel-y (meters 0.00016666666) (meters 0.0005)) + (:friction 0.94 0.04) + (:timer (seconds 2)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-13 sp-cpuinfo-flag-14)) + (:rotate-y (degrees 0)) + ) + ) + +(defpart 835 + :init-specs ((:texture (bigpuff level-default-sprite)) + (:num 1.0 2.0) + (:scale-x (meters 1) (meters 1)) + (:rot-z (degrees 0) (degrees 3600)) + (:scale-y (meters 1) (meters 1)) + (:r 196.0) + (:g 128.0 64.0) + (:b :copy g) + (:a 10.0 4.0) + (:vel-x (meters -0.006666667) (meters 0.013333334)) + (:vel-y (meters -0.05) (meters -0.1)) + (:vel-z (meters -0.006666667) (meters 0.013333334)) + (:scalevel-x (meters 0.053333335) (meters 0.053333335)) + (:rotvel-z (degrees -1.2) (degrees 2.4)) + (:scalevel-y :copy scalevel-x) + (:fade-r 0.0) + (:fade-g 0.0) + (:fade-b 0.0) + (:fade-a -0.21333334 -0.42666668) + (:accel-y (meters 0.00016666666) (meters 0.0005)) + (:friction 0.94 0.04) + (:timer (seconds 2)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-13 sp-cpuinfo-flag-14)) + (:rotate-y (degrees 0)) + ) + ) + +(defpart 836 + :init-specs ((:texture (glow level-default-sprite)) + (:num 1.0) + (:y (meters 0.1)) + (:scale-x (meters 1.4) (meters 0.1)) + (:rot-x (degrees 2.25)) + (:scale-y :copy scale-x) + (:r 128.0) + (:g 48.0 32.0) + (:b 0.0) + (:a 48.0 8.0) + (:timer (seconds 0.017)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-3 glow)) + (:userdata 409.6) + (:rotate-y (degrees 0)) + ) + ) + +(defpart 833 + :init-specs ((:texture (hotdot level-default-sprite)) + (:num 0.0 1.0) + (:x (meters 0) (meters 0.5)) + (:scale-x (meters 0.2) (meters 0.1)) + (:scale-y :copy scale-x) + (:r 192.0 64.0) + (:g 128.0) + (:b 0.0) + (:a 128.0) + (:omega (degrees 0.0675) (degrees 0.0225)) + (:vel-x (meters -0.013333334) (meters 0.026666667)) + (:vel-y (meters -0.1) (meters -0.06666667)) + (:vel-z (meters -0.013333334) (meters 0.026666667)) + (:fade-g -1.0) + (:fade-a -2.56) + (:accel-x (meters 0) (meters 0.0016666667)) + (:friction 0.96 0.02) + (:timer (seconds 0.085) (seconds 0.08)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-3 sp-cpuinfo-flag-13 sp-cpuinfo-flag-14)) + (:func 'sparticle-motion-blur) + (:rotate-y (degrees 0) (degrees 3600)) + ) + ) + +(defpart 834 + :init-specs ((:num 0.4) + (:rot-x 8) + (:r 1638.4) + (:g 1331.2) + (:b 1433.6) + (:vel-y (meters -0.05) (meters -0.016666668)) + (:fade-r 32.768) + (:fade-g 28.671999) + (:fade-b 26.623999) + (:accel-x (meters 0) (meters 0.0016666667)) + (:friction 0.94) + (:timer (seconds 0.335)) + (:flags (distort)) + (:next-time (seconds 0.167)) + (:next-launcher 837) + (:rotate-y (degrees 0) (degrees 360)) + ) + ) + +(defpart 837 + :init-specs ((:fade-r 0.0) (:fade-g 0.0) (:fade-b -4.096)) + ) + +(defpartgroup group-warp-hellcat-thruster + :id 207 + :duration (seconds 3) + :flags (sp0 sp4) + :bounds (static-bspherem 0 0 0 32) + :parts ((sp-item 838 :flags (is-3d sp7)) + (sp-item 839 :flags (is-3d sp7)) + (sp-item 840 :flags (sp7)) + (sp-item 841 :flags (is-3d sp7)) + (sp-item 842 :flags (is-3d sp7)) + (sp-item 843 :flags (sp7)) + ) + ) + +(defpart 838 + :init-specs ((:texture (mech-flame lprecurc-sprite)) + (:num 1.0) + (:x (meters 1.45)) + (:y (meters 1.1)) + (:z (meters -5.15)) + (:scale-x (meters 0.6)) + (:rot-x 4) + (:scale-y (meters 2)) + (:r 128.0 128.0) + (:g 32.0 96.0) + (:b :copy g) + (:a 128.0 64.0) + (:timer (seconds 0.017)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-3)) + (:rotate-y (degrees 0)) + ) + ) + +(defpart 839 + :init-specs ((:texture (gun-yellow-muzzleflash level-default-sprite)) + (:num 1.0) + (:x (meters 1.45)) + (:y (meters 1.1)) + (:z (meters -5.15)) + (:scale-x (meters 0.6)) + (:rot-x 4) + (:rot-z (degrees 90)) + (:scale-y (meters 2)) + (:r 128.0 128.0) + (:g 32.0 96.0) + (:b :copy g) + (:a 128.0 64.0) + (:timer (seconds 0.017)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-3)) + (:rotate-y (degrees 0)) + ) + ) + +(defpart 840 + :init-specs ((:texture (glow-soft level-default-sprite)) + (:num 1.0) + (:x (meters 1.45)) + (:y (meters 1.1)) + (:z (meters -4.75)) + (:scale-x (meters 1.75)) + (:rot-x (degrees 0.5625)) + (:scale-y :copy scale-x) + (:r 255.0) + (:g 0.0 64.0) + (:b 0.0) + (:a 16.0 4.0) + (:rotvel-z (degrees 0.3)) + (:timer (seconds 0.017)) + (:flags (glow)) + (:userdata 2048.0) + (:rotate-y (degrees 0)) + ) + ) + +(defpart 841 + :init-specs ((:texture (gun-yellow-muzzleflash level-default-sprite)) + (:num 1.0) + (:x (meters -1.45)) + (:y (meters 1.1)) + (:z (meters -5.15)) + (:scale-x (meters 0.6)) + (:rot-x 4) + (:scale-y (meters 2)) + (:r 128.0 128.0) + (:g 32.0 96.0) + (:b :copy g) + (:a 128.0 64.0) + (:timer (seconds 0.017)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-3)) + (:rotate-y (degrees 0)) + ) + ) + +(defpart 842 + :init-specs ((:texture (gun-yellow-muzzleflash level-default-sprite)) + (:num 1.0) + (:x (meters -1.45)) + (:y (meters 1.1)) + (:z (meters -5.15)) + (:scale-x (meters 0.6)) + (:rot-x 4) + (:rot-z (degrees 90)) + (:scale-y (meters 2)) + (:r 128.0 128.0) + (:g 32.0 96.0) + (:b :copy g) + (:a 128.0 64.0) + (:timer (seconds 0.017)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-3)) + (:rotate-y (degrees 0)) + ) + ) + +(defpart 843 + :init-specs ((:texture (glow-soft level-default-sprite)) + (:num 1.0) + (:x (meters -1.45)) + (:y (meters 1.1)) + (:z (meters -4.75)) + (:scale-x (meters 1.75)) + (:rot-x (degrees 0.5625)) + (:scale-y :copy scale-x) + (:r 255.0) + (:g 0.0 64.0) + (:b 0.0) + (:a 16.0 4.0) + (:rotvel-z (degrees 0.3)) + (:timer (seconds 0.017)) + (:flags (glow)) + (:userdata 2048.0) + (:rotate-y (degrees 0)) + ) + ) + +(defskelgroup skel-warp-gate warp-gate warp-gate-lod0-jg warp-gate-idle-ja + ((warp-gate-lod0-mg (meters 999999))) + :bounds (static-spherem 0 3 0 4) + :origin-joint-index 3 + ) + +(deftype warp-gate (process-drawable) + ((root collide-shape :override) + (level-name symbol) + (on-notice pair) + (on-activate pair) + (on-close pair) + (wait-for pair) + (continue continue-point) + (distance meters) + (anim-speed float) + (test-time time-frame) + (center vector :inline) + (selected int32) ;; added + (wmenu-list (array warp-gate-menu-entry)) ;; added + (page int32) ;; added + ) + (:state-methods + idle + hidden + ) + (:methods + (init-skel-and-collide! (_type_) none) + (init-defaults! (_type_) none) + (warp-select-menu (_type_) none) ;; handles the menu logic for selecting warp destinations + (set-warp! (_type_ int) none) ;; sets the warp destination based on the selected menu index + (warp-to-continue (_type_) none) ;; executes the warp transition to the chosen destination + (available-to-use? (_type_) symbol) ;; checks if there's at least one valid destination available for use + ) + (:states ;; added + warp-gate-menu + execute-warp + ) + ) + +(defstate hidden (warp-gate) + :virtual #t + :code sleep-code + ) + +;; WARN: Return type mismatch draw-control vs none. +(defmethod init-skel-and-collide! ((this warp-gate)) + (let ((s5-0 (new 'process 'collide-shape this (collide-list-enum usually-hit-by-player)))) + (set! (-> s5-0 penetrated-by) (penetrate)) + (let ((v1-2 (new 'process 'collide-shape-prim-mesh s5-0 (the-as uint 0) (the-as uint 0)))) + (set! (-> v1-2 prim-core collide-as) (collide-spec obstacle)) + (set! (-> v1-2 prim-core action) (collide-action solid)) + (set! (-> v1-2 transform-index) 3) + (set-vector! (-> v1-2 local-sphere) 0.0 12288.0 0.0 16384.0) + (set! (-> s5-0 total-prims) (the-as uint 1)) + (set! (-> s5-0 root-prim) v1-2) + ) + (set! (-> s5-0 nav-radius) (* 0.75 (-> s5-0 root-prim local-sphere w))) + (let ((v1-5 (-> s5-0 root-prim))) + (set! (-> s5-0 backup-collide-as) (-> v1-5 prim-core collide-as)) + (set! (-> s5-0 backup-collide-with) (-> v1-5 prim-core collide-with)) + ) + (set! (-> this root) s5-0) + ) + (initialize-skeleton + this + (the-as skeleton-group (art-group-get-by-name *level* "skel-warp-gate" (the-as (pointer level) #f))) + (the-as pair 0) + ) + (none) + ) + +;; WARN: Return type mismatch float vs none. +(defmethod init-defaults! ((this warp-gate)) + (set! (-> this level-name) (-> this level name)) + (set! (-> this on-notice) (res-lump-struct (-> this entity) 'on-notice pair)) + (set! (-> this on-activate) #f) + (set! (-> this wait-for) #f) + (set! (-> this continue) #f) + (set! (-> this on-close) #f) + (set! (-> this part) (create-launch-control group-warpgate this)) + (vector-copy! (-> this center) (-> this root trans)) + (+! (-> this center y) 13516.8) + (set! (-> this sound) + (new 'process 'ambient-sound (static-sound-spec "warpgate" :group 0 :fo-max 30) (-> this root trans) 0.0) + ) + (set! (-> this distance) (res-lump-float (-> this entity) 'distance :default 20480.0)) + (set! (-> this wmenu-list) ;; added - sets the current warp-gate menu list. Add more cases as needed. + (case-str (-> this name) + (("warp-gate-21") ;; vinroom warp-gate + *warp-gate-21-menu-list* + ) + (("warp-gate-31") ;; templex warp-gate + *warp-gate-31-menu-list* + ) + (("warp-gate-33") ;; templeb warp-gate + *warp-gate-33-menu-list* + ) + (("warp-gate-34") ;; templed warp-gate + *warp-gate-34-menu-list* + ) + (("warp-gate-30") ;; volcanox warp-gate + *warp-gate-30-menu-list* + ) + (else + *empty-warp-gate-menu-list* ;; Just an empty array. Leave it at is. Used as a fallback when an entity doesn't have a defined menu. + ) + ) + ) + (none) + ) + +;; WARN: Return type mismatch object vs none. +(defbehavior warp-gate-init warp-gate ((arg0 entity-actor) (arg1 vector)) + (stack-size-set! (-> self main-thread) 512) + (init-skel-and-collide! self) + (if arg0 + (process-drawable-from-entity! self arg0) + ) + (if arg1 + (vector-copy! (-> self root trans) arg1) + ) + (logior! (-> self mask) (process-mask actor-pause)) + (init-defaults! self) + (go-virtual idle) + (none) + ) + +;; WARN: Return type mismatch none vs object. +(defmethod init-from-entity! ((this warp-gate) (arg0 entity-actor)) + "Set up a newly created process from the entity that created it." + (warp-gate-init arg0 (the-as vector #f)) + ) + +(define *warp-jump-mods* (new 'static 'surface + :name 'jump + :turnv 273066.66 + :turnvf 30.0 + :turnvv 1820444.5 + :turnvvf 30.0 + :tiltv 65536.0 + :tiltvf 150.0 + :tiltvv 262144.0 + :tiltvvf 15.0 + :transv-max 65536.0 + :target-speed 65536.0 + :slip-factor 1.0 + :slide-factor 1.0 + :slope-up-factor 1.0 + :slope-down-factor 1.0 + :slope-slip-angle 1.0 + :impact-fric 1.0 + :bend-factor 1.0 + :bend-speed 1.0 + :alignv 1.0 + :slope-up-traction 1.0 + :align-speed 1.0 + :mode 'air + :flags (surface-flag turn-to-vel turn-when-centered gun-off) + ) + ) + +(defstate target-warp-out (target) + :event (behavior ((proc process) (argc int) (message symbol) (block event-message-block)) + (case message + (('death-end) + (let ((v0-0 (the-as object (logior (-> self draw status) (draw-control-status no-draw))))) + (set! (-> self draw status) (the-as draw-control-status v0-0)) + v0-0 + ) + ) + (('warp-gate) + (if (not (-> self control unknown-spool-anim00)) + 'busy + ) + ) + (else + (target-generic-event-handler proc argc message block) + ) + ) + ) + :enter (behavior ((arg0 vector) (arg1 vector) (arg2 handle)) + (set-time! (-> self state-time)) + (logclear! (-> self control status) (collide-status on-surface on-ground touch-surface)) + (set! (-> self control mod-surface) *warp-jump-mods*) + (vector-copy! (-> self control unknown-vector37) arg0) + (vector-copy! (-> self control unknown-vector38) arg1) + (+! (-> self control unknown-vector37 y) -4096.0) + (set! (-> self control unknown-word04) (the-as uint #f)) + (set! (-> self control unknown-handle02) arg2) + (vector-reset! (-> self control transv)) + (logior! (-> self target-flags) (target-flags tf6)) + (vector-copy! (-> self alt-cam-pos) arg1) + (forward-up-nopitch->quaternion + (-> self control dir-targ) + (vector-! (new 'stack-no-clear 'vector) arg1 (-> self control trans)) + (vector-y-quaternion! (new 'stack-no-clear 'vector) (-> self control dir-targ)) + ) + ) + :exit (behavior () + (logclear! (-> self target-flags) (target-flags tf6)) + ) + :code (behavior ((arg0 vector) (arg1 vector) (arg2 handle)) + (ja-channel-push! 1 (seconds 0.2)) + (ja-no-eval :group! jakb-duck-high-jump-ja :num! (seek! (ja-aframe 16.0 0)) :frame-num 0.0) + (until (ja-done? 0) + (suspend) + (ja :num! (seek! (ja-aframe 16.0 0))) + ) + (vector-! (-> self control transv) (-> self control unknown-vector37) (-> self control trans)) + (vector-xz-normalize! (-> self control transv) 32768.0) + (let ((v1-18 (new-stack-vector0))) + (let ((f0-6 (vector-dot (-> self control dynam gravity-normal) (-> self control transv)))) + 0.0 + (vector-! v1-18 (-> self control transv) (vector-float*! v1-18 (-> self control dynam gravity-normal) f0-6)) + ) + (let* ((f0-7 (vector-length v1-18)) + (f1-1 f0-7) + (f2-4 + (- (sqrtf + (* 2.0 + (-> self control dynam gravity-length) + (vector-dot + (-> self control dynam gravity-normal) + (vector-! (new 'stack-no-clear 'vector) (-> self control unknown-vector37) (-> self control trans)) + ) + ) + ) + (* 0.008333334 (- (-> self control dynam gravity-length))) + ) + ) + ) + (vector+! + (-> self control transv) + (vector-float*! (-> self control transv) (-> self control dynam gravity-normal) f2-4) + (vector-float*! v1-18 v1-18 (/ f0-7 f1-1)) + ) + ) + ) + (let ((v1-20 (-> self control root-prim))) + (set! (-> v1-20 prim-core collide-as) (collide-spec)) + (set! (-> v1-20 prim-core collide-with) (collide-spec)) + ) + 0 + (set-time! (-> self state-time)) + (set! (-> self trans-hook) + (lambda :behavior target + () + (let ((v1-0 (new-stack-vector0)) + (f0-1 (vector-dot (-> self control dynam gravity-normal) (-> self control transv))) + ) + 0.0 + (vector-! v1-0 (-> self control transv) (vector-float*! v1-0 (-> self control dynam gravity-normal) f0-1)) + (let* ((f1-2 (vector-length v1-0)) + (f2-0 f1-2) + ) + (if (< f0-1 0.0) + (set! f0-1 8192.0) + ) + (vector+! + (-> self control transv) + (vector-float*! (-> self control transv) (-> self control dynam gravity-normal) f0-1) + (vector-float*! v1-0 v1-0 (/ f1-2 f2-0)) + ) + ) + ) + (let ((gp-1 (vector-! (new-stack-vector0) (-> self control unknown-vector37) (-> self control trans)))) + (set! (-> gp-1 y) 0.0) + (send-event *target* 'sidekick #f) + (when (and (or (< (vector-dot gp-1 (-> self control transv)) 0.0) (-> self control unknown-spool-anim00)) + (time-elapsed? (-> self state-time) (seconds 0.05)) + ) + (vector-seek! (-> self draw color-mult) (new 'static 'vector) (* 2.0 (seconds-per-frame))) + (set! (-> self control transv x) (* 0.95 (-> self control transv x))) + (set! (-> self control transv z) (* 0.95 (-> self control transv z))) + (when (not (-> self control unknown-spool-anim00)) + (sound-play "warpgate-tele") + (send-event (handle->process (-> self control unknown-handle02)) 'effect) + (send-event self 'draw #f) + (let ((v0-1 #t)) + (set! (-> self control unknown-word04) (the-as uint v0-1)) + v0-1 + ) + ) + ) + ) + ) + ) + (ja-no-eval :group! jakb-duck-high-jump-ja :num! (seek! (ja-aframe 40.0 0)) :frame-num (ja-aframe 16.0 0)) + (until (ja-done? 0) + (suspend) + (ja :num! (seek! (ja-aframe 40.0 0))) + ) + (sleep-code) + ) + :post target-no-stick-post + ) + +(defstate target-warp-in (target) + :event target-generic-event-handler + :enter (behavior ((arg0 vector) (arg1 vector) (arg2 object)) + (set! (-> self control did-move-to-pole-or-max-jump-height) (the-as float arg2)) + ((-> target-warp-out enter) arg0 arg1 (the-as handle arg2)) + ) + :exit (-> target-warp-out exit) + :trans (behavior () + (set! (-> self control transv x) + (* 2.4 (- (-> self control unknown-vector38 x) (-> self control unknown-vector37 x))) + ) + (set! (-> self control transv z) + (* 2.4 (- (-> self control unknown-vector38 z) (-> self control unknown-vector37 z))) + ) + (if (logtest? (-> self control status) (collide-status on-surface)) + (go target-hit-ground #f) + ) + ) + :code (behavior ((arg0 vector) (arg1 vector) (arg2 object)) + (let ((a0-1 (-> self control did-move-to-pole-or-max-jump-height))) + (when a0-1 + (let ((s5-0 (res-lump-struct (the-as res-lump a0-1) 'camera-name string))) + (when s5-0 + (logclear! (-> self target-flags) (target-flags tf6)) + (process-spawn-function + process + (lambda :behavior process + ((arg0 string)) + (local-vars (a1-2 event-message-block)) + (add-setting! 'entity-name arg0 0.0 0) + (until (send-event-function *camera* a1-2) + (suspend) + (set! a1-2 (new 'stack-no-clear 'event-message-block)) + (let ((v1-2 (process->ppointer self))) + (set! (-> a1-2 from) v1-2) + ) + (set! (-> a1-2 num-params) 0) + (set! (-> a1-2 message) 'intro-done?) + ) + #f + ) + s5-0 + :to self + ) + ) + ) + ) + ) + (let ((v1-12 (-> self control root-prim))) + (set! (-> self control backup-collide-as) (-> v1-12 prim-core collide-as)) + (set! (-> self control backup-collide-with) (-> v1-12 prim-core collide-with)) + ) + (let ((v1-15 (-> self control root-prim))) + (set! (-> v1-15 prim-core collide-as) (collide-spec)) + (set! (-> v1-15 prim-core collide-with) (collide-spec)) + ) + 0 + (ja-channel-set! 0) + (vector-reset! (-> self control transv)) + (move-to-point! (-> self control) (-> self control unknown-vector37)) + (let ((s5-1 (current-time))) + (while (or (not (time-elapsed? s5-1 (seconds 1))) + (< 81920.0 (vector-vector-distance (camera-pos) (-> self control trans))) + ) + (suspend) + ) + ) + (set-heading-vec! (-> self control) (-> self control transv)) + (rot->dir-targ! (-> self control)) + (set-time! (-> self state-time)) + (set! (-> self post-hook) target-no-stick-post) + (ja-channel-set! 1) + (send-event + (if arg2 + (-> (the-as process arg2) child 3) + ) + 'effect + ) + (send-event self 'draw #t) + (sound-play "warpgate-tele") + (ja-no-eval :group! jakb-duck-high-jump-ja :num! (seek! (ja-aframe 42.0 0)) :frame-num (ja-aframe 40.0 0)) + (until (ja-done? 0) + (let ((v1-58 (new-stack-vector0))) + (let ((f0-5 (vector-dot (-> self control dynam gravity-normal) (-> self control transv)))) + 0.0 + (vector-! v1-58 (-> self control transv) (vector-float*! v1-58 (-> self control dynam gravity-normal) f0-5)) + ) + (let* ((f0-6 (vector-length v1-58)) + (f1-1 f0-6) + (f2-3 + (- (sqrtf (* 4096.0 (-> self control dynam gravity-length))) + (* 0.008333334 (- (-> self control dynam gravity-length))) + ) + ) + ) + (vector+! + (-> self control transv) + (vector-float*! (-> self control transv) (-> self control dynam gravity-normal) f2-3) + (vector-float*! v1-58 v1-58 (/ f0-6 f1-1)) + ) + ) + ) + (suspend) + (ja :num! (seek! (ja-aframe 42.0 0))) + ) + (ja-no-eval :group! jakb-duck-high-jump-ja :num! (seek! (ja-aframe 50.0 0)) :frame-num (ja-aframe 42.0 0)) + (until (ja-done? 0) + (suspend) + (ja :num! (seek! (ja-aframe 50.0 0))) + ) + (let ((v1-79 (-> self control root-prim))) + (set! (-> v1-79 prim-core collide-as) (-> self control backup-collide-as)) + (set! (-> v1-79 prim-core collide-with) (-> self control backup-collide-with)) + ) + (ja-no-eval :group! jakb-duck-high-jump-ja :num! (seek!) :frame-num (ja-aframe 50.0 0)) + (until (ja-done? 0) + (suspend) + (ja :num! (seek!)) + ) + (target-falling-anim -1 (seconds 0.33)) + ) + :post target-no-move-post + ) + +(defskelgroup skel-air-train air-train air-train-lod0-jg air-train-idle-ja + ((air-train-lod0-mg (meters 999999))) + :bounds (static-spherem 0 2 -2 12.5) + :origin-joint-index 3 + ) + +(deftype air-train (warp-gate) + ((part-exhaust-left sparticle-launch-control) + (part-exhaust-right sparticle-launch-control) + (part-dust sparticle-launch-control) + (dust-y float) + (hover-sound sound-id) + (base-pos vector :inline) + (menu-data air-train-menu-data) ;; added + ) + (:methods ;; added + (warp-select-menu (_type_) none) ;; handles the menu logic for selecting warp destinations + (set-warp! (_type_ int) none) ;; sets the warp destination based on the selected menu index + (warp-to-continue (_type_) none) ;; executes the warp transition to the chosen destination + (available-to-use? (_type_) symbol) ;; checks if there's at least one valid destination available for use + (hide-air-train? (_type_) symbol) ;; checks whether the air-train should be hidden or not + ) + (:states ;; added + air-train-menu + air-train-warp + ) + ) + + +;; WARN: Return type mismatch warp-gate vs air-train. +(defmethod relocate ((this air-train) (offset int)) + (if (nonzero? (-> this part-exhaust-left)) + (&+! (-> this part-exhaust-left) offset) + ) + (if (nonzero? (-> this part-exhaust-right)) + (&+! (-> this part-exhaust-right) offset) + ) + (if (nonzero? (-> this part-dust)) + (&+! (-> this part-dust) offset) + ) + (the-as air-train ((method-of-type warp-gate relocate) this offset)) + ) + +(defmethod deactivate ((this air-train)) + "Make a process dead, clean it up, remove it from the active pool, and return to dead pool." + (sound-stop (-> this hover-sound)) + (if (nonzero? (-> this part-exhaust-left)) + (kill-particles (-> this part-exhaust-left)) + ) + (if (nonzero? (-> this part-exhaust-right)) + (kill-particles (-> this part-exhaust-right)) + ) + (if (nonzero? (-> this part-dust)) + (kill-particles (-> this part-dust)) + ) + ((method-of-type warp-gate deactivate) this) + (none) + ) + +;; WARN: Return type mismatch draw-control vs none. +(defmethod init-skel-and-collide! ((this air-train)) + (let ((s5-0 (new 'process 'collide-shape-moving this (collide-list-enum usually-hit-by-player)))) + (set! (-> s5-0 dynam) (copy *standard-dynamics* 'process)) + (set! (-> s5-0 reaction) cshape-reaction-default) + (set! (-> s5-0 no-reaction) + (the-as (function collide-shape-moving collide-query vector vector object) nothing) + ) + (set! (-> s5-0 penetrated-by) (penetrate)) + (let ((s4-0 (new 'process 'collide-shape-prim-group s5-0 (the-as uint 2) 0))) + (set! (-> s5-0 total-prims) (the-as uint 3)) + (set! (-> s4-0 prim-core collide-as) (collide-spec obstacle)) + (set! (-> s4-0 prim-core collide-with) (collide-spec jak player-list)) + (set! (-> s4-0 prim-core action) (collide-action solid)) + (set! (-> s4-0 transform-index) 3) + (set-vector! (-> s4-0 local-sphere) 0.0 0.0 0.0 69632.0) + (set! (-> s5-0 root-prim) s4-0) + ) + (let ((v1-13 (new 'process 'collide-shape-prim-mesh s5-0 (the-as uint 0) (the-as uint 0)))) + (set! (-> v1-13 prim-core collide-as) (collide-spec obstacle)) + (set! (-> v1-13 prim-core collide-with) (collide-spec jak player-list)) + (set! (-> v1-13 prim-core action) (collide-action solid)) + (set! (-> v1-13 transform-index) 6) + (set-vector! (-> v1-13 local-sphere) 0.0 10240.0 0.0 24576.0) + ) + (let ((v1-15 (new 'process 'collide-shape-prim-mesh s5-0 (the-as uint 1) (the-as uint 0)))) + (set! (-> v1-15 prim-core collide-as) (collide-spec obstacle)) + (set! (-> v1-15 prim-core collide-with) (collide-spec jak player-list)) + (set! (-> v1-15 prim-core action) (collide-action solid)) + (set! (-> v1-15 transform-index) 3) + (set-vector! (-> v1-15 local-sphere) 0.0 0.0 0.0 53248.0) + ) + (set! (-> s5-0 nav-radius) (* 0.75 (-> s5-0 root-prim local-sphere w))) + (let ((v1-18 (-> s5-0 root-prim))) + (set! (-> s5-0 backup-collide-as) (-> v1-18 prim-core collide-as)) + (set! (-> s5-0 backup-collide-with) (-> v1-18 prim-core collide-with)) + ) + (set! (-> this root) s5-0) + ) + (initialize-skeleton + this + (the-as skeleton-group (art-group-get-by-name *level* "skel-air-train" (the-as (pointer level) #f))) + (the-as pair 0) + ) + (none) + ) + +;; WARN: Return type mismatch sound-id vs none. +(defmethod init-defaults! ((this air-train)) + (let ((t9-0 (method-of-type warp-gate init-defaults!))) + (t9-0 this) + ) + (vector-copy! (-> this base-pos) (-> this root trans)) + (let ((v1-2 (-> this level-name))) + (set! (-> this dust-y) (cond + ((= v1-2 'nest) + -1105.92 + ) + ((= v1-2 'caspad) + 114647.04 + ) + (else + (the-as float #x7f800000) + ) + ) + ) + ) + (set! (-> this part-exhaust-left) (create-launch-control group-airtrain-thruster-off this)) + (set! (-> this part-exhaust-right) (create-launch-control group-airtrain-thruster-off this)) + (set! (-> this part-dust) (create-launch-control group-airtrain-dust-hover this)) + (set! (-> this root pause-adjust-distance) 368640.0) + (set! (-> this hover-sound) (sound-play "air-train")) + (set! (-> this menu-data) ;; added - Sets the current air-train menu data. Add more cases as needed. + (case-str (-> this name) + (("air-train-1") ;; ctyport air-train + *air-train-1-menu-data* + ) + (("air-train-5") ;; desert air-train + *air-train-5-menu-data* + ) + (else + *empty-air-train-menu-data* ;; Just an empty array. Leave it at is. Used as a fallback when an entity doesn't have a defined menu. + ) + ) + ) + (none) + ) + +(load-scene (new 'static 'scene + :name "desert-air-train-in" + :extra #f + :info #f + :scene-flags (scene-flags scf1 scf2 scf3 scf4) + :mask-to-clear (process-mask movie enemy platform projectile) + :entity "air-train-5" + :art-group "scenecamera" + :anim "desert-air-train-in" + :parts 4 + :command-list '((0 + (kill "air-train-5") + (fadein (frame-time-30 10)) + (apply ,(lambda () (kill-by-type v-marauder *active-pool*))) + ) + (260 + (part-tracker + "group-warp-fma-drop-thrusters" + entity + "air-train" + joint + "thruster_l" + track + #t + duration + (frame-range 260 475) + ) + (part-tracker + "group-warp-fma-drop-thrusters" + entity + "air-train" + joint + "thruster_r" + track + #t + duration + (frame-range 260 475) + ) + ) + (270 (part-tracker + "group-warp-fma-dust-takeoff" + entity + "particleman" + joint + "particleA" + track + #t + duration + (frame-range 270 475) + ) + ) + (350 + (part-tracker + "group-warp-thruster-trail" + entity + "air-train" + joint + "thruster_l" + track + #t + duration + (frame-range 350 475) + subsample-num + (new 'static 'bfloat :data 5.0) + ) + (part-tracker + "group-warp-thruster-trail" + entity + "air-train" + joint + "thruster_r" + track + #t + duration + (frame-range 350 475) + subsample-num + (new 'static 'bfloat :data 5.0) + ) + ) + (475 (fadeout (frame-time-30 5))) + ) + :cut-list '(285) + :wait-ground-time (seconds 1) + :actor (new 'static 'boxed-array :type scene-actor + (new 'static 'scene-actor + :name "scenecamera" + :level #f + :art-group "skel-scenecamera" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '() + :camera 4 + :shadow-flags -1 + :shadow-volume-joint #f + ) + (new 'static 'scene-actor + :name "jakc-highres" + :level 'warpcast + :art-group "skel-jakc-highres" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min 290)) + :cloth-reset-frames '() + :cloth-commands '() + :flags #x1 + :shadow-flags -1 + :shadow-volume-joint #f + :no-draw-seg #x80 + ) + (new 'static 'scene-actor + :name "sidekick-highres" + :level 'warpcast + :art-group "skel-sidekick-highres" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min 290)) + :cloth-reset-frames '() + :cloth-commands '() + :flags #x1 + :shadow-flags -1 + :shadow-volume-joint #f + ) + (new 'static 'scene-actor + :name "particleman" + :level 'warpcast + :art-group "skel-particleman" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '() + :shadow-flags -1 + :shadow-volume-joint #f + ) + (new 'static 'scene-actor + :name "air-train" + :level 'desertb + :art-group "skel-air-train" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '() + :flags #x1 + :shadow-flags -1 + :shadow-volume-joint #f + ) + ) + :load-point "desert-warp" + :end-point "ctyport-warp" + :borrow '() + :sfx-volume 0.75 + :ambient-volume -1.0 + :music-volume -1.0 + :music-delay 1500.0 + :on-running #f + :on-complete #f + ) + ) + +(load-scene (new 'static 'scene + :name "desert-air-train-out" + :extra #f + :info #f + :scene-flags (scene-flags scf1 scf2 scf3 scf4) + :mask-to-clear (process-mask movie enemy platform projectile) + :entity "air-train-5" + :art-group "scenecamera" + :anim "desert-air-train-out" + :parts 3 + :command-list '((0 (kill "air-train-5") (fadein (frame-time-30 10))) + (1 + (part-tracker + "group-warp-fma-drop-thrusters" + entity + "air-train" + joint + "thruster_l" + track + #t + duration + (frame-range 1 200) + ) + (part-tracker + "group-warp-fma-drop-thrusters" + entity + "air-train" + joint + "thruster_r" + track + #t + duration + (frame-range 1 200) + ) + ) + (65 (part-tracker + "group-warp-fma-dust-takeoff" + entity + "particleman" + joint + "particleA" + track + #t + duration + (frame-range 65 172) + ) + ) + (290 (fadeout (frame-time-30 5))) + ) + :cut-list '(180) + :wait-ground-time (seconds 1) + :actor (new 'static 'boxed-array :type scene-actor + (new 'static 'scene-actor + :name "scenecamera" + :level #f + :art-group "skel-scenecamera" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '() + :camera 4 + :shadow-flags -1 + :shadow-volume-joint #f + ) + (new 'static 'scene-actor + :name "jakc-highres" + :level 'warpcast + :art-group "skel-jakc-highres" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((180 max)) + :cloth-reset-frames '() + :cloth-commands '() + :flags #x1 + :shadow-flags -1 + :shadow-volume-joint #f + :no-draw-seg #x80 + ) + (new 'static 'scene-actor + :name "sidekick-highres" + :level 'warpcast + :art-group "skel-sidekick-highres" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((180 max)) + :cloth-reset-frames '() + :cloth-commands '() + :flags #x1 + :shadow-flags -1 + :shadow-volume-joint #f + ) + (new 'static 'scene-actor + :name "particleman" + :level 'warpcast + :art-group "skel-particleman" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '() + :shadow-flags -1 + :shadow-volume-joint #f + ) + (new 'static 'scene-actor + :name "air-train" + :level 'desertb + :art-group "skel-air-train" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '() + :flags #x1 + :shadow-flags -1 + :shadow-volume-joint #f + ) + ) + :load-point "desert-warp" + :end-point "desert-warp" + :borrow '() + :sfx-volume 0.75 + :ambient-volume -1.0 + :music-volume -1.0 + :music-delay 1500.0 + :on-running #f + :on-complete #f + ) + ) + +(load-scene (new 'static 'scene + :name "city-air-train-out" + :extra #f + :info #f + :scene-flags (scene-flags scf1 scf2 scf3 scf4) + :mask-to-clear (process-mask movie enemy platform projectile) + :entity "scene-stage-87" + :art-group "scenecamera" + :anim "city-air-train-out" + :parts 2 + :command-list '((0 (kill "air-train-1") (fadein (frame-time-30 10))) (235 (fadeout (frame-time-30 5)))) + :cut-list '(98 188) + :wait-ground-time (seconds 1) + :actor (new 'static 'boxed-array :type scene-actor + (new 'static 'scene-actor + :name "scenecamera" + :level #f + :art-group "skel-scenecamera" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '() + :camera 4 + :shadow-flags -1 + :shadow-volume-joint #f + ) + (new 'static 'scene-actor + :name "jakc-highres" + :level 'citycast + :art-group "skel-jakc-highres" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '(((min max) set-flags local-space)) + :flags #x1 + :shadow-flags -1 + :shadow-volume-joint #f + :no-draw-seg #x80 + ) + (new 'static 'scene-actor + :name "sidekick-highres" + :level 'citycast + :art-group "skel-sidekick-highres" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '() + :flags #x1 + :shadow-flags -1 + :shadow-volume-joint #f + ) + (new 'static 'scene-actor + :name "air-train" + :level 'ctyport + :art-group "skel-air-train" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '() + :flags #x1 + :shadow-flags -1 + :shadow-volume-joint #f + ) + ) + :load-point "ctyport-air-train" + :end-point "ctyport-warp" + :borrow '() + :sfx-volume -1.0 + :ambient-volume -1.0 + :music-volume -1.0 + :music-delay 1500.0 + :on-running '(begin + (sound-play-loop "port-amb-mov") + (sound-play-loop "port-water-mov") + (sound-play-loop "port-gulls-mov") + ) + :on-complete #f + ) + ) + +(load-scene (new 'static 'scene + :name "city-air-train-in-desert" + :extra #f + :info #f + :scene-flags (scene-flags scf1 scf2 scf3 scf4) + :mask-to-clear (process-mask movie enemy platform projectile) + :entity "scene-stage-87" + :art-group "scenecamera" + :anim "city-air-train-in-desert" + :parts 3 + :command-list '((0 (kill "air-train-1") (fadein (frame-time-30 10))) (275 (fadeout (frame-time-30 5)))) + :cut-list '(51 102 226) + :wait-ground-time (seconds 1) + :actor (new 'static 'boxed-array :type scene-actor + (new 'static 'scene-actor + :name "scenecamera" + :level #f + :art-group "skel-scenecamera" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '() + :camera 4 + :shadow-flags -1 + :shadow-volume-joint #f + ) + (new 'static 'scene-actor + :name "jakc-highres" + :level 'citycast + :art-group "skel-jakc-highres" + :prefix "" + :draw-frames '((min 226)) + :scissor-frames '() + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '(((min max) set-flags local-space)) + :flags #x1 + :shadow-flags -1 + :shadow-volume-joint #f + :no-draw-seg #x80 + ) + (new 'static 'scene-actor + :name "sidekick-highres" + :level 'citycast + :art-group "skel-sidekick-highres" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '() + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '() + :flags #x1 + :shadow-flags -1 + :shadow-volume-joint #f + ) + (new 'static 'scene-actor + :name "air-train" + :level 'ctyport + :art-group "skel-air-train" + :prefix "" + :draw-frames '((min max)) + :scissor-frames '((min max)) + :shadow-frames '((min max)) + :cloth-reset-frames '() + :cloth-commands '() + :flags #x1 + :shadow-flags -1 + :shadow-volume-joint #f + ) + ) + :load-point "ctyport-warp" + :end-point "desert-warp" + :borrow '() + :sfx-volume -1.0 + :ambient-volume -1.0 + :music-volume -1.0 + :music-delay 1500.0 + :on-running '(begin + (sound-play-loop "port-amb-mov") + (sound-play-loop "port-water-mov") + (sound-play-loop "port-gulls-mov") + ) + :on-complete #f + ) + ) + +(defpartgroup group-warp-fma-dust-takeoff + :id 208 + :flags (sp0 sp4) + :bounds (static-bspherem 0 0 0 64) + :parts ((sp-item 844 :flags (sp7))) + ) + +(defpart 844 + :init-specs ((:texture (dirtpuff01 level-default-sprite)) + (:birth-func 'birth-func-curve) + (:num 5.0) + (:x (meters 0) (meters 3)) + (:scale-x (meters 0.5)) + (:rot-z (degrees 0) (degrees 360)) + (:scale-y :copy scale-x) + (:r 128.0) + (:g 100.0) + (:b 60.0) + (:a 0.0) + (:vel-x (meters 0.033333335) (meters 0.06666667)) + (:accel-y (meters 0) (meters 0.00016666666)) + (:timer (seconds 3)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-13 launch-along-z)) + (:userdata 0.0) + (:func 'live-func-curve) + (:conerot-z (degrees 0)) + (:rotate-y (degrees 0) (degrees 3600)) + ) + ) + +(if #t + (set! *range-warp-dust-color* (new 'static 'curve-color-fast + :xs (new 'static 'vector :y -1.0 :z -2.0 :w -3.0) + :ys (new 'static 'inline-array vector 4 + (new 'static 'vector :x 140.0 :y 120.0 :z 80.0 :w 128.0) + (new 'static 'vector :x 100.0 :y 80.0 :z 40.0 :w 128.0) + (new 'static 'vector :x 100.0 :y 80.0 :z 40.0 :w 128.0) + (new 'static 'vector :x 100.0 :y 80.0 :z 40.0 :w 128.0) + ) + :one-over-x-deltas (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0) + ) + ) + ) + +(if #t + (set! *range-warp-dust-alpha* (new 'static 'curve2d-fast + :xs (new 'static 'vector :y -1.0 :z -2.0 :w -3.0) + :ys (new 'static 'vector :x 32.0 :y 40.0 :z 41.0 :w 42.0) + :one-over-x-deltas (new 'static 'vector :x 8.0 :y 1.0 :z 1.0 :w 1.0) + ) + ) + ) + +(if #t + (set! *range-warp-dust-scale-x* (new 'static 'curve2d-fast + :xs (new 'static 'vector :y -1.0 :z -2.0 :w -3.0) + :ys (new 'static 'vector :x 3.0 :y 3.3 :z 4.3 :w 5.3) + :one-over-x-deltas (new 'static 'vector :x 0.29999995 :y 1.0000002 :z 1.0 :w 1.0) + ) + ) + ) + +(if #t + (set! *range-warp-dust-scale-y* (new 'static 'curve2d-fast + :xs (new 'static 'vector :y -1.0 :z -2.0 :w -3.0) + :ys (new 'static 'vector :x 3.0 :y 3.3 :z 4.3 :w 5.3) + :one-over-x-deltas (new 'static 'vector :x 0.29999995 :y 1.0000002 :z 1.0 :w 1.0) + ) + ) + ) + +(if #t + (set! *curve-warp-dust-alpha* (new 'static 'curve2d-fast + :xs (new 'static 'vector :y -0.1 :z -0.5 :w -1.0) + :ys (new 'static 'vector :y 1.0 :z 1.0) + :one-over-x-deltas (new 'static 'vector :x 10.0 :z -2.0 :w 1.0) + ) + ) + ) + +(if #t + (set! *curve-warp-dust-scale-x* (new 'static 'curve2d-fast + :xs (new 'static 'vector :y -0.3 :z -0.4 :w -1.0) + :ys (new 'static 'vector :y 5.0 :z 6.0 :w 6.5) + :one-over-x-deltas (new 'static 'vector :x 16.666666 :y 10.000001 :z 0.8333333 :w 1.0) + ) + ) + ) + +(if #t + (set! *curve-warp-dust-scale-y* (new 'static 'curve2d-fast + :xs (new 'static 'vector :y -0.3 :z -0.4 :w -1.0) + :ys (new 'static 'vector :y 5.0 :z 6.0 :w 6.5) + :one-over-x-deltas (new 'static 'vector :x 16.666666 :y 10.000001 :z 0.8333333 :w 1.0) + ) + ) + ) + +(define *part-warp-fma-dust-takeoff-curve-settings* (new 'static 'particle-curve-settings + :lifetime-base (seconds 5) + :lifetime-offset (seconds 2) + :flags (particle-curve-flags pcf0) + ) + ) + +(set! (-> *part-id-table* 844 init-specs 15 initial-valuef) + (the-as float *part-warp-fma-dust-takeoff-curve-settings*) + ) + +(set! (-> *part-warp-fma-dust-takeoff-curve-settings* color-start) *range-warp-dust-color*) + +(set! (-> *part-warp-fma-dust-takeoff-curve-settings* alpha-start) *range-warp-dust-alpha*) + +(set! (-> *part-warp-fma-dust-takeoff-curve-settings* scale-x-start) *range-warp-dust-scale-x*) + +(set! (-> *part-warp-fma-dust-takeoff-curve-settings* scale-y-start) *range-warp-dust-scale-y*) + +(set! (-> *part-warp-fma-dust-takeoff-curve-settings* r-scalar) #f) + +(set! (-> *part-warp-fma-dust-takeoff-curve-settings* g-scalar) #f) + +(set! (-> *part-warp-fma-dust-takeoff-curve-settings* b-scalar) #f) + +(set! (-> *part-warp-fma-dust-takeoff-curve-settings* a-scalar) *curve-warp-dust-alpha*) + +(set! (-> *part-warp-fma-dust-takeoff-curve-settings* scale-x-scalar) *curve-warp-dust-scale-x*) + +(set! (-> *part-warp-fma-dust-takeoff-curve-settings* scale-y-scalar) *curve-warp-dust-scale-y*) + +(defpartgroup group-warp-fma-drop-thrusters + :id 209 + :flags (sp0 sp4) + :bounds (static-bspherem 0 0 0 640) + :parts ((sp-item 845 :flags (sp7)) + (sp-item 846 :flags (sp7) :period (seconds 0.017) :length (seconds 0.017)) + (sp-item 847 :flags (sp7) :period (seconds 0.017) :length (seconds 0.017)) + ) + ) + +(defpart 845 + :init-specs ((:num 1.0) + (:x (meters -2) (meters 4)) + (:y (meters -2) (meters 4)) + (:z (meters -2) (meters 4)) + (:rot-x 5) + (:r 20480.0) + (:g 10240.0) + (:b 8192.0 4096.0) + (:timer (seconds 0.5)) + (:flags (distort launch-along-z)) + ) + ) + +(defpart 846 + :init-specs ((:texture (colorflash level-default-sprite)) + (:num 4.0) + (:scale-x (meters 2) (meters 2)) + (:scale-y :copy scale-x) + (:r 255.0) + (:g 200.0) + (:b 128.0) + (:a 40.0 10.0) + (:vel-y (meters 0.1)) + (:timer (seconds 0.017)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-3)) + (:conerot-z (degrees 0)) + (:rotate-y (degrees 0)) + ) + ) + +(defpart 847 + :init-specs ((:texture (glow level-default-sprite)) + (:num 3.0) + (:scale-x (meters 6) (meters 1)) + (:scale-y :copy scale-x) + (:r 255.0) + (:g 100.0 28.0) + (:b 0.0) + (:a 8.0 8.0) + (:vel-y (meters 0.1)) + (:timer (seconds 0.017)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-3)) + (:conerot-z (degrees 0)) + (:rotate-y (degrees 0)) + ) + ) + +(defpartgroup group-warp-thruster-trail + :id 210 + :flags (sp0 sp4 sp13) + :bounds (static-bspherem 0 0 0 640) + :parts ((sp-item 848 :flags (sp7))) + ) + +(defpart 848 + :init-specs ((:texture (big-cloud level-default-sprite)) + (:num 1.0) + (:scale-x (meters 3)) + (:rot-z (degrees 0) (degrees 360)) + (:scale-y :copy scale-x) + (:r 80.0 100.0) + (:g :copy r) + (:b :copy r) + (:a 20.0 10.0) + (:vel-y (meters 0.1)) + (:scalevel-x (meters 0.016666668) (meters 0.016666668)) + (:scalevel-y :copy scalevel-x) + (:fade-a -0.05 -0.05) + (:friction 0.9) + (:timer (seconds 2)) + (:flags (sp-cpuinfo-flag-2 sp-cpuinfo-flag-13)) + (:conerot-z (degrees 0)) + (:rotate-y (degrees 0)) + ) + ) diff --git a/goal_src/jak3/engine/mods/warp-gate-menu/warp-gate-menu-h.gc b/goal_src/jak3/engine/mods/warp-gate-menu/warp-gate-menu-h.gc new file mode 100644 index 0000000000..30720dcd2a --- /dev/null +++ b/goal_src/jak3/engine/mods/warp-gate-menu/warp-gate-menu-h.gc @@ -0,0 +1,240 @@ +;;-*-Lisp-*- +(in-package goal) + +#| This file defines the warp-gate destination menu structure and its related lists. + Each menu list corresponds to a specific warp-gate entity and contains + destinations Jak can warp to, based on mission/task progress. + + Also, check the method `init-defaults!` of the `warp-gate` type in `warp-gate-menu-data.gc`, + which is responsible for assigning a menu entry list to a specific entity. Do this if you + want to add custom warp-gate menus in your own custom levels. + |# + +(deftype warp-gate-menu-entry (structure) + ((level-name symbol) ;; level name + (continue-name string) ;; name of the checkpoint Jak will be teleported to + (text-id text-id) ;; text ID that defines the name displayed for this destination in the menu + (allow-when (function symbol)) ;; optional: function that must return true for this entry to become available + (forbid-when (function symbol)) ;; optional: function that hides this entry if it returns true, regardless of `allow-when` + (on-activate pair) ;; optional: actions executed when the destination is selected (e.g., play scenes, load levels, close tasks) + (wait-for pair) + (on-close pair) + ) + ) + +(defmacro static-warp-gate-menu-entry (&key level-name + &key continue-name + &key text-id + &key (allow-when #f) + &key (forbid-when #f) + &key (on-activate #f) + &key (wait-for #f) + &key (on-close #f)) + `(new 'static 'warp-gate-menu-entry + :level-name ,level-name + :continue-name ,continue-name + :text-id ,text-id + :allow-when ,allow-when + :forbid-when ,forbid-when + :on-activate ,on-activate + :wait-for ,wait-for + :on-close ,on-close + ) + ) + +;; just an empty array. leave it at is. +;; used as a fallback when an entity doesn't have a defined menu. +(define *empty-warp-gate-menu-list* (new 'static 'boxed-array :type warp-gate-menu-entry)) + +;; vinroom warp-gate +(define *warp-gate-21-menu-list* (new 'static 'boxed-array :type warp-gate-menu-entry + (static-warp-gate-menu-entry + :level-name 'volcanox + :continue-name "volcanox-warp" + :text-id (text-id volcano-name) ;"Volcano" + :allow-when (lambda () (task-closed? "volcano-darkeco-resolution")) ;; volcano mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'templex + :continue-name "templex-warp" + :text-id (text-id temple-name-entry) ;"Temple (Entrance)" + :allow-when (lambda () (task-closed? "city-power-game-resolution")) ;; power game mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'templeb + :continue-name "templeb-warp" + :text-id (text-id temple-name-oracle) ;"Temple (Oracle)" + :allow-when (lambda () (task-closed? "temple-defend-resolution")) ;; third temple mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'templed + :continue-name "templed-warp" + :text-id (text-id temple-name-ruins) ;"Temple (Ruins)" + :allow-when (lambda () (task-closed? "temple-defend-resolution")) ;; third temple mission required + :forbid-when #f + :on-activate #f + ) + ) + ) + +;; templex warp-gate +(define *warp-gate-31-menu-list* (new 'static 'boxed-array :type warp-gate-menu-entry + (static-warp-gate-menu-entry + :level-name 'volcanox + :continue-name "volcanox-warp" + :text-id (text-id volcano-name) ;"Volcano" + :allow-when (lambda () (task-closed? "volcano-darkeco-resolution")) ;; volcano mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'vinroom + :continue-name "vinroom-warp" + :text-id (text-id vinroom-name) ;"Power Station" + :allow-when (lambda () (task-closed? "city-power-game-resolution")) ;; power game mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'templeb + :continue-name "templeb-warp" + :text-id (text-id temple-name-oracle) ;"Temple (Oracle)" + :allow-when (lambda () (task-closed? "temple-defend-resolution")) ;; third temple mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'templed + :continue-name "templed-warp" + :text-id (text-id temple-name-ruins) ;"Temple (Ruins)" + :allow-when (lambda () (task-closed? "temple-defend-resolution")) ;; third temple mission required + :forbid-when #f + :on-activate #f + ) + ) + ) + +;; templeb warp-gate +(define *warp-gate-33-menu-list* (new 'static 'boxed-array :type warp-gate-menu-entry + (static-warp-gate-menu-entry + :level-name 'templex + :continue-name "templex-warp" + :text-id (text-id temple-name-entry) ;"Temple (Entrance)" + :allow-when (lambda () (task-closed? "temple-oracle-resolution")) ;; first temple mission required + :forbid-when (lambda () (task-closed? "temple-tests-introduction")) ;; unavailable from the second temple mission + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'volcanox + :continue-name "volcanox-warp" + :text-id (text-id volcano-name) ;"Volcano" + :allow-when (lambda () (task-closed? "temple-defend-resolution")) ;; third temple mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'vinroom + :continue-name "vinroom-warp" + :text-id (text-id vinroom-name) ;"Power Station" + :allow-when (lambda () (task-closed? "temple-defend-resolution")) ;; third temple mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'templex + :continue-name "templex-warp" + :text-id (text-id temple-name-entry) ;"Temple (Entrance)" + :allow-when (lambda () (task-closed? "temple-defend-resolution")) ;; third temple mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'templed + :continue-name "templed-warp" + :text-id (text-id temple-name-ruins) ;"Temple (Ruins)" + :allow-when (lambda () (task-closed? "temple-defend-resolution")) ;; third temple mission required + :forbid-when #f + :on-activate #f + ) + ) + ) + +;; templed warp-gate +(define *warp-gate-34-menu-list* (new 'static 'boxed-array :type warp-gate-menu-entry + (static-warp-gate-menu-entry + :level-name 'templex + :continue-name "templex-warp" + :text-id (text-id temple-name-entry) ;"Temple (Entrance)" + :allow-when (lambda () (task-closed? "temple-defend-resolution")) ;; third temple mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'volcanox + :continue-name "volcanox-warp" + :text-id (text-id volcano-name) ;"Volcano" + :allow-when (lambda () (task-closed? "wascity-defend-resolution")) ;; spargus defend mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'vinroom + :continue-name "vinroom-warp" + :text-id (text-id vinroom-name) ;"Power Station" + :allow-when (lambda () (task-closed? "wascity-defend-resolution")) ;; spargus defend mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'templeb + :continue-name "templeb-warp" + :text-id (text-id temple-name-oracle) ;"Temple (Oracle)" + :allow-when (lambda () (task-closed? "wascity-defend-resolution")) ;; spargus defend mission required + :forbid-when #f + :on-activate #f + ) + ) + ) + +;; volcanox warp-gate +(define *warp-gate-30-menu-list* (new 'static 'boxed-array :type warp-gate-menu-entry + (static-warp-gate-menu-entry + :level-name 'vinroom + :continue-name "vinroom-warp" + :text-id (text-id vinroom-name) ;"Power Station" + :allow-when (lambda () (task-closed? "city-power-game-resolution")) ;; power game mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'templex + :continue-name "templex-warp" + :text-id (text-id temple-name-entry) ;"Temple (Entrance)" + :allow-when (lambda () (task-closed? "volcano-darkeco-resolution")) ;; volcano mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'templeb + :continue-name "templeb-warp" + :text-id (text-id temple-name-oracle) ;"Temple (Oracle)" + :allow-when (lambda () (task-closed? "temple-defend-resolution")) ;; third temple mission required + :forbid-when #f + :on-activate #f + ) + (static-warp-gate-menu-entry + :level-name 'templed + :continue-name "templed-warp" + :text-id (text-id temple-name-ruins) ;"Temple (Ruins)" + :allow-when (lambda () (task-closed? "temple-defend-resolution")) ;; third temple mission required + :forbid-when #f + :on-activate #f + ) + ) + ) diff --git a/goal_src/jak3/engine/mods/warp-gate-menu/warp-gate-menu.gc b/goal_src/jak3/engine/mods/warp-gate-menu/warp-gate-menu.gc new file mode 100644 index 0000000000..4bbbac150c --- /dev/null +++ b/goal_src/jak3/engine/mods/warp-gate-menu/warp-gate-menu.gc @@ -0,0 +1,425 @@ +;;-*-Lisp-*- +(in-package goal) + +(define *wm-selected* -1) +(define *wm-wg-items-per-page* 6) + +(defmethod warp-select-menu ((this warp-gate)) + (let* ((menu (-> this wmenu-list)) + (list-length (-> menu length)) + (available-idxs (new 'static 'boxed-array :type int32)) ;; array to store the indexes of the options that are available for selection + (available-count 0) ;; stores the amount of options that are available for selection + ) + (dotimes (i list-length) + (let* ((allowed? (-> menu i allow-when)) + (forbidden? (-> menu i forbid-when))) + ;; include the option if `allowed?` is set and returns true, + ;; and `forbidden?` is either not set (not forbidden?) or does not return true (not (forbidden?)). + (when (and (or (not allowed?) (allowed?)) + (or (not forbidden?) (not (forbidden?)))) + (set! (-> available-idxs available-count) i) ;; store the available option indexes in `available-idxs` array + (+! available-count 1) + ) + ) + ) + + (let* ((page (-> this page)) ;; current page + (start-idx (* page *wm-wg-items-per-page*)) ;; start index of the current page + (end-idx (+ start-idx *wm-wg-items-per-page*)) ;; exclusive end index for the current page, used to check if there's a next page + (have-next-page? (< end-idx available-count)) ;; is there a next page? + (have-prev-page? (> page 0)) ;; is there a previous page? + (items-this-page (min *wm-wg-items-per-page* (- available-count start-idx))) ;; amount of items in this page (only destination options is counted) + (extra-options (cond ((and have-prev-page? have-next-page?) 2) ;; add 2 if have next and previous pages + (have-prev-page? 1) ;; add 1 if only have previous page + (have-next-page? 1) ;; add 1 if only have next page + (else 0))) ;; no extra option + (total-items (+ items-this-page extra-options)) ;; total entries displayed on screen + ) + (when (not (paused?)) + (cond + ((and (cpad-pressed? 0 up l-analog-up) (> (-> this selected) 0)) + (seekl! (-> this selected) 0 1) + (sound-play "dmenu-move") + ) + ((and (cpad-pressed? 0 down l-analog-down) (< (-> this selected) (+ total-items -1))) + (seekl! (-> this selected) (+ total-items -1) 1) + (sound-play "dmenu-move") + ) + ((and (cpad-pressed? 0 confirm) (nonzero? available-count)) + (sound-play "menu-pick") + (cond + ((and have-prev-page? (= (-> this selected) items-this-page)) ;; go to the previous page + (+! (-> this page) -1) + (set! (-> this selected) 0) + ) + ((and have-next-page? (or (and have-prev-page? (= (-> this selected) (+ items-this-page 1))) ;; go to the next page + (and (not have-prev-page?) (= (-> this selected) items-this-page)))) + (+! (-> this page) 1) + (set! (-> this selected) 0) + ) + (else ;; warp to the selected destination + (set! *wm-selected* (-> available-idxs (+ start-idx (-> this selected)))) + (go execute-warp) + ) + ) + ) + ) + (let* ((font-height 40) + (font-x 36) + (font-y (- 228 (* total-items (/ font-height 2)))) + (font-ctxt (new + 'stack + 'font-context + *font-default-matrix* + font-x + font-y + 0.0 + (font-color default) + (font-flags shadow kerning) + ) + ) + ) + (set! (-> font-ctxt flags) (font-flags shadow kerning middle middle-vert large)) + (set! (-> font-ctxt width) (the float 440)) + (set! (-> font-ctxt height) (the float 50)) + (set! (-> font-ctxt scale) 1.0) + (let ((a0-59 40)) + (set! (-> font-ctxt origin x) (the float font-x)) + (set! (-> font-ctxt origin y) (the float a0-59)) + ) + ;; print menu header + (set! (-> font-ctxt color) (font-color progress-old-yellow)) + (let ((select-text (lookup-text! *common-text* (text-id select-destination) #f))) + (format (clear *temp-string*) select-text) + ) + (print-game-text *temp-string* font-ctxt #f 44 (bucket-id hud-draw-hud-alpha)) + (set! (-> font-ctxt height) (the float font-height)) + ;; print menu options + (cond + ((nonzero? available-count) ;; menu have data, print the options on the screen. + (dotimes (i items-this-page) + (let ((valid-idx (-> available-idxs (+ start-idx i)))) + (set! (-> font-ctxt origin x) (the float font-x)) + (set! (-> font-ctxt origin y) (the float font-y)) + (set! (-> font-ctxt scale) (if (= (-> this selected) i) + 0.8 + 0.6 + ) + ) + (set! (-> font-ctxt color) (if (= (-> this selected) i) + (font-color progress-old-selected) + (font-color default) + ) + ) + (print-game-text (lookup-text! *common-text* (-> menu valid-idx text-id) #f) font-ctxt #f 44 (bucket-id hud-draw-hud-alpha)) + (+! font-y font-height) + ) + ) + (when have-prev-page? ;; print `Previous Page` if there is a previous page indeed + (set! (-> font-ctxt origin x) (the float font-x)) + (set! (-> font-ctxt origin y) (the float font-y)) + (set! (-> font-ctxt scale) (if (= (-> this selected) items-this-page) + 0.8 + 0.6 + ) + ) + (set! (-> font-ctxt color) (if (= (-> this selected) items-this-page) + (font-color progress-old-selected) + (font-color default) + ) + ) + (print-game-text (lookup-text! *common-text* (text-id previous-page) #f) font-ctxt #f 44 (bucket-id hud-draw-hud-alpha)) + (+! font-y font-height) + ) + (when have-next-page? ;; print `Next Page` if there is a next page indeed + (set! (-> font-ctxt origin x) (the float font-x)) + (set! (-> font-ctxt origin y) (the float font-y)) + (set! (-> font-ctxt scale) (if (= (-> this selected) (- total-items 1)) + 0.8 + 0.6 + ) + ) + (set! (-> font-ctxt color) (if (= (-> this selected) (- total-items 1)) + (font-color progress-old-selected) + (font-color default) + ) + ) + (print-game-text (lookup-text! *common-text* (text-id next-page) #f) font-ctxt #f 44 (bucket-id hud-draw-hud-alpha)) + (+! font-y font-height) + ) + ) + (else ;; no menu data, print an error message on the screen. + (set! (-> font-ctxt origin x) (the float font-x)) + (set! (-> font-ctxt origin y) (the float font-y)) + (set! (-> font-ctxt scale) 0.8) + (set! (-> font-ctxt color) (font-color default)) + (print-game-text (lookup-text! *common-text* (text-id no-menu-data) #f) font-ctxt #f 44 (bucket-id hud-draw-hud-alpha)) + ) + ) + ) + ) + ) + ) + (none) + ) + +(defmethod set-warp! ((this warp-gate) (idx int)) + (let ((menu (-> (-> this wmenu-list) idx))) + (set! (-> this level-name) (-> menu level-name)) + (set! (-> this continue) (get-continue-by-name *game-info* (-> menu continue-name))) + (set! (-> this on-activate) (the-as pair (-> menu on-activate))) + (set! (-> this wait-for) (-> menu wait-for)) + (set! (-> this on-close) (-> menu on-close)) + ) + (none) + ) + +(defmethod available-to-use? ((this warp-gate)) + (let* ((menu (-> this wmenu-list)) + (list-length (-> menu length)) + ) + (dotimes (i list-length) + (let* ((allowed? (-> menu i allow-when)) + (forbidden? (-> menu i forbid-when))) + ;; include the option if `allowed?` is set and returns true, + ;; and `forbidden?` is either not set (not forbidden?) or does not return true (not (forbidden?)). + (when (and (or (not allowed?) (allowed?)) + (or (not forbidden?) (not (forbidden?)))) + (return #t) + ) + ) + ) + (when (zero? list-length) + (return #t) ;; treat empty lists as available so that it can be displayed the "No Menu Data" error message instead of disabling interaction + ) + ) + #f + ) + +(defstate idle (warp-gate) + :virtual #t + :event (behavior ((proc process) (argc int) (message symbol) (block event-message-block)) + (case message + (('hide) + (go-virtual hidden) + ) + (('effect) + (script-eval '(part-tracker "group-warpgate" entity self joint "outerOut")) + ) + ) + ) + :code (behavior () + (remove-setting! 'allow-progress) + (set-time! (-> self state-time)) + (update-transforms (-> self root)) + (until #f + (when (and (and *target* + (and (>= (-> self distance) (vector-vector-distance (-> self root trans) (-> *target* control trans))) + (not (logtest? (focus-status teleporting) (-> *target* focus-status))) + ) + ) + (available-to-use? self) + (-> *setting-control* user-current airlock) + (begin + (persist-with-delay *setting-control* 'lightjak (seconds 0.1) 'lightjak #f 0.0 0) + (persist-with-delay *setting-control* 'darkjak (seconds 0.1) 'darkjak #f 0.0 0) + (persist-with-delay *setting-control* 'board (seconds 0.1) 'board #f 0.0 0) + (not (logtest? (focus-status in-head edge-grab pole flut tube light board pilot mech dark indax) + (-> *target* focus-status) + ) + ) + ) + (not (-> *setting-control* user-current hint)) + (zero? (-> *target* ext-anim)) + ) + (talker-surpress!) + (when (and (can-display-query? self "warp-gate" -99.0) + (cond + ((and (-> *target* next-state) (let ((v1-37 (-> *target* next-state name))) + (or (= v1-37 'target-warp-in) (= v1-37 'target-warp-out)) + ) + ) + (set-time! (-> self state-time)) + #f + ) + (else + #t + ) + ) + (time-elapsed? (-> self state-time) (seconds 0.1)) + ) + (when (cpad-pressed? 0 triangle) + (logclear! (-> *cpad-list* cpads 0 button0-abs 0) (pad-buttons triangle)) + (logclear! (-> *cpad-list* cpads 0 button0-rel 0) (pad-buttons triangle)) + (go warp-gate-menu) + ) + (script-eval (-> self on-close)) + (let ((gp-0 (new 'stack 'font-context *font-default-matrix* 32 320 0.0 (font-color default) (font-flags shadow kerning)))) + (set-width! gp-0 340) + (set-height! gp-0 80) + (let ((v1-60 gp-0) + (a0-25 (-> *setting-control* user-default language)) + ) + (set! (-> v1-60 scale) (if (or (= a0-25 (language-enum korean)) (= a0-25 (language-enum russian))) + 0.9 + 0.7 + ) + ) + ) + (set! (-> gp-0 flags) (font-flags shadow kerning large)) + (print-game-text + (lookup-text! *common-text* (text-id text-0083) #f) + gp-0 + #f + 44 + (bucket-id hud-draw-hud-alpha) + ) + ) + ) + ) + (cond + ((available-to-use? self) + (seek! (-> self anim-speed) 1.0 (* 2.0 (seconds-per-frame))) + (setup-masks (-> self draw) 2 0) + ) + (else + (setup-masks (-> self draw) 0 2) + (seek! (-> self anim-speed) 0.0 (* 2.0 (seconds-per-frame))) + ) + ) + (update! (-> self sound)) + (ja-post) + (suspend) + (ja :num! (loop! (-> self anim-speed))) + ) + #f + ) + ) + +(defstate warp-gate-menu (warp-gate) + :enter (behavior () + (set-setting! 'minimap 'clear 0.0 (minimap-flag minimap)) + (set-time! (-> self state-time)) + ) + :exit (behavior () + (remove-setting! 'minimap) + (send-event *camera* 'change-target *target*) + (remove-setting! 'interp-time) + (remove-setting! 'mode-name) + ) + :trans (behavior () + ;(format *stdcon* "selected: ~D~%" *wm-selected*) + ;(format *stdcon* "page: ~D~%" (-> self page)) + (when (time-elapsed? (-> self state-time) (seconds 0.5)) + (warp-select-menu self) + (when (cpad-pressed? 0 triangle) + (when (and (not (process-grab? *target* #f)) (not (real-movie?))) + (process-release? *target*) + ) + (go-virtual idle) + ) + ) + ) + :code (behavior () + (set-setting! 'mode-name 'cam-really-fixed 0.0 0) + (suspend) + (until (process-grab? *target* #f) + (suspend) + ) + (sleep-code) + ) + ) + +(defstate execute-warp (warp-gate) + :event (behavior ((proc process) (argc int) (message symbol) (block event-message-block)) + (case message + (('effect) + (script-eval '(part-tracker "group-warpgate" entity self joint "outerOut")) + ) + ) + ) + :enter (behavior () + (set-warp! self *wm-selected*) + ) + :exit (behavior () + (remove-setting! 'mode-name) + (remove-setting! 'interp-time) + ) + :trans (behavior () + (send-event *camera* 'joystick 0.0 0.0) + ) + :code (behavior () + (local-vars (v1-38 symbol)) + (kill-current-talker '() '() 'exit) + (set-setting! 'mode-name 'cam-fixed 0.0 0) + (set-setting! 'interp-time 'abs 0.0 0) + (set-time! (-> self state-time)) + (logclear! (-> self mask) (process-mask actor-pause)) + (when (not (-> self continue)) + (process-release? *target*) + (go-virtual idle) + ) + (set-setting! 'allow-progress #f 0.0 0) + (set! (-> *setting-control* user-default border-mode) #t) + (set! (-> *level* play?) #t) + (apply-settings *setting-control*) + (let ((s5-0 (new 'stack-no-clear 'event-message-block))) + (set! (-> s5-0 from) (process->ppointer self)) + (set! (-> s5-0 num-params) 4) + (set! (-> s5-0 message) 'change-state) + (set! (-> s5-0 param 0) (the-as uint target-warp-out)) + (let ((v1-22 (new 'static 'vector))) + (vector-copy! v1-22 (-> self center)) + (set! (-> s5-0 param 1) (the-as uint v1-22)) + ) + (set! (-> s5-0 param 2) (the-as uint (target-pos 0))) + (set! (-> s5-0 param 3) (the-as uint (process->handle self))) + (send-event-function *target* s5-0) + ) + (when (-> self on-activate) + (script-eval (-> self on-activate)) + ) + (while (begin + (set! v1-38 (when (-> self wait-for) + (let* ((s5-1 (-> self wait-for)) + (a1-8 (car s5-1)) + ) + (while (not (null? s5-1)) + (when (not (member (level-status? *level* (the-as symbol a1-8) #f) '(loaded active))) + (set! v1-38 #t) + (goto cfg-21) + ) + (set! s5-1 (cdr s5-1)) + (set! a1-8 (car s5-1)) + ) + ) + #f + ) + ) + (label cfg-21) + (or v1-38 (not (time-elapsed? (-> self state-time) (seconds 2)))) + ) + (update! (-> self sound)) + (suspend) + (ja :num! (loop!)) + (ja-post) + ) + (if (not (logtest? (-> (-> self continue) flags) (continue-flags no-blackout))) + (set-blackout-frames (seconds 0.05)) + ) + (start 'play (-> self continue)) + (suspend-for (seconds 1) + ) + (while (and *target* (and (>= 81920.0 (vector-vector-distance (-> self root trans) (-> *target* control trans))) + (not (logtest? (focus-status teleporting) (-> *target* focus-status))) + ) + ) + (suspend) + (ja :num! (loop!)) + (ja-post) + ) + (logior! (-> self mask) (process-mask actor-pause)) + (go-virtual idle) + ) + ) + \ No newline at end of file diff --git a/goal_src/jak3/engine/ui/text-h.gc b/goal_src/jak3/engine/ui/text-h.gc index 3701f5f02b..6c0e149b6a 100644 --- a/goal_src/jak3/engine/ui/text-h.gc +++ b/goal_src/jak3/engine/ui/text-h.gc @@ -1617,6 +1617,22 @@ (pad-circle #x2001) (pad-x #x2002) (pad-square #x2003) + + ;; destination names text + (ctyport-name #x10000) + (desert-name #x10001) + (volcano-name #x10002) + (temple-name-entry #x10003) + (temple-name-oracle #x10004) + (temple-name-ruins #x10005) + (vinroom-name #x10006) + + ;; menu stuff text + (select-destination #x100000) + (no-menu-data #x100001) + (next-page #x100002) + (previous-page #x100003) + ) ;; ---text-id From 53fab14f34a8a638b98433d2e3a3502da57d7d36 Mon Sep 17 00:00:00 2001 From: Nick0778 <149975116+Nick0778@users.noreply.github.com> Date: Sun, 17 May 2026 23:02:01 -0300 Subject: [PATCH 3/7] fix `templed-warp` weird jak and camera initial transforms --- goal_src/jak3/engine/level/level-info.gc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/goal_src/jak3/engine/level/level-info.gc b/goal_src/jak3/engine/level/level-info.gc index bc74fb1886..19cdcd0873 100644 --- a/goal_src/jak3/engine/level/level-info.gc +++ b/goal_src/jak3/engine/level/level-info.gc @@ -17846,10 +17846,11 @@ :name "templed-warp" :level 'templed :flags (continue-flags no-auto warp-gate) - :trans (new 'static 'vector :x 17512212.0 :y 389120.0 :z 18223136.0 :w 1.0) - :camera-trans (new 'static 'vector :x 17555770.0 :y 409207.2 :z 18242222.0 :w 1.0) - :quat (new 'static 'vector4h :data (new 'static 'array int16 4 0 -19542 0 -26298)) - :camera-rot (new 'static 'array int16 9 -13637 0 #x745f -4384 #x7e99 -2005 -29467 -4823 -13490) + ;; mod-base-change changed jak and camera misaligned initial transforms for this checkpoint + :trans (new 'static 'vector :x (meters 4279.29) :y (meters 95.18) :z (meters 4446.81) :w 1.0) + :camera-trans (new 'static 'vector :x 17576318.0 :y 410942.1562 :z 18230798.0 :w 1.0) + :quat (new 'static 'vector4h :data (new 'static 'array int16 4 0 -19005 0 -26542)) + :camera-rot (new 'static 'array int16 9 -10636 0 31001 -4712 32384 -1615 -30631 -4984 -10511) :on-goto #f :vis-nick 'templed :vehicle-type #x1b From ce177a35308523380c572700023655b9ac5ef767 Mon Sep 17 00:00:00 2001 From: Nick0778 <149975116+Nick0778@users.noreply.github.com> Date: Sun, 17 May 2026 23:11:30 -0300 Subject: [PATCH 4/7] kill `"vol-holo-eye-1"` entity when entering volcano via warp-gate --- goal_src/jak3/engine/level/level-info.gc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/goal_src/jak3/engine/level/level-info.gc b/goal_src/jak3/engine/level/level-info.gc index 19cdcd0873..e4aa125bf7 100644 --- a/goal_src/jak3/engine/level/level-info.gc +++ b/goal_src/jak3/engine/level/level-info.gc @@ -18167,7 +18167,7 @@ :camera-trans (new 'static 'vector :x -519551.78 :y 18144.46 :z -1833278.2 :w 1.0) :quat (new 'static 'vector4h :data (new 'static 'array int16 4 -3 -24001 0 -22304)) :camera-rot (new 'static 'array int16 9 -4826 0 #x7e96 -6097 #x7db4 -907 -31829 -6166 -4741) - :on-goto #f + :on-goto '(begin (kill "vol-holo-eye-1" store #f)) ;;mod-base-change kill "vol-holo-eye-1" when entering volcano via warp-gate :vis-nick 'volcanox :vehicle-type #x1b :want-count 1 From 149fef81b6285bd5792610b74983915ed5d72a0f Mon Sep 17 00:00:00 2001 From: Nick0778 <149975116+Nick0778@users.noreply.github.com> Date: Mon, 18 May 2026 18:59:37 -0300 Subject: [PATCH 5/7] Add README for Air Train/Warp Gate Menu System --- .../jak3/engine/mods/air-train-menu/README.md | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 goal_src/jak3/engine/mods/air-train-menu/README.md diff --git a/goal_src/jak3/engine/mods/air-train-menu/README.md b/goal_src/jak3/engine/mods/air-train-menu/README.md new file mode 100644 index 0000000000..7901b0f6f3 --- /dev/null +++ b/goal_src/jak3/engine/mods/air-train-menu/README.md @@ -0,0 +1,125 @@ +## Air Train / Warp Gate Destination Menu System + +This branch implements a menu system that allows you to select and teleport to a destination using any Air Train or Warp Gate in the game. +It also supports adding custom destination menus for Air Trains and Warp Gates in your own custom levels. + +**Note:** This system is **disabled by default**. To enable it, go to: +`\goal_src\jak3\dgos\game.gd` +Scroll to the bottom of the file and **uncomment all the lines related to the menu system**, and **comment out** the original `warp-gate.gc` line. + +The image below highlights the files that need to be uncommented: + +img1 + +Below are two examples: one showing **how to add new options to existing menus for Air Trains**, and another demonstrating **how to assign a new menu to an Air Train entity placed in a custom level**. + +### 1. How to add new options to existing menus for Air Trains + +#### 1.1. Open the Menu Definitions File +Go to: +`\goal_src\jak3\engine\mods\air-train-menu\air-train-menu-h.gc` +After opening this file, you will see this: + +img2 + +As you can see, this file defines the Air Train destination menus for all vanilla entities. + +Just below that, you’ll find the definition for `*air-train-1-menu-data*`, which in this case defines a menu with only one destination option: `Desert Wasteland` for the Haven City Port Air Train. + +#### 1.2. Add a New Entry for Eco Mine (Example) +Now, let’s suppose you want to add a new destination where Jak can be teleported to **Eco Mine**. +To do this, simply copy the existing entry and paste it below. + +Then adjust the values as follows: +- Set the `level-name` to `'minec` +- Set the `continue-name` to `"minec-start"` (the name of the checkpoint Jak will warp to) +- Set `allow-when` to `#f` if you don’t want to restrict it to a specific task +- Leave `on-activate` empty or remove it if no action is needed + +You should end up with something like this: + +img3 + +#### 1.3. Add the Display Text + +Now, for the `text-id`, you’ll need to add a new text entry so that the option appears as **Eco Mine** instead of reusing a label like `Desert Wasteland`. + +Go to: +`\game\assets\jak3\text\game_custom_text_en-US.json` +Scroll to the end and add: + +img4 + +Then go to: +`\goal_src\jak3\engine\ui\text-h.gc` +Scroll down and add the corresponding `text-id` constant: + +img5 + +Finally, go back to: +`\goal_src\jak3\engine\mods\air-train-menu\air-train-menu-h.gc` +and update the entry to use your new `text-id`: + +img6 + +#### 1.4. Test in Game + +Once you’ve done all this, rebuild the game and head to the Haven City Port Air Train to test your new destination! + +img7 +img8 + +### 2. How to assign a new menu to an Air Train entity placed in a custom level + +Now, let’s say you want to create a new menu and assign it to an Air Train entity placed in your custom level. The process is similar to the previous one, but this time you’ll define a new menu list in `air-train-menu-h.gc`. + +**Note:** This example uses the custom level `test-zone`. + +#### 2.1. Create a New Menu Data + +Define a simple menu list like this: + +img9 + +In this example, Jak will be able to teleport to `Haven City Port`. + +#### 2.2. Add a Return Option to an Existing Menu + +To allow Jak to return to your custom level, add a new entry to `*air-train-1-menu-data*` (Haven City Port Air Train): + +img10 + +Also, make sure to add a new text entry, so the option appears with your custom level's name, following the same process from the previous example. + +#### 2.3. Place the Entity in Your Custom Level + +Next, in your custom level `.jsonc` file, add the Air Train entity like this: + +img11 + +**Note:** Make sure to include `air-train-ag.go` in your custom level’s `.gd` file. Also, don’t forget to set the `"distance"` lump to define how close Jak needs to be to interact with the Air Train. + +#### 2.4. Assign the Menu to the Entity + +Go to: + `\goal_src\jak3\engine\mods\warp-gate-menu\warp-gate-menu-data.gc` +Scroll down to the `init-defaults!` method of the `air-train` type: + +img12 + +Then, add a new case with the name of the Air Train entity you placed in your custom level: + +img13 + +#### 2.5. Test in Game + +Once you’ve done all this, rebuild the game and head to the Haven City Port Air Train. You should now be able to teleport to your custom level and test your custom menu! + +img14 +img15 + +**Note:** The logic is the same for Warp Gates. However, to add new entries or menus, go to: `\goal_src\jak3\engine\mods\warp-gate-menu\warp-gate-menu-h.gc`. To assign a menu to a Warp Gate entity, edit the `init-defaults!` method of the `warp-gate` type in: `\goal_src\jak3\engine\mods\warp-gate-menu\warp-gate-menu-data.gc` + +I hope this contributes to the development of your mods! + +*~~Nick07* From 2ef84a6930bfdd29f08e58a397a5250981e2adb8 Mon Sep 17 00:00:00 2001 From: Nick0778 <149975116+Nick0778@users.noreply.github.com> Date: Mon, 18 May 2026 19:03:52 -0300 Subject: [PATCH 6/7] Add README for Air Train/Warp Gate Menu System 2 --- .../jak3/engine/mods/warp-gate-menu/README.md | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 goal_src/jak3/engine/mods/warp-gate-menu/README.md diff --git a/goal_src/jak3/engine/mods/warp-gate-menu/README.md b/goal_src/jak3/engine/mods/warp-gate-menu/README.md new file mode 100644 index 0000000000..7901b0f6f3 --- /dev/null +++ b/goal_src/jak3/engine/mods/warp-gate-menu/README.md @@ -0,0 +1,125 @@ +## Air Train / Warp Gate Destination Menu System + +This branch implements a menu system that allows you to select and teleport to a destination using any Air Train or Warp Gate in the game. +It also supports adding custom destination menus for Air Trains and Warp Gates in your own custom levels. + +**Note:** This system is **disabled by default**. To enable it, go to: +`\goal_src\jak3\dgos\game.gd` +Scroll to the bottom of the file and **uncomment all the lines related to the menu system**, and **comment out** the original `warp-gate.gc` line. + +The image below highlights the files that need to be uncommented: + +img1 + +Below are two examples: one showing **how to add new options to existing menus for Air Trains**, and another demonstrating **how to assign a new menu to an Air Train entity placed in a custom level**. + +### 1. How to add new options to existing menus for Air Trains + +#### 1.1. Open the Menu Definitions File +Go to: +`\goal_src\jak3\engine\mods\air-train-menu\air-train-menu-h.gc` +After opening this file, you will see this: + +img2 + +As you can see, this file defines the Air Train destination menus for all vanilla entities. + +Just below that, you’ll find the definition for `*air-train-1-menu-data*`, which in this case defines a menu with only one destination option: `Desert Wasteland` for the Haven City Port Air Train. + +#### 1.2. Add a New Entry for Eco Mine (Example) +Now, let’s suppose you want to add a new destination where Jak can be teleported to **Eco Mine**. +To do this, simply copy the existing entry and paste it below. + +Then adjust the values as follows: +- Set the `level-name` to `'minec` +- Set the `continue-name` to `"minec-start"` (the name of the checkpoint Jak will warp to) +- Set `allow-when` to `#f` if you don’t want to restrict it to a specific task +- Leave `on-activate` empty or remove it if no action is needed + +You should end up with something like this: + +img3 + +#### 1.3. Add the Display Text + +Now, for the `text-id`, you’ll need to add a new text entry so that the option appears as **Eco Mine** instead of reusing a label like `Desert Wasteland`. + +Go to: +`\game\assets\jak3\text\game_custom_text_en-US.json` +Scroll to the end and add: + +img4 + +Then go to: +`\goal_src\jak3\engine\ui\text-h.gc` +Scroll down and add the corresponding `text-id` constant: + +img5 + +Finally, go back to: +`\goal_src\jak3\engine\mods\air-train-menu\air-train-menu-h.gc` +and update the entry to use your new `text-id`: + +img6 + +#### 1.4. Test in Game + +Once you’ve done all this, rebuild the game and head to the Haven City Port Air Train to test your new destination! + +img7 +img8 + +### 2. How to assign a new menu to an Air Train entity placed in a custom level + +Now, let’s say you want to create a new menu and assign it to an Air Train entity placed in your custom level. The process is similar to the previous one, but this time you’ll define a new menu list in `air-train-menu-h.gc`. + +**Note:** This example uses the custom level `test-zone`. + +#### 2.1. Create a New Menu Data + +Define a simple menu list like this: + +img9 + +In this example, Jak will be able to teleport to `Haven City Port`. + +#### 2.2. Add a Return Option to an Existing Menu + +To allow Jak to return to your custom level, add a new entry to `*air-train-1-menu-data*` (Haven City Port Air Train): + +img10 + +Also, make sure to add a new text entry, so the option appears with your custom level's name, following the same process from the previous example. + +#### 2.3. Place the Entity in Your Custom Level + +Next, in your custom level `.jsonc` file, add the Air Train entity like this: + +img11 + +**Note:** Make sure to include `air-train-ag.go` in your custom level’s `.gd` file. Also, don’t forget to set the `"distance"` lump to define how close Jak needs to be to interact with the Air Train. + +#### 2.4. Assign the Menu to the Entity + +Go to: + `\goal_src\jak3\engine\mods\warp-gate-menu\warp-gate-menu-data.gc` +Scroll down to the `init-defaults!` method of the `air-train` type: + +img12 + +Then, add a new case with the name of the Air Train entity you placed in your custom level: + +img13 + +#### 2.5. Test in Game + +Once you’ve done all this, rebuild the game and head to the Haven City Port Air Train. You should now be able to teleport to your custom level and test your custom menu! + +img14 +img15 + +**Note:** The logic is the same for Warp Gates. However, to add new entries or menus, go to: `\goal_src\jak3\engine\mods\warp-gate-menu\warp-gate-menu-h.gc`. To assign a menu to a Warp Gate entity, edit the `init-defaults!` method of the `warp-gate` type in: `\goal_src\jak3\engine\mods\warp-gate-menu\warp-gate-menu-data.gc` + +I hope this contributes to the development of your mods! + +*~~Nick07* From d3f4995bb77d808f39867728e25e4b8eb7081719 Mon Sep 17 00:00:00 2001 From: Nick0778 <149975116+Nick0778@users.noreply.github.com> Date: Mon, 18 May 2026 20:01:01 -0300 Subject: [PATCH 7/7] reduce delay time to open the air-train menu in Jak II I reduced the delay time because it took too long to open the menu, and it could get boring :( --- goal_src/jak2/engine/mods/air-train-menu/air-train-menu.gc | 2 +- goal_src/jak2/engine/mods/warp-gate-menu/warp-gate-menu.gc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/goal_src/jak2/engine/mods/air-train-menu/air-train-menu.gc b/goal_src/jak2/engine/mods/air-train-menu/air-train-menu.gc index b58026ae7a..84fcb58f95 100644 --- a/goal_src/jak2/engine/mods/air-train-menu/air-train-menu.gc +++ b/goal_src/jak2/engine/mods/air-train-menu/air-train-menu.gc @@ -293,7 +293,7 @@ :trans (behavior () ;(format *stdcon* "selected: ~D~%" *wm-selected*) ;(format *stdcon* "page: ~D~%" (-> self page)) - (when (time-elapsed? (-> self state-time) (seconds 1.5)) + (when (time-elapsed? (-> self state-time) (seconds 0.5)) (warp-select-menu self) (when (cpad-pressed? 0 triangle) (when (and (not (process-grab? *target* #f)) (not (real-movie?))) diff --git a/goal_src/jak2/engine/mods/warp-gate-menu/warp-gate-menu.gc b/goal_src/jak2/engine/mods/warp-gate-menu/warp-gate-menu.gc index d9f32d33db..c2fef24ca3 100644 --- a/goal_src/jak2/engine/mods/warp-gate-menu/warp-gate-menu.gc +++ b/goal_src/jak2/engine/mods/warp-gate-menu/warp-gate-menu.gc @@ -320,7 +320,7 @@ :trans (behavior () ;(format *stdcon* "selected: ~D~%" *wm-selected*) ;(format *stdcon* "page: ~D~%" (-> self page)) - (when (time-elapsed? (-> self state-time) (seconds 1.5)) + (when (time-elapsed? (-> self state-time) (seconds 0.5)) (warp-select-menu self) (when (cpad-pressed? 0 triangle) (when (and (not (process-grab? *target* #f)) (not (real-movie?)))