;;-*-Lisp-*-
(in-package goal)

;; name: joint-exploder.gc
;; name in dgo: joint-exploder
;; dgos: GAME, COMMON


;; DECOMP BEGINS

(deftype joint-exploder-tuning (structure)
  ((explosion                    uint64)
   (duration                     time-frame)
   (gravity                      float)
   (rot-speed                    float)
   (bounds-inflate               float)
   (max-probe-width              float)
   (max-probe-height             float)
   (max-probe-depth              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 data 0))
   (away-from-rand-transv-xz-hi  float           :overlay-at (-> fountain-rand-transv-hi data 1))
   (away-from-rand-transv-y-lo   float           :overlay-at (-> fountain-rand-transv-hi data 2))
   (away-from-rand-transv-y-hi   float           :overlay-at (-> fountain-rand-transv-hi data 3))
   (hit-xz-reaction              float)
   (hit-y-reaction               float)
   )
  (:methods
    (new (symbol type uint) _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))
   (collide-spec  uint32)
   (art-level     symbol)
   )
  )


(deftype joint-exploder-joint (structure)
  ((next         int16)
   (prev         int16)
   (joint-index  int16)
   (mat          matrix  :inline)
   (rmat         matrix  :inline)
   (update-rmat  matrix  :inline)
   (transv       vector  :inline)
   (prev-pos     vector  :inline)
   )
  )


(deftype joint-exploder-joints (basic)
  ((num-joints  int32)
   (joint       joint-exploder-joint  :inline :dynamic)
   )
  (:methods
    (new (symbol type joint-exploder-static-params) _type_)
    )
  )


(deftype joint-exploder-list (structure)
  ((head         int32)
   (pre-moved?   symbol)
   (bbox-valid?  symbol)
   (probeless?   symbol)
   (bbox         bounding-box  :inline)
   )
  )


(deftype joint-exploder (process-drawable)
  ((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-to-list (_type_ joint-exploder-list int) int)
    (update-bbox-for-joint (_type_ joint-exploder-list joint-exploder-joint) none)
    (do-collision-response (_type_ joint-exploder-list) none)
    (init-joint-list (_type_) none)
    (remove-from-list-and-reset (_type_ joint-exploder-list int) int)
    (final-adjust (_type_ joint-exploder-list int) int)
    (integrate-and-kill (_type_ joint-exploder-list) none)
    (remove-joint-from-list (_type_ joint-exploder-list int) int)
    (adjust-bbox-for-limits-along-axis (_type_ joint-exploder-list int) joint-exploder-list)
    (adjust-bbox-for-limits (_type_ joint-exploder-list) none)
    )
  (:states
    joint-exploder-shatter
    )
  )


;; WARN: Return type mismatch uint vs int.
(defmethod asize-of ((this joint-exploder-joints))
  (the-as int (+ (-> this type size) (* 240 (-> this num-joints))))
  )

(defmethod new joint-exploder-joints ((allocation symbol) (type-to-make type) (arg0 joint-exploder-static-params))
  (let* ((gp-0 (-> arg0 joints length))
         (v0-0 (object-new allocation type-to-make (the-as int (+ (-> type-to-make size) (* 240 gp-0)))))
         )
    (set! (-> v0-0 num-joints) gp-0)
    v0-0
    )
  )

(defun joint-exploder-joint-callback ((arg0 draw-control) (arg1 cspace-array) (arg2 joint-control))
  (let ((exploder (the-as joint-exploder (-> arg0 process))))
    (let ((s3-0 (-> exploder joints)))
      (countdown (s2-0 (-> s3-0 num-joints))
        (let* ((v1-3 (-> s3-0 joint s2-0))
               (a0-5 (-> arg1 data (-> v1-3 joint-index) bone transform))
               )
          (matrix*! a0-5 (-> v1-3 rmat) (-> v1-3 mat))
          )
        )
      )
    (let ((s4-1 (-> exploder scale-vector)))
      (countdown (s3-1 (-> arg1 length))
        (let ((a2-2 (-> arg1 data s3-1 bone transform)))
          (scale-matrix! a2-2 s4-1 a2-2)
          )
        )
      )
    )
  (let ((s4-2 (new-stack-matrix0))
        (f30-0 (-> arg0 bounds w))
        )
    (matrix-4x4-inverse! s4-2 (-> arg1 data 0 bone transform))
    (set! (-> arg0 bounds w) 1.0)
    (vector-matrix*! (-> arg0 bounds) (-> arg0 bounds) s4-2)
    (set! (-> arg0 bounds w) f30-0)
    )
  0
  (none)
  )

(defmethod remove-from-list-and-reset ((this joint-exploder) (arg0 joint-exploder-list) (arg1 int))
  (let ((v0-0 (remove-joint-from-list this arg0 arg1)))
    (let* ((v1-1 (-> this joints))
           (v1-2 (-> v1-1 joint arg1))
           )
      (set! (-> v1-2 mat quad 0) (the-as uint128 0))
      (set! (-> v1-2 mat vector 1 quad) (the-as uint128 0))
      (set! (-> v1-2 mat vector 2 quad) (the-as uint128 0))
      (set! (-> v1-2 mat trans quad) (-> this root trans quad))
      )
    v0-0
    )
  )

(defmethod remove-joint-from-list ((this joint-exploder) (arg0 joint-exploder-list) (arg1 int))
  (let* ((v1-0 (-> this joints))
         (a2-1 (-> v1-0 joint arg1))
         (a0-4 (-> a2-1 prev))
         (v0-0 (-> a2-1 next))
         )
    (cond
      ((>= a0-4 0)
       (set! (-> v1-0 joint a0-4 next) v0-0)
       (if (>= v0-0 0)
           (set! (-> v1-0 joint v0-0 prev) a0-4)
           )
       )
      (else
        (set! (-> arg0 head) v0-0)
        (cond
          ((>= v0-0 0)
           (let ((v1-2 (-> v1-0 joint v0-0)))
             (set! (-> v1-2 prev) -1)
             )
           )
          (else
            (set! (-> arg0 bbox-valid?) #f)
            )
          )
        )
      )
    v0-0
    )
  )

(defmethod add-joint-to-list ((this joint-exploder) (arg0 joint-exploder-list) (arg1 int))
  (let* ((v1-0 (-> this joints))
         (a3-0 (-> v1-0 joint arg1))
         (a0-4 (-> arg0 head))
         )
    (set! (-> arg0 head) arg1)
    (set! (-> a3-0 prev) -1)
    (set! (-> a3-0 next) a0-4)
    (when (>= a0-4 0)
      (set! (-> v1-0 joint a0-4 prev) arg1)
      arg1
      )
    )
  )

(defmethod update-bbox-for-joint ((this joint-exploder) (arg0 joint-exploder-list) (arg1 joint-exploder-joint))
  (let ((a1-1 (-> arg1 mat trans)))
    (cond
      ((-> arg0 bbox-valid?)
       (add-point! (-> arg0 bbox) a1-1)
       )
      (else
        (set! (-> arg0 bbox-valid?) #t)
        (set! (-> arg0 bbox min quad) (-> a1-1 quad))
        (set! (-> arg0 bbox max quad) (-> a1-1 quad))
        )
      )
    )
  (add-point! (-> arg0 bbox) (-> arg1 prev-pos))
  (none)
  )

(defmethod adjust-bbox-for-limits-along-axis ((this joint-exploder) (arg0 joint-exploder-list) (arg1 int))
  (local-vars
    (sv-16 int)
    (sv-32 int)
    (sv-48 joint-exploder-joint)
    (sv-64 int)
    (sv-80 joint-exploder-joint)
    (sv-96 int)
    (sv-112 joint-exploder-joint)
    )
  (let ((s5-0 (the-as joint-exploder-list #f)))
    (let ((v1-0 1))
      (until (= v1-0 5)
        (let ((a0-4 (-> this lists v1-0)))
          (when (< (-> a0-4 head) 0)
            (set! s5-0 a0-4)
            (goto cfg-6)
            )
          )
        (+! v1-0 1)
        )
      )
    (label cfg-6)
    (cond
      (s5-0
        (set! (-> s5-0 pre-moved?) #t)
        (set! (-> s5-0 bbox-valid?) #f)
        )
      (else
        (set! s5-0 (the-as joint-exploder-list (-> this lists)))
        )
      )
    (set! (-> arg0 bbox-valid?) #f)
    (let ((s2-0 (-> this joints)))
      (set! sv-32 (-> arg0 head))
      (let ((s1-0 0)
            (s0-0 0)
            )
        (let ((v1-7 arg1))
          (cond
            ((zero? v1-7)
             (let ((f30-0 (* 0.5 (+ (-> arg0 bbox min x) (-> arg0 bbox max x)))))
               (while (>= sv-32 0)
                 (set! sv-48 (-> s2-0 joint sv-32))
                 (cond
                   ((>= (-> sv-48 mat trans x) f30-0)
                    (set! sv-16 (remove-joint-from-list this arg0 sv-32))
                    (add-joint-to-list this s5-0 sv-32)
                    (set! sv-32 sv-16)
                    (update-bbox-for-joint this s5-0 sv-48)
                    (+! s0-0 1)
                    )
                   (else
                     (update-bbox-for-joint this arg0 sv-48)
                     (set! sv-32 (-> sv-48 next))
                     (+! s1-0 1)
                     )
                   )
                 )
               )
             )
            ((= v1-7 1)
             (let ((f30-1 (* 0.5 (+ (-> arg0 bbox min y) (-> arg0 bbox max y)))))
               (while (>= sv-32 0)
                 (set! sv-80 (-> s2-0 joint sv-32))
                 (cond
                   ((>= (-> sv-80 mat trans y) f30-1)
                    (set! sv-64 (remove-joint-from-list this arg0 sv-32))
                    (add-joint-to-list this s5-0 sv-32)
                    (set! sv-32 sv-64)
                    (update-bbox-for-joint this s5-0 sv-80)
                    (+! s0-0 1)
                    )
                   (else
                     (update-bbox-for-joint this arg0 sv-80)
                     (set! sv-32 (-> sv-80 next))
                     (+! s1-0 1)
                     )
                   )
                 )
               )
             )
            ((= v1-7 2)
             (let ((f30-2 (* 0.5 (+ (-> arg0 bbox min z) (-> arg0 bbox max z)))))
               (while (>= sv-32 0)
                 (set! sv-112 (-> s2-0 joint sv-32))
                 (cond
                   ((>= (-> sv-112 mat trans z) f30-2)
                    (set! sv-96 (remove-joint-from-list this arg0 sv-32))
                    (add-joint-to-list this s5-0 sv-32)
                    (set! sv-32 sv-96)
                    (update-bbox-for-joint this s5-0 sv-112)
                    (+! s0-0 1)
                    )
                   (else
                     (update-bbox-for-joint this arg0 sv-112)
                     (set! sv-32 (-> sv-112 next))
                     (+! s1-0 1)
                     )
                   )
                 )
               )
             )
            )
          )
        (cond
          ((zero? s0-0)
           (final-adjust this arg0 arg1)
           )
          ((zero? s1-0)
           (if (not (-> s5-0 probeless?))
               (final-adjust this s5-0 arg1)
               )
           )
          )
        )
      )
    s5-0
    )
  )

;; WARN: Return type mismatch symbol vs int.
(defmethod final-adjust ((this joint-exploder) (arg0 joint-exploder-list) (arg1 int))
  (local-vars (sv-48 int) (sv-64 (inline-array joint-exploder-list)) (sv-80 joint-exploder-joint))
  (set! (-> arg0 bbox-valid?) #f)
  (let ((s3-0 (-> this joints))
        (s2-0 (-> arg0 head))
        )
    (while (>= s2-0 0)
      (set! sv-80 (-> s3-0 joint s2-0))
      (let ((s1-0 (new 'stack-no-clear 'bounding-box))
            (s0-0 (-> arg0 bbox-valid?))
            )
        (set! (-> s1-0 min quad) (-> arg0 bbox min quad))
        (set! (-> s1-0 max quad) (-> arg0 bbox max quad))
        (update-bbox-for-joint this arg0 sv-80)
        (let* ((v1-7 arg1)
               (v1-8 (cond
                       ((zero? v1-7)
                        (< (-> this tuning max-probe-width) (- (-> arg0 bbox max x) (-> arg0 bbox min x)))
                        )
                       ((= v1-7 1)
                        (< (-> this tuning max-probe-height) (- (-> arg0 bbox max y) (-> arg0 bbox min y)))
                        )
                       ((= v1-7 2)
                        (< (-> this tuning max-probe-depth) (- (-> arg0 bbox max z) (-> arg0 bbox min z)))
                        )
                       )
                     )
               )
          (when v1-8
            (set! sv-48 (remove-joint-from-list this arg0 s2-0))
            (set! sv-64 (-> this lists))
            (add-joint-to-list this (the-as joint-exploder-list sv-64) s2-0)
            (set! s2-0 sv-48)
            (update-bbox-for-joint this (the-as joint-exploder-list sv-64) sv-80)
            (set! (-> arg0 bbox-valid?) s0-0)
            (set! (-> arg0 bbox min quad) (-> s1-0 min quad))
            (set! (-> arg0 bbox max quad) (-> s1-0 max quad))
            )
          )
        )
      )
    )
  (the-as int #f)
  )

(defmethod adjust-bbox-for-limits ((this joint-exploder) (arg0 joint-exploder-list))
  (when (and (-> arg0 bbox-valid?) (>= (-> arg0 head) 0) (not (-> arg0 probeless?)))
    (let ((a2-0 -1))
      (cond
        ((< (-> this tuning max-probe-width) (- (-> arg0 bbox max x) (-> arg0 bbox min x)))
         (set! a2-0 0)
         )
        ((< (-> this tuning max-probe-height) (- (-> arg0 bbox max y) (-> arg0 bbox min y)))
         (set! a2-0 1)
         )
        ((< (-> this tuning max-probe-depth) (- (-> arg0 bbox max z) (-> arg0 bbox min z)))
         (set! a2-0 2)
         )
        )
      (when (>= a2-0 0)
        (let ((a1-2 (adjust-bbox-for-limits-along-axis this arg0 a2-0)))
          (if (not (-> a1-2 probeless?))
              (adjust-bbox-for-limits this a1-2)
              )
          )
        (adjust-bbox-for-limits this arg0)
        )
      )
    )
  0
  (none)
  )

(defmethod integrate-and-kill ((this joint-exploder) (arg0 joint-exploder-list))
  (set! (-> arg0 bbox-valid?) #f)
  (set! (-> arg0 pre-moved?) #t)
  (let ((s4-0 (-> this joints))
        (f30-0 (* (-> this tuning gravity) (seconds-per-frame)))
        (s3-0 (-> arg0 head))
        )
    (while (>= s3-0 0)
      (let* ((s2-0 (-> s4-0 joint s3-0))
             (s1-0 (-> s2-0 mat trans))
             )
        (set! (-> s2-0 prev-pos quad) (-> s1-0 quad))
        (+! (-> s2-0 transv y) f30-0)
        (vector-v+! s1-0 s1-0 (-> s2-0 transv))
        (matrix*! (-> s2-0 rmat) (-> s2-0 rmat) (-> s2-0 update-rmat))
        (cond
          ((or (< (-> s1-0 y) (-> this die-if-below-y))
               (< (-> this die-if-beyond-xz-dist-sqrd) (vector-vector-xz-distance s1-0 (-> this root trans)))
               )
           (set! s3-0 (remove-from-list-and-reset this arg0 s3-0))
           )
          (else
            (update-bbox-for-joint this arg0 s2-0)
            (set! s3-0 (-> s2-0 next))
            )
          )
        )
      )
    )
  0
  (none)
  )

(defmethod do-collision-response ((this joint-exploder) (arg0 joint-exploder-list))
  (let ((s5-0 (new 'stack-no-clear 'collide-query)))
    (set! (-> s5-0 collide-with) (the-as collide-spec (-> this static-params collide-spec)))
    (set! (-> s5-0 ignore-process0) this)
    (set! (-> s5-0 ignore-process1) #f)
    (set! (-> s5-0 ignore-pat) (new 'static 'pat-surface :noentity #x1 :nojak #x1 :probe #x1 :noendlessfall #x1))
    (set! (-> s5-0 action-mask) (collide-action solid))
    (mem-copy! (the-as pointer (-> s5-0 bbox)) (the-as pointer (-> arg0 bbox)) 32)
    (fill-using-bounding-box *collide-cache* s5-0)
    )
  (let ((s5-1 (-> this joints))
        (v1-6 (-> arg0 head))
        )
    (while (>= v1-6 0)
      (let ((s4-1 (-> s5-1 joint v1-6)))
        (let ((s3-0 (-> s4-1 mat trans))
              (s2-0 (new 'stack-no-clear 'collide-query))
              )
          (vector-! (-> s2-0 move-dist) s3-0 (-> s4-1 prev-pos))
          (set! (-> s2-0 start-pos quad) (-> s4-1 prev-pos quad))
          (let ((v1-11 s2-0))
            (set! (-> v1-11 radius) 40.96)
            (set! (-> v1-11 collide-with) (the-as collide-spec (-> this static-params collide-spec)))
            (set! (-> v1-11 ignore-process0) #f)
            (set! (-> v1-11 ignore-process1) #f)
            (set! (-> v1-11 ignore-pat) (new 'static 'pat-surface :noentity #x1 :nojak #x1 :probe #x1 :noendlessfall #x1))
            (set! (-> v1-11 action-mask) (collide-action solid))
            )
          (when (>= (probe-using-line-sphere *collide-cache* s2-0) 0.0)
            (set! (-> s3-0 quad) (-> s2-0 best-other-tri intersect quad))
            (let* ((v1-16 (-> s4-1 transv))
                   (f28-0 (sqrtf (+ (* (-> v1-16 x) (-> v1-16 x)) (* (-> v1-16 z) (-> v1-16 z)))))
                   )
              (vector-reflect! (-> s4-1 transv) (-> s4-1 transv) (-> s2-0 best-other-tri normal))
              (let ((f30-0 (-> s4-1 transv y)))
                (set! (-> s4-1 transv y) 0.0)
                (vector-normalize! (-> s4-1 transv) (* f28-0 (-> this tuning hit-xz-reaction)))
                (set! (-> s4-1 transv y) (* f30-0 (-> this tuning hit-y-reaction)))
                )
              )
            (+! (-> s3-0 y) (* 40.96 (-> s2-0 best-other-tri normal y)))
            (set! (-> s3-0 w) 1.0)
            (matrix-lerp! (-> s4-1 update-rmat) (-> s4-1 update-rmat) *identity-matrix* 0.5)
            )
          )
        (set! v1-6 (-> s4-1 next))
        )
      )
    )
  0
  (none)
  )

(defstate joint-exploder-shatter (joint-exploder)
  :enter (behavior ()
    (set-time! (-> self state-time))
    )
  :trans (behavior ()
    (let* ((f0-1 (the float (- (current-time) (-> self state-time))))
           (f1-1 (- 1.0 (/ f0-1 (the float (-> self tuning duration)))))
           (f0-3 (- 1.0 (/ f0-1 (* 0.75 (the float (-> self tuning duration))))))
           )
      (if (< f0-3 0.0)
          (set! f0-3 0.0)
          )
      (set-vector! (-> self scale-vector) f1-1 f0-3 f1-1 1.0)
      )
    (dotimes (v1-11 5)
      (set! (-> self lists v1-11 pre-moved?) #f)
      )
    (dotimes (gp-0 5)
      (let ((s5-0 (-> self lists gp-0)))
        (when (>= (-> s5-0 head) 0)
          (when (not (-> s5-0 pre-moved?))
            (integrate-and-kill self s5-0)
            (if (nonzero? gp-0)
                (adjust-bbox-for-limits self s5-0)
                )
            )
          )
        )
      )
    (let ((gp-1 (new 'stack-no-clear 'bounding-box)))
      (let ((v1-29 (-> self root trans)))
        (set! (-> gp-1 min quad) (-> v1-29 quad))
        (set! (-> gp-1 max quad) (-> v1-29 quad))
        )
      (dotimes (s5-1 5)
        (let ((s4-0 (-> self lists s5-1)))
          (if (-> s4-0 bbox-valid?)
              (add-box! gp-1 (-> s4-0 bbox))
              )
          (if (nonzero? s5-1)
              (do-collision-response self s4-0)
              )
          )
        )
      (let ((s5-2 (-> self draw bounds)))
        (vector-average! s5-2 (-> gp-1 min) (-> gp-1 max))
        (set! (-> s5-2 w) (+ (vector-vector-distance s5-2 (-> gp-1 max)) (-> self tuning bounds-inflate)))
        )
      )
    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-joint-list ((this joint-exploder))
  (let ((gp-0 (-> this joints)))
    (dotimes (s4-0 (-> gp-0 num-joints))
      (let ((v1-2 (-> this static-params joints s4-0))
            (s3-0 (-> gp-0 joint s4-0))
            )
        (let ((a0-6 (-> v1-2 parent-joint-index)))
          (set! (-> s3-0 prev) (+ s4-0 -1))
          (set! (-> s3-0 next) (+ s4-0 1))
          (set! (-> s3-0 joint-index) (-> v1-2 joint-index))
          (cond
            ((>= a0-6 0)
             (if (zero? a0-6)
                 (set! a0-6 (-> v1-2 joint-index))
                 )
             (let* ((a3-0 (-> (the-as process-drawable (-> this parent 0)) node-list data a0-6 bone transform))
                    (a2-0 (-> s3-0 mat))
                    (v1-9 (-> a3-0 quad 0))
                    (a0-8 (-> a3-0 quad 1))
                    (a1-4 (-> a3-0 quad 2))
                    (a3-1 (-> a3-0 trans quad))
                    )
               (set! (-> a2-0 quad 0) v1-9)
               (set! (-> a2-0 quad 1) a0-8)
               (set! (-> a2-0 quad 2) a1-4)
               (set! (-> a2-0 trans quad) a3-1)
               )
             (matrix-identity! (-> s3-0 rmat))
             )
            (else
              (let* ((a3-2 (-> this node-list data (-> v1-2 joint-index) bone transform))
                     (a2-1 (-> s3-0 mat))
                     (v1-15 (-> a3-2 quad 0))
                     (a0-11 (-> a3-2 quad 1))
                     (a1-5 (-> a3-2 quad 2))
                     (a3-3 (-> a3-2 trans quad))
                     )
                (set! (-> a2-1 quad 0) v1-15)
                (set! (-> a2-1 quad 1) a0-11)
                (set! (-> a2-1 quad 2) a1-5)
                (set! (-> a2-1 trans quad) a3-3)
                )
              (matrix-identity! (-> s3-0 rmat))
              )
            )
          )
        (case (-> this tuning explosion)
          ((1)
           (vector-! (-> s3-0 transv) (-> s3-0 mat trans) (-> this tuning fountain-rand-transv-lo))
           (vector-normalize!
             (-> s3-0 transv)
             (rand-vu-float-range (-> this tuning fountain-rand-transv-hi x) (-> this tuning fountain-rand-transv-hi y))
             )
           (+! (-> s3-0 transv y)
               (rand-vu-float-range (-> this tuning fountain-rand-transv-hi z) (-> this tuning fountain-rand-transv-hi w))
               )
           (set! (-> s3-0 transv w) 1.0)
           )
          (else
            (let ((s0-0 (-> this tuning fountain-rand-transv-lo))
                  (s1-1 (-> this tuning fountain-rand-transv-hi))
                  )
              (set-vector!
                (-> s3-0 transv)
                (rand-vu-float-range (-> s0-0 x) (-> s1-1 x))
                (rand-vu-float-range (-> s0-0 y) (-> s1-1 y))
                (rand-vu-float-range (-> s0-0 z) (-> s1-1 z))
                1.0
                )
              )
            )
          )
        (let* ((v1-21 (vector-normalize-copy! (new 'stack-no-clear 'vector) (-> s3-0 transv) 1.0))
               (s2-4 (vector-cross! (new 'stack-no-clear 'vector) v1-21 *up-vector*))
               (s1-2 (new 'stack-no-clear 'quaternion))
               )
          (vector-normalize! s2-4 1.0)
          (quaternion-vector-angle! s1-2 s2-4 (* 182.04445 (-> this tuning rot-speed)))
          (quaternion->matrix (-> s3-0 update-rmat) s1-2)
          )
        )
      )
    (when (nonzero? (-> gp-0 num-joints))
      (let ((v1-32 (-> gp-0 joint (+ (-> gp-0 num-joints) -1))))
        (set! (-> v1-32 next) -1)
        )
      (let ((v1-33 (-> this lists 1)))
        (set! (-> v1-33 head) 0)
        (let ((s5-1 (-> v1-33 bbox)))
          (let ((v1-34 (-> gp-0 joint 0 mat trans)))
            (set! (-> s5-1 min quad) (-> v1-34 quad))
            (set! (-> s5-1 max quad) (-> v1-34 quad))
            )
          (dotimes (s4-1 (-> gp-0 num-joints))
            (add-point! s5-1 (the-as vector (+ (the-as uint (-> gp-0 joint 0 mat trans)) (* 240 s4-1))))
            )
          )
        )
      )
    )
  0
  (none)
  )

;; WARN: Return type mismatch process-drawable vs joint-exploder.
(defmethod relocate ((this joint-exploder) (arg0 int))
  (if (nonzero? (-> this joints))
      (&+! (-> this joints) arg0)
      )
  (the-as joint-exploder ((method-of-type process-drawable relocate) this arg0))
  )

;; WARN: Return type mismatch object vs none.
(defbehavior joint-exploder-init-by-other joint-exploder ((arg0 skeleton-group) (arg1 int) (arg2 joint-exploder-tuning) (arg3 joint-exploder-static-params))
  (set! (-> self static-params) arg3)
  (set! (-> self die-if-beyond-xz-dist-sqrd) 10485760000.0)
  (mem-copy! (the-as pointer (-> self tuning)) (the-as pointer arg2) 88)
  (set! (-> self joints) (new 'process 'joint-exploder-joints arg3))
  (dotimes (v1-2 5)
    (let ((a0-6 (-> self lists v1-2)))
      (set! (-> a0-6 head) -1)
      (set! (-> a0-6 bbox-valid?) #f)
      (set! (-> a0-6 pre-moved?) #f)
      (set! (-> a0-6 probeless?) #f)
      )
    )
  (let ((v1-5 (-> self lists)))
    (set! (-> v1-5 0 probeless?) #t)
    )
  (set! (-> self root) (new 'process 'trsqv))
  (set! (-> self root trans quad) (-> (the-as process-drawable (-> self parent 0)) root trans quad))
  (quaternion-copy! (-> self root quat) (-> (the-as process-drawable (-> self parent 0)) root quat))
  (set! (-> self root scale quad) (-> (the-as process-drawable (-> self parent 0)) root scale quad))
  (when (-> arg3 art-level)
    (let ((a1-6 (entity-actor-from-level-name (-> arg3 art-level))))
      (if a1-6
          (process-entity-set! self a1-6)
          )
      )
    )
  (initialize-skeleton self arg0 (the-as pair 0))
  (logior! (-> self skel status) (joint-control-status sync-math))
  (set! (-> self anim) (the-as art-joint-anim (-> self draw art-group data arg1)))
  (ja-channel-set! 1)
  (ja :group! (-> self anim) :num! min)
  (ja-post)
  (init-joint-list 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)
  )

;; WARN: Return type mismatch structure vs joint-exploder-tuning.
(defmethod new joint-exploder-tuning ((allocation symbol) (type-to-make type) (arg0 uint))
  (let ((t9-0 (method-of-type structure new))
        (v1-1 type-to-make)
        )
    (-> type-to-make size)
    (let ((v0-0 (the-as joint-exploder-tuning (t9-0 allocation v1-1))))
      (set! (-> v0-0 explosion) arg0)
      (set! (-> v0-0 duration) (seconds 2))
      (set! (-> v0-0 gravity) -286720.0)
      (set! (-> v0-0 rot-speed) 8.4)
      (set! (-> v0-0 bounds-inflate) 16384.0)
      (set! (-> v0-0 max-probe-width) 20480.0)
      (set! (-> v0-0 max-probe-height) 24576.0)
      (set! (-> v0-0 max-probe-depth) 20480.0)
      (set! (-> v0-0 hit-xz-reaction) 0.75)
      (set! (-> v0-0 hit-y-reaction) 0.7)
      (cond
        ((zero? arg0)
         (set-vector! (-> v0-0 fountain-rand-transv-lo) -81920.0 20480.0 -81920.0 1.0)
         (set-vector! (-> v0-0 fountain-rand-transv-hi) 81920.0 61440.0 81920.0 1.0)
         )
        ((= arg0 1)
         (vector-reset! (-> v0-0 fountain-rand-transv-lo))
         (set! (-> v0-0 fountain-rand-transv-hi x) 49152.0)
         (set! (-> v0-0 fountain-rand-transv-hi y) 163840.0)
         (set! (-> v0-0 fountain-rand-transv-hi z) 20480.0)
         (set! (-> v0-0 fountain-rand-transv-hi w) 61440.0)
         )
        )
      (the-as joint-exploder-tuning v0-0)
      )
    )
  )
