Files
jak-project/goal_src/jak1/engine/anim/joint-exploder.gc
T
2026-07-26 14:43:53 -04:00

506 lines
26 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
(bundles "GAME.CGO")
(require "engine/collide/collide-cache.gc")
(require "engine/common-obs/process-drawable.gc")
;; DECOMP BEGINS
;; Each selected skeleton joint becomes an independently moving fragment. The tuning storage is
;; overlaid because fountain launches use component-wise velocity ranges, while radial launches use
;; the same 32 bytes as a focal point plus horizontal and vertical speed ranges.
(deftype joint-exploder-tuning (structure)
((explosion uint64)
(duration time-frame)
(gravity float)
(rot-speed float)
(fountain-rand-transv-lo vector :inline)
(fountain-rand-transv-hi vector :inline)
(away-from-focal-pt vector :inline :overlay-at fountain-rand-transv-lo)
(away-from-rand-transv-xz-lo float :overlay-at (-> fountain-rand-transv-hi x))
(away-from-rand-transv-xz-hi float :overlay-at (-> fountain-rand-transv-hi y))
(away-from-rand-transv-y-lo float :overlay-at (-> fountain-rand-transv-hi z))
(away-from-rand-transv-y-hi float :overlay-at (-> fountain-rand-transv-hi w)))
(:methods
(new (symbol type int) _type_)))
(deftype joint-exploder-static-joint-params (structure)
((joint-index int16)
(parent-joint-index int16)))
(deftype joint-exploder-static-params (basic)
((joints (array joint-exploder-static-joint-params))))
(deftype joint-exploder-joint (structure)
((next int16)
(prev int16)
(joint-index int16)
(rspeed float)
(mat matrix :inline)
(rmat matrix :inline)
(transv vector :inline)
(prev-pos vector :inline)))
(deftype joint-exploder-joints (basic)
((num-joints int32)
(joint joint-exploder-joint :inline :dynamic :offset 16))
(:methods
(new (symbol type joint-exploder-static-params) _type_)))
(deftype joint-exploder-list (structure)
((head int32)
(pre-moved? symbol)
(bbox-valid? symbol)
(bbox bounding-box :inline)))
;; Lists 1 through 4 are spatial buckets for background collision. List 1 starts with every
;; fragment, and oversized bounds split at their midpoint into any empty bucket in that range.
;; When all four are occupied, the upper half spills into list 0: it still moves, draws, and
;; contributes to the overall bounds, but it is not subdivided or tested against the background.
(deftype joint-exploder (process-drawable)
((parent-override (pointer process-drawable) :overlay-at parent)
(die-if-below-y float)
(die-if-beyond-xz-dist-sqrd float)
(joints joint-exploder-joints)
(static-params joint-exploder-static-params)
(anim art-joint-anim)
(scale-vector vector :inline)
(tuning joint-exploder-tuning :inline)
(lists joint-exploder-list 5 :inline))
(:methods
(add-joint! (_type_ joint-exploder-list int) int)
(grow-bbox! (_type_ joint-exploder-list joint-exploder-joint) none)
(collide-joints! (_type_ joint-exploder-list) symbol)
(init-joints! (_type_) symbol)
(kill-joint! (_type_ joint-exploder-list int) int)
(integrate-joints! (_type_ joint-exploder-list) symbol)
(remove-joint! (_type_ joint-exploder-list int) int)
(split-list! (_type_ joint-exploder-list int) joint-exploder-list)
(subdivide-list! (_type_ joint-exploder-list) none))
(:states
joint-exploder-shatter))
(defmethod asize-of ((this joint-exploder-joints))
"Return the dynamic allocation size: the sixteen-byte header plus 176 bytes per joint."
(the-as int (+ (-> this type size) (* 176 (-> this num-joints)))))
(defmethod new joint-exploder-joints ((allocation symbol) (type-to-make type) (static-params joint-exploder-static-params))
"Allocate the dynamic joint array sized from static-params."
(let* ((joint-count (-> static-params joints length))
(result (object-new allocation type-to-make (the-as int (+ (-> type-to-make size) (* 176 joint-count))))))
(set! (-> result num-joints) joint-count)
result))
(defun joint-exploder-joint-callback ((exploder joint-exploder))
"Compose each fragment's spin and simulated base transform into its skeleton joint, then apply
the current disappearance scale to every skeleton transform."
(let* ((skeleton-nodes (-> exploder node-list))
(joint-array (-> exploder joints))
(i (-> joint-array num-joints)))
(while (nonzero? i)
(+! i -1)
(let* ((joint-data (-> joint-array joint i))
(bone-transform (-> skeleton-nodes data (-> joint-data joint-index) bone transform)))
(matrix*! bone-transform (-> joint-data rmat) (-> joint-data mat))))
(let ((exploder-scale (-> exploder scale-vector)))
(set! i (-> skeleton-nodes length))
(while (nonzero? i)
(+! i -1)
(let ((scaled-transform (-> skeleton-nodes data i bone transform)))
(scale-matrix! scaled-transform exploder-scale scaled-transform)))))
0
(none))
(defmethod kill-joint! ((this joint-exploder) (joint-list joint-exploder-list) (joint-index int))
"Remove joint-index from joint-list, zero its transform basis, and place it at the exploder
root so its fragment collapses out of view. Return the following list index."
(let ((next-index (remove-joint! this joint-list joint-index)))
(let* ((joint-array (-> this joints))
(joint-data (-> joint-array joint joint-index)))
(set! (-> joint-data mat vector 0 quad) (the-as uint128 0))
(set! (-> joint-data mat vector 1 quad) (the-as uint128 0))
(set! (-> joint-data mat vector 2 quad) (the-as uint128 0))
(set! (-> joint-data mat vector 3 quad) (-> this root trans quad)))
next-index))
(defmethod remove-joint! ((this joint-exploder) (joint-list joint-exploder-list) (joint-index int))
"Unlink joint-index from joint-list's doubly linked index chain and return its former next
index. Invalidate the bounds when the list becomes empty."
(let* ((joint-array (-> this joints))
(joint-data (-> joint-array joint joint-index))
(previous-index (-> joint-data prev))
(next-index (-> joint-data next)))
(cond
((>= previous-index 0)
(set! (-> joint-array joint previous-index next) next-index)
(if (>= next-index 0) (set! (-> (the-as joint-exploder-joint (-> joint-array joint next-index)) prev) previous-index)))
(else
(set! (-> joint-list head) next-index)
(cond
((>= next-index 0) (let ((next-joint-data (-> joint-array joint next-index))) (set! (-> next-joint-data prev) -1)))
(else (set! (-> joint-list bbox-valid?) #f)))))
next-index))
(defmethod add-joint! ((this joint-exploder) (joint-list joint-exploder-list) (joint-index int))
"Insert joint-index at the head of joint-list's doubly linked index chain."
(let* ((joint-array (-> this joints))
(joint-data (-> joint-array joint joint-index))
(old-head-index (-> joint-list head)))
(set! (-> joint-list head) joint-index)
(set! (-> joint-data prev) -1)
(set! (-> joint-data next) old-head-index)
(when (>= old-head-index 0)
(set! (-> (the-as joint-exploder-joint (-> joint-array joint old-head-index)) prev) joint-index)
joint-index)))
(defmethod grow-bbox! ((this joint-exploder) (joint-list joint-exploder-list) (joint-data joint-exploder-joint))
"Expand joint-list's bounds to include joint-data's current and previous positions, so the
box encloses its complete swept segment for this frame."
(let ((joint-position (-> joint-data mat vector 3)))
(cond
((-> joint-list bbox-valid?) (add-point! (-> joint-list bbox) (the-as vector3s joint-position)))
(else
(set! (-> joint-list bbox-valid?) #t)
(set! (-> joint-list bbox min quad) (-> joint-position quad))
(set! (-> joint-list bbox max quad) (-> joint-position quad)))))
(add-point! (-> joint-list bbox) (the-as vector3s (-> joint-data prev-pos)))
(none))
(defmethod split-list! ((this joint-exploder) (joint-list joint-exploder-list) (split-axis int))
"Try to acquire an empty collision bucket from lists 1 through 4, split joint-list at its
bounding-box midpoint on axis, and move members on the upper side into that bucket. When all
four are occupied, spill into non-colliding list 0 and return false to stop recursion."
(local-vars (current-joint joint-exploder-joint) (split-position float) (next-index int))
(let ((available-list (the-as joint-exploder-list #f)))
(let ((list-index 1))
(until (= list-index 5)
(let ((candidate-list (-> this lists list-index)))
(when (< (-> candidate-list head) 0)
(set! available-list candidate-list)
(goto cfg-6)))
(+! list-index 1)))
(label cfg-6)
(let ((destination-list (the-as object available-list)))
(cond
((the-as joint-exploder-list destination-list)
(set! (-> (the-as joint-exploder-list destination-list) pre-moved?) #t)
(set! (-> (the-as joint-exploder-list destination-list) bbox-valid?) #f))
(else (set! destination-list (-> this lists))))
(set! (-> joint-list bbox-valid?) #f)
(let ((joint-array (-> this joints))
(current-index (-> joint-list head)))
(cond
((zero? split-axis)
(set! split-position (* 0.5 (+ (-> joint-list bbox min x) (-> joint-list bbox max x))))
(while (>= current-index 0)
(set! current-joint (-> joint-array joint current-index))
(cond
((>= (-> current-joint mat vector 3 x) split-position)
(set! next-index (remove-joint! this joint-list current-index))
(add-joint! this (the-as joint-exploder-list destination-list) current-index)
(set! current-index next-index)
(grow-bbox! this (the-as joint-exploder-list destination-list) current-joint))
(else (grow-bbox! this joint-list current-joint) (set! current-index (-> current-joint next))))))
((= split-axis 1)
(set! split-position (* 0.5 (+ (-> joint-list bbox min y) (-> joint-list bbox max y))))
(while (>= current-index 0)
(set! current-joint (-> joint-array joint current-index))
(cond
((>= (-> current-joint mat vector 3 y) split-position)
(set! next-index (remove-joint! this joint-list current-index))
(add-joint! this (the-as joint-exploder-list destination-list) current-index)
(set! current-index next-index)
(grow-bbox! this (the-as joint-exploder-list destination-list) current-joint))
(else (grow-bbox! this joint-list current-joint) (set! current-index (-> current-joint next))))))
((= split-axis 2)
(set! split-position (* 0.5 (+ (-> joint-list bbox min z) (-> joint-list bbox max z))))
(while (>= current-index 0)
(set! current-joint (-> joint-array joint current-index))
(cond
((>= (-> current-joint mat vector 3 z) split-position)
(set! next-index (remove-joint! this joint-list current-index))
(add-joint! this (the-as joint-exploder-list destination-list) current-index)
(set! current-index next-index)
(grow-bbox! this (the-as joint-exploder-list destination-list) current-joint))
(else (grow-bbox! this joint-list current-joint) (set! current-index (-> current-joint next)))))))))
available-list))
(defmethod subdivide-list! ((this joint-exploder) (joint-list joint-exploder-list))
"Recursively split valid nonempty lists whose X, Y, or Z extent exceeds five metres,
prioritizing axes in that order. The small boxes limit the background collision-cache work."
(when (and (-> joint-list bbox-valid?) (>= (-> joint-list head) 0))
(cond
((< 20480.0 (- (-> joint-list bbox max x) (-> joint-list bbox min x)))
(let ((x-split-list (split-list! this joint-list 0))) (if x-split-list (subdivide-list! this x-split-list)))
(subdivide-list! this joint-list))
((< 20480.0 (- (-> joint-list bbox max y) (-> joint-list bbox min y)))
(let ((y-split-list (split-list! this joint-list 1))) (if y-split-list (subdivide-list! this y-split-list)))
(subdivide-list! this joint-list))
((< 20480.0 (- (-> joint-list bbox max z) (-> joint-list bbox min z)))
(let ((z-split-list (split-list! this joint-list 2))) (if z-split-list (subdivide-list! this z-split-list)))
(subdivide-list! this joint-list))))
(none))
(defmethod integrate-joints! ((this joint-exploder) (joint-list joint-exploder-list))
"Advance every member of joint-list by one frame of gravity, linear velocity, and local-Z
spin. Kill fragments outside the vertical or radial limits and rebuild swept bounds for the
survivors."
(set! (-> joint-list bbox-valid?) #f)
(set! (-> joint-list pre-moved?) #t)
(let ((joint-array (-> this joints))
(gravity-step (* (-> this tuning gravity) (seconds-per-frame)))
(current-index (-> joint-list head)))
(while (>= current-index 0)
(let* ((joint-data (-> joint-array joint current-index))
(position (-> joint-data mat vector 3)))
(set! (-> joint-data prev-pos quad) (-> position quad))
(+! (-> joint-data transv y) gravity-step)
(vector-v+! position position (-> joint-data transv))
(let ((cos-step 0.99)
(sin-step (* (-> joint-data rspeed) (seconds-per-frame)))
(r00 (-> joint-data rmat vector 0 x))
(r01 (-> joint-data rmat vector 0 y))
(r10 (-> joint-data rmat vector 1 x))
(r11 (-> joint-data rmat vector 1 y)))
(set! (-> joint-data rmat vector 0 x) (- (* r00 cos-step) (* r01 sin-step)))
(set! (-> joint-data rmat vector 0 y) (+ (* r00 sin-step) (* r01 cos-step)))
(set! (-> joint-data rmat vector 1 x) (- (* r10 cos-step) (* r11 sin-step)))
(set! (-> joint-data rmat vector 1 y) (+ (* r10 sin-step) (* r11 cos-step))))
(cond
((or (< (-> position y) (-> this die-if-below-y))
(< (-> this die-if-beyond-xz-dist-sqrd) (vector-vector-xz-distance position (-> this root trans))))
(set! current-index (kill-joint! this joint-list current-index)))
(else (grow-bbox! this joint-list joint-data) (set! current-index (-> joint-data next)))))))
#f)
(defmethod collide-joints! ((this joint-exploder) (joint-list joint-exploder-list))
"Fill the shared background collision cache for joint-list, sweep a 0.01-metre sphere along
each joint's frame motion, and bounce hits with 75 percent horizontal and 70 percent
vertical speed retention while halving spin."
(fill-using-bounding-box *collide-cache*
(-> joint-list bbox)
(collide-kind background)
this
(new 'static 'pat-surface :noentity #x1))
(let ((joint-array (-> this joints))
(current-index (-> joint-list head)))
(while (>= current-index 0)
(let ((joint-data (-> joint-array joint current-index)))
(let ((position (-> joint-data mat vector 3))
(frame-motion (new 'stack-no-clear 'vector))
(probe-result (new 'stack-no-clear 'collide-tri-result)))
(vector-! frame-motion position (-> joint-data prev-pos))
(when (>= (probe-using-line-sphere *collide-cache*
(-> joint-data prev-pos)
frame-motion
40.96
(collide-kind background)
probe-result
(new 'static 'pat-surface :noentity #x1))
0.0)
(set! (-> position quad) (-> probe-result intersect quad))
(let ((horizontal-speed (vector-xz-length (-> joint-data transv))))
(vector-reflect! (-> joint-data transv) (-> joint-data transv) (-> probe-result normal))
(let ((vertical-speed (-> joint-data transv y)))
(set! (-> joint-data transv y) 0.0)
(vector-normalize! (-> joint-data transv) (* 0.75 horizontal-speed))
(set! (-> joint-data transv y) (* 0.7 vertical-speed))))
(+! (-> position y) (* 40.96 (-> probe-result normal y)))
(set! (-> position w) 1.0)
(set! (-> joint-data rspeed) (/ (-> joint-data rspeed) 2))))
(set! current-index (-> joint-data next)))))
#f)
(defstate joint-exploder-shatter (joint-exploder)
:enter
(behavior ()
(set-time! (-> self state-time)))
:trans
(behavior ()
;; Shrink Y to zero after three quarters of the lifetime, then finish collapsing X/Z. Lists
;; are marked as they move because subdivision can transfer joints into a later list.
(local-vars (joint-list joint-exploder-list))
(let* ((elapsed-frames (the float (- (current-time) (-> self state-time))))
(horizontal-scale (- 1.0 (/ elapsed-frames (the float (-> self tuning duration)))))
(vertical-scale (- 1.0 (/ elapsed-frames (* 0.75 (the float (-> self tuning duration)))))))
(if (< vertical-scale 0.0) (set! vertical-scale 0.0))
(set-vector! (-> self scale-vector) horizontal-scale vertical-scale horizontal-scale 1.0))
(let ((i 0))
(while (< i 5)
(set! (-> self lists i pre-moved?) #f)
(+! i 1))
(set! i 0)
(while (< i 5)
(set! joint-list (-> self lists i))
(when (>= (-> joint-list head) 0)
(when (not (-> joint-list pre-moved?))
(integrate-joints! self joint-list)
(if (nonzero? i) (subdivide-list! self joint-list))))
(+! i 1))
(let ((combined-bounds (new 'stack-no-clear 'bounding-box)))
(let ((root-position (-> self root trans)))
(set! (-> combined-bounds min quad) (-> root-position quad))
(set! (-> combined-bounds max quad) (-> root-position quad)))
(set! i 0)
(while (< i 5)
(set! joint-list (-> self lists i))
(if (-> joint-list bbox-valid?) (add-box! combined-bounds (-> joint-list bbox)))
(if (nonzero? i) (collide-joints! self joint-list))
(+! i 1))
(let ((draw-bounds (-> self draw bounds)))
(set-vector! draw-bounds
(* 0.5 (+ (-> combined-bounds min x) (-> combined-bounds max x)))
(* 0.5 (+ (-> combined-bounds min y) (-> combined-bounds max y)))
(* 0.5 (+ (-> combined-bounds min z) (-> combined-bounds max z)))
1.0)
(let ((bound-radius (+ 16384.0 (vector-vector-distance draw-bounds (-> combined-bounds max)))))
(vector-! draw-bounds draw-bounds (-> self root trans))
(set! (-> draw-bounds w) bound-radius)))))
0)
:code
(behavior ()
(set-time! (-> self state-time))
(until (time-elapsed? (-> self state-time) (-> self tuning duration))
(suspend)
(ja :num! (loop!))))
:post ja-post)
(defmethod init-joints! ((this joint-exploder))
"Build each fragment's base transform, spin matrix, linked-list indices, and launch velocity
from the static joint table and selected explosion style, then seed the main list and bounds."
(local-vars
(basis-x uint128)
(basis-y uint128)
(basis-z uint128)
(fragment-matrix matrix)
(source-matrix matrix)
(translation uint128))
(let ((joint-array (-> this joints))
(i 0))
(while (< i (-> joint-array num-joints))
(let ((static-joint (-> this static-params joints i))
(joint-data (-> joint-array joint i)))
(let ((parent-index (-> static-joint parent-joint-index)))
(set! (-> joint-data prev) (+ i -1))
(set! (-> joint-data next) (+ i 1))
(set! (-> joint-data joint-index) (-> static-joint joint-index))
(set! (-> joint-data rspeed) (-> this tuning rot-speed))
(cond
((>= parent-index 0)
(if (zero? parent-index) (set! parent-index (-> static-joint joint-index)))
(set! source-matrix (-> this parent-override 0 node-list data parent-index bone transform))
(set! fragment-matrix (-> joint-data mat))
(set! basis-x (-> source-matrix vector 0 quad))
(set! basis-y (-> source-matrix vector 1 quad))
(set! basis-z (-> source-matrix vector 2 quad))
(set! translation (-> source-matrix vector 3 quad))
(set! (-> fragment-matrix vector 0 quad) basis-x)
(set! (-> fragment-matrix vector 1 quad) basis-y)
(set! (-> fragment-matrix vector 2 quad) basis-z)
(set! (-> fragment-matrix vector 3 quad) translation)
(matrix-identity! (-> joint-data rmat)))
(else
(set! source-matrix (-> this node-list data (-> static-joint joint-index) bone transform))
(set! fragment-matrix (-> joint-data mat))
(set! basis-x (-> source-matrix vector 0 quad))
(set! basis-y (-> source-matrix vector 1 quad))
(set! basis-z (-> source-matrix vector 2 quad))
(set! translation (-> source-matrix vector 3 quad))
(set! (-> fragment-matrix vector 0 quad) basis-x)
(set! (-> fragment-matrix vector 1 quad) basis-y)
(set! (-> fragment-matrix vector 2 quad) basis-z)
(set! (-> fragment-matrix vector 3 quad) translation)
(matrix-identity! (-> joint-data rmat)))))
(case (-> this tuning explosion)
((1)
(vector-! (-> joint-data transv) (-> joint-data mat vector 3) (-> this tuning fountain-rand-transv-lo))
(vector-normalize! (-> joint-data transv)
(rand-vu-float-range (-> this tuning fountain-rand-transv-hi x) (-> this tuning fountain-rand-transv-hi y)))
(+! (-> joint-data transv y)
(rand-vu-float-range (-> this tuning fountain-rand-transv-hi z) (-> this tuning fountain-rand-transv-hi w)))
(set! (-> joint-data transv w) 1.0))
(else
(let ((velocity-low (-> this tuning fountain-rand-transv-lo))
(velocity-high (-> this tuning fountain-rand-transv-hi)))
(set-vector! (-> joint-data transv)
(rand-vu-float-range (-> velocity-low x) (-> velocity-high x))
(rand-vu-float-range (-> velocity-low y) (-> velocity-high y))
(rand-vu-float-range (-> velocity-low z) (-> velocity-high z))
1.0)))))
(+! i 1))
(when (nonzero? (-> joint-array num-joints))
(let ((last-joint (-> joint-array joint (+ (-> joint-array num-joints) -1)))) (set! (-> last-joint next) -1))
(let ((main-list (-> this lists 1)))
(set! (-> main-list head) 0)
(let ((main-bounds (-> main-list bbox)))
(let ((first-position (-> joint-array joint 0 mat vector 3)))
(set! (-> main-bounds min quad) (-> first-position quad))
(set! (-> main-bounds max quad) (-> first-position quad)))
(set! i 0)
(while (< i (-> joint-array num-joints))
(add-point! main-bounds (the-as vector3s (-> joint-array joint i mat vector 3)))
(+! i 1))))
#f)))
(defmethod relocate ((this joint-exploder) (offset int))
"Relocate the separately allocated dynamic joint array, then relocate the drawable."
(if (nonzero? (-> this joints)) (&+! (-> this joints) offset))
(the-as joint-exploder ((method-of-type process-drawable relocate) this offset)))
(defbehavior joint-exploder-init-by-other joint-exploder ((exploder-sg skeleton-group)
(animation-index int)
(tuning joint-exploder-tuning)
(static-params joint-exploder-static-params))
"Spawn fragments from parent using exploder-sg and animation-index. Copy tuning, allocate the
static joint selection, inherit the parent's root transform, pose the animation, initialize the
fragments, install the post-bind callback, and enter the shatter state."
(set! (-> self static-params) static-params)
(set! (-> self die-if-beyond-xz-dist-sqrd) 10485760000.0)
(mem-copy! (the-as pointer (-> self tuning)) (the-as pointer tuning) 64)
(set! (-> self joints) (new 'process 'joint-exploder-joints static-params))
(dotimes (i 5)
(let ((joint-list (-> self lists i)))
(set! (-> joint-list head) -1)
(set! (-> joint-list bbox-valid?) #f)
(set! (-> joint-list pre-moved?) #f)))
(logior! (-> self mask) (process-mask enemy))
(set! (-> self root) (new 'process 'trsqv))
(set! (-> self root trans quad) (-> self parent-override 0 root trans quad))
(quaternion-copy! (-> self root quat) (-> self parent-override 0 root quat))
(set! (-> self root scale quad) (-> self parent-override 0 root scale quad))
(initialize-skeleton self exploder-sg '())
(logior! (-> self skel status) (janim-status inited))
(set! (-> self anim) (the-as art-joint-anim (-> self draw art-group data animation-index)))
(ja-channel-set! 1)
(ja :group! (-> self anim) :num! min)
(ja-post)
(init-joints! self)
(set! (-> self die-if-below-y) (+ -102400.0 (-> self root trans y)))
(set! (-> self skel postbind-function) joint-exploder-joint-callback)
(go joint-exploder-shatter)
(none))
(defmethod new joint-exploder-tuning ((allocation symbol) (type-to-make type) (explosion-style int))
"Allocate default tuning for explosion-style. Style 0 uses component-wise random fountain
velocity; style 1 launches away from a focal point with randomized horizontal and vertical
speeds."
(let ((parent-new (method-of-type structure new))
(requested-type type-to-make))
(-> type-to-make size)
(let ((result (the-as joint-exploder-tuning (parent-new allocation requested-type))))
(set! (-> result explosion) (the-as uint explosion-style))
(set! (-> result duration) (seconds 2))
(set! (-> result gravity) -286720.0)
(set! (-> result rot-speed) 8.4)
(cond
((zero? explosion-style)
(set-vector! (-> result fountain-rand-transv-lo) -81920.0 20480.0 -81920.0 1.0)
(set-vector! (-> result fountain-rand-transv-hi) 81920.0 61440.0 81920.0 1.0))
((= explosion-style 1)
(vector-reset! (-> result fountain-rand-transv-lo))
(set! (-> result fountain-rand-transv-hi x) 49152.0)
(set! (-> result fountain-rand-transv-hi y) 163840.0)
(set! (-> result fountain-rand-transv-hi z) 20480.0)
(set! (-> result fountain-rand-transv-hi w) 61440.0)))
result)))