Files
jak-project/goal_src/jak1/engine/common-obs/orb-cache.gc
T
2026-07-28 12:00:35 -07:00

246 lines
13 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
(bundles "GAME.CGO")
(require "engine/common-obs/collectables.gc")
(require "engine/common-obs/baseplat.gc")
;; DECOMP BEGINS
(deftype orb-cache-top (baseplat)
((active-distance float)
(inactive-distance float)
(money-list handle 60)
(money-pos-list float 60)
(money-pos-actual float 60)
(platform-pos float)
(root-pos float)
(money int32)
(activated symbol))
(:methods
(pos-logic (_type_ symbol) symbol)
(calculate-pos (_type_ symbol) none))
(:states (orb-cache-top-activate symbol)
(orb-cache-top-complete symbol)
(orb-cache-top-idle symbol)))
(defskelgroup *orb-cache-top-sg*
orb-cache-top
orb-cache-top-lod0-jg
orb-cache-top-idle-ja
((orb-cache-top-lod0-mg (meters 20)) (orb-cache-top-lod1-mg (meters 999999)))
:bounds (static-spherem 0 0 0 4))
;; The closed cache waits for a blue-eco charge and hints when Jak approaches without one.
(defstate orb-cache-top-idle (orb-cache-top)
:event
(behavior ((source process) (argc int) (message symbol) (block event-message-block))
(case message
(('eco-blue)
(process-entity-status! self (entity-perm-status complete) #t)
(dotimes (i 5)
(spawn-projectile-blue *target*))
(increment-success-for-hint (text-id sidekick-hint-orb-cache-top))
(go orb-cache-top-activate #f))
(else (plat-event source argc message block))))
:trans
(behavior ()
(if (and (and *target* (>= 20480.0 (vector-vector-distance (-> self root trans) (-> *target* control trans))))
(not (send-event *target* 'query 'powerup (pickup-type eco-blue))))
(level-hint-spawn (text-id sidekick-hint-orb-cache-top) "sksp0009" (the-as entity #f) *entity-pool* (game-task none))))
:code
(behavior ((initial? symbol))
(if (and (not initial?) (-> self child)) (sound-play "close-orb-cash"))
(dotimes (i (-> self money))
(let ((orb-process (handle->process (-> self money-list i)))) (if orb-process (deactivate orb-process))))
(process-entity-status! self (entity-perm-status complete) #f)
(ja :group! orb-cache-top-idle-ja :num! (identity (ja-aframe 0.0 0)))
(transform-post)
(anim-loop)))
(defmethod bounce! ((this orb-cache-top))
"Wake the platform and start a 150-tick vertical bounce with a 60-tick period. Use full
downward amplitude after the platform has risen more than one metre from root-pos, and half
amplitude while it is near the closed position."
(if (< 4096.0 (- (-> this basetrans y) (-> this root-pos)))
(activate! (-> this smush) -1.0 60 150 1.0 1.0)
(activate! (-> this smush) -0.5 60 150 1.0 1.0))
(set! (-> this bouncing) #t)
(logclear! (-> this mask) (process-mask sleep))
0
(none))
(defmethod calculate-pos ((this orb-cache-top) (open? symbol))
"Calculate platform-pos and each remaining orb's desired height. An open cache raises the
platform 2.5 metres plus 1.5 metres per orb after the first and stacks the orbs downward at
1.5-metre intervals; a closed cache targets root-pos."
(let ((platform-offset 0.0))
(when open?
(set! platform-offset (+ 10240.0 (* 6144.0 (the float (+ (-> this money) -1)))))
(if (< platform-offset 2048.0) (set! platform-offset 2048.0)))
(set! (-> this platform-pos) (+ (-> this root-pos) platform-offset))
(let ((orb-offset (+ -6144.0 platform-offset)))
(dotimes (i (-> this money))
(set! (-> this money-pos-list i) (+ (-> this root-pos) orb-offset))
(set! orb-offset (+ -6144.0 orb-offset)))))
0
(none))
(defmethod pos-logic ((this orb-cache-top) (open? symbol))
"Remove collected orbs from the packed handle and height arrays, update the persistent
collected count, and seek the platform and remaining orbs toward their desired heights.
While closing, do not lower the platform onto a player underneath it. Enter complete once
no orbs remain and every height has settled; return true when all current seeks are done."
(dotimes (i (-> this money))
(when (not (handle->process (-> this money-list i)))
(dotimes (shift-index (-> this money))
(when (< i shift-index)
(set! (-> this money-list (+ shift-index -1)) (-> this money-list shift-index))
(set! (-> this money-pos-actual (+ shift-index -1)) (-> this money-pos-actual shift-index))))
(+! (-> this money) -1)
(calculate-pos this open?)
(+! i -1)
(let ((permanent-state (-> this entity extra perm)))
(logior! (-> permanent-state status) (entity-perm-status user-set-from-cstage))
(+! (-> permanent-state user-int16 0) 1))))
(let ((orb-position (new 'stack-no-clear 'vector))
(at-target? #t))
(let ((complete? #f))
(let ((current-platform-offset (- (-> this basetrans y) (-> this root-pos)))
(target-platform-offset (- (-> this platform-pos) (-> this root-pos))))
(when (zero? (-> this money))
(set! target-platform-offset 2048.0)
(set! complete? #t))
;; Hold or lift the lid when Jak is below it; never finish closing onto him.
(when (and (< target-platform-offset 15155.2)
(and *target* (>= 16384.0 (vector-vector-distance (-> this root trans) (-> *target* control trans))))
(< (-> (target-pos 0) y) (-> this basetrans y)))
(set! target-platform-offset (if (< 14131.2 current-platform-offset) 15155.2 current-platform-offset))
(set! complete? #f))
(seek! (-> this basetrans y) (+ (-> this root-pos) target-platform-offset) (* 40960.0 (seconds-per-frame)))
(if (not (= (-> this basetrans y) (+ (-> this root-pos) target-platform-offset))) (set! at-target? #f)))
(dotimes (orb-index (-> this money))
(vector-copy! orb-position (-> (the-as process-drawable (handle->process (-> this money-list orb-index))) root trans))
(seek! (-> this money-pos-actual orb-index) (-> this money-pos-list orb-index) (* 40960.0 (seconds-per-frame)))
(if (not (= (-> this money-pos-actual orb-index) (-> this money-pos-list orb-index))) (set! at-target? #f))
(if (>= (-> this money-pos-actual orb-index) (+ -8192.0 (-> this root-pos)))
(set! (-> orb-position y) (-> this money-pos-actual orb-index))
(set! (-> orb-position y) (+ -8192.0 (-> this root-pos))))
(send-event (handle->process (-> this money-list orb-index)) 'trans orb-position))
(set! complete? (and at-target? complete?))
(if complete? (go orb-cache-top-complete #f)))
at-target?))
;; Keep the raised cache alive while Jak is nearby. Once he leaves, lower it until he returns with
;; blue eco or the platform reaches the closed position.
(defstate orb-cache-top-activate (orb-cache-top)
:event plat-event
:exit
(behavior ()
(process-entity-status! self (entity-perm-status no-kill) #f))
:trans plat-trans
:code
(behavior ((initial? symbol))
(process-entity-status! self (entity-perm-status no-kill) #t)
(calculate-pos self initial?)
(if initial? (set! (-> self basetrans y) (-> self platform-pos)) (sound-play "open-orb-cash"))
(dotimes (i (-> self money))
(let ((spawn-position (new 'stack-no-clear 'vector)))
(vector-copy! spawn-position (-> self basetrans))
(set! (-> spawn-position y) (-> self money-pos-list i))
(set! (-> self money-pos-actual i) (-> spawn-position y))
(set! (-> self money-list i)
(ppointer->handle (process-spawn money :init money-init-by-other-no-bob spawn-position *null-vector* 5 1.0 (-> self entity) :to self)))))
(loop
(calculate-pos self #t)
(while (not (or (not *target*)
(< (-> self inactive-distance) (vector-vector-xz-distance (-> self root trans) (-> *target* control trans)))))
(pos-logic self #t)
(suspend))
(calculate-pos self #f)
(while (and (not (and (and *target*
(>= (-> self active-distance) (vector-vector-xz-distance (-> self root trans) (-> *target* control trans))))
(let ((reopen-query (new 'stack-no-clear 'event-message-block)))
(set! (-> reopen-query from) self)
(set! (-> reopen-query num-params) 2)
(set! (-> reopen-query message) 'query)
(set! (-> reopen-query param 0) (the-as uint 'powerup))
(set! (-> reopen-query param 1) (the-as uint (pickup-type eco-blue)))
(or (send-event-function *target* reopen-query) (-> self activated)))))
(not (pos-logic self #f)))
(suspend))
(if (not (and (and *target*
(>= (-> self active-distance) (vector-vector-xz-distance (-> self root trans) (-> *target* control trans))))
(let ((final-query (new 'stack-no-clear 'event-message-block)))
(set! (-> final-query from) self)
(set! (-> final-query num-params) 2)
(set! (-> final-query message) 'query)
(set! (-> final-query param 0) (the-as uint 'powerup))
(set! (-> final-query param 1) (the-as uint (pickup-type eco-blue)))
(or (send-event-function *target* final-query) (-> self activated)))))
(go orb-cache-top-idle initial?))))
:post plat-post)
(defstate orb-cache-top-complete (orb-cache-top)
:event plat-event
:trans plat-trans
:code
(behavior ((initial? symbol))
(if (not initial?) (sound-play "close-orb-cash"))
(ja :group! orb-cache-top-idle-ja :num! (identity (ja-aframe 0.0 0)))
(new 'stack-no-clear 'vector)
(set! (-> self basetrans y) (+ 2048.0 (-> self root-pos)))
(anim-loop))
:post plat-post)
(defmethod init-from-entity! ((this orb-cache-top) (source-entity entity-actor))
"Create the sticky blue-eco platform collision, drawable, and skeleton. Load the configured
orb count, subtract the number already collected from permanent state, initialize the
fifteen-metre open and sixty-metre close distances, and enter complete, active, or idle
according to the remaining count and saved activation flag. The configured count must fit
the fixed sixty-entry handle and height arrays."
(let ((placed-entity (-> this entity)))
(if (when placed-entity
(let ((assigned-task (-> placed-entity extra perm task))) (if assigned-task (= assigned-task (game-task none)))))
(set! (-> this entity extra perm task) (game-task complete))))
(let ((collision (new 'process 'collide-shape-moving this (collide-list-enum hit-by-player))))
(set! (-> collision dynam) (copy *standard-dynamics* 'process))
(set! (-> collision reaction) default-collision-reaction)
(set! (-> collision no-reaction)
(the-as (function collide-shape-moving collide-shape-intersect vector vector none) nothing))
(alloc-riders collision 1)
(let ((collision-mesh (new 'process 'collide-shape-prim-mesh collision (the-as uint 0) (the-as uint 0))))
(set! (-> collision-mesh prim-core collide-as) (collide-kind ground-object blue-eco-suck))
(set! (-> collision-mesh collide-with) (collide-kind target))
(set! (-> collision-mesh prim-core action) (collide-action solid rider-plat-sticky))
(set! (-> collision-mesh prim-core offense) (collide-offense indestructible))
(set! (-> collision-mesh transform-index) 0)
(set-vector! (-> collision-mesh local-sphere) 0.0 0.0 0.0 11468.8)
(set-root-prim! collision collision-mesh))
(set! (-> collision nav-radius) (* 0.75 (-> collision root-prim local-sphere w)))
(backup-collide-with-as collision)
(set! (-> this root) collision))
(process-drawable-from-entity! this source-entity)
(logclear! (-> this mask) (process-mask actor-pause))
(initialize-skeleton this *orb-cache-top-sg* '())
(logior! (-> this skel status) (janim-status inited))
(update-transforms! (-> this root))
(init-platform! this)
(set! (-> this money) (res-lump-value (-> this entity) 'orb-cache-count int :default (the-as uint128 20)))
(set! (-> this active-distance) 61440.0)
(set! (-> this inactive-distance) 245760.0)
(set! (-> this root-pos) (-> this basetrans y))
(set! (-> this platform-pos) (-> this root-pos))
(set! (-> this activated)
(the-as symbol (and (-> this entity) (logtest? (-> this entity extra perm status) (entity-perm-status complete)))))
(let ((permanent-state (-> this entity extra perm)))
(logior! (-> permanent-state status) (entity-perm-status user-set-from-cstage))
(set! (-> this money) (- (-> this money) (-> permanent-state user-int16 0))))
(dotimes (i (-> this money))
(set! (-> this money-list i) (the-as handle #f)))
(cond
((zero? (-> this money)) (go orb-cache-top-complete #t))
((and (-> this entity) (logtest? (-> this entity extra perm status) (entity-perm-status complete)))
(go orb-cache-top-activate #t))
(else (go orb-cache-top-idle #f)))
(none))