;;-*-Lisp-*-
(in-package goal)
(bundles "GAME.CGO")
(require "engine/collide/collide-cache.gc")
(require "engine/common-obs/process-drawable.gc")

;; DECOMP BEGINS

(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)))


(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
   (joint-exploder-method-20 (_type_ joint-exploder-list int) int)
   (joint-exploder-method-21 (_type_ joint-exploder-list joint-exploder-joint) none)
   (joint-exploder-method-22 (_type_ joint-exploder-list) symbol)
   (joint-exploder-method-23 (_type_) symbol)
   (joint-exploder-method-24 (_type_ joint-exploder-list int) int)
   (joint-exploder-method-25 (_type_ joint-exploder-list) symbol)
   (joint-exploder-method-26 (_type_ joint-exploder-list int) int)
   (joint-exploder-method-27 (_type_ joint-exploder-list int) joint-exploder-list)
   (joint-exploder-method-28 (_type_ joint-exploder-list) none))
  (:states
   joint-exploder-shatter))


(defmethod asize-of ((this joint-exploder-joints))
  (the-as int (+ (-> this type size) (* 176 (-> 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) (* 176 gp-0))))))
    (set! (-> v0-0 num-joints) gp-0)
    v0-0))

(defun joint-exploder-joint-callback ((arg0 joint-exploder))
  (let ((gp-0 (-> arg0 node-list)))
    (let ((s4-0 (-> arg0 joints)))
      (countdown (s3-0 (-> s4-0 num-joints))
        (let* ((v1-3 (-> s4-0 joint s3-0))
               (a0-5 (-> gp-0 data (-> v1-3 joint-index) bone transform)))
          (matrix*! a0-5 (-> v1-3 rmat) (-> v1-3 mat)))))
    (let ((s5-1 (-> arg0 scale-vector)))
      (countdown (s4-1 (-> gp-0 length))
        (let ((a2-1 (-> gp-0 data s4-1 bone transform))) (scale-matrix! a2-1 s5-1 a2-1)))))
  0
  (none))

(defmethod joint-exploder-method-24 ((this joint-exploder) (arg0 joint-exploder-list) (arg1 int))
  (let ((v0-0 (joint-exploder-method-26 this arg0 arg1)))
    (let* ((v1-1 (-> this joints))
           (v1-2 (-> v1-1 joint arg1)))
      (set! (-> v1-2 mat vector 0 quad) (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 vector 3 quad) (-> this root trans quad)))
    v0-0))

(defmethod joint-exploder-method-26 ((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! (-> (the-as joint-exploder-joint (-> 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 joint-exploder-method-20 ((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! (-> (the-as joint-exploder-joint (-> v1-0 joint a0-4)) prev) arg1)
      arg1)))

(defmethod joint-exploder-method-21 ((this joint-exploder) (arg0 joint-exploder-list) (arg1 joint-exploder-joint))
  (let ((a1-1 (-> arg1 mat vector 3)))
    (cond
      ((-> arg0 bbox-valid?) (add-point! (-> arg0 bbox) (the-as vector3s 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) (the-as vector3s (-> arg1 prev-pos)))
  (none))

(defmethod joint-exploder-method-27 ((this joint-exploder) (arg0 joint-exploder-list) (arg1 int))
  (local-vars (sv-16 int) (sv-32 int) (sv-48 int))
  (let ((s4-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! s4-0 a0-4) (goto cfg-6)))
        (+! v1-0 1)))
    (label cfg-6)
    (let ((s3-0 (the-as object s4-0)))
      (cond
        ((the-as joint-exploder-list s3-0)
         (set! (-> (the-as joint-exploder-list s3-0) pre-moved?) #t)
         (set! (-> (the-as joint-exploder-list s3-0) bbox-valid?) #f))
        (else (set! s3-0 (-> this lists))))
      (set! (-> arg0 bbox-valid?) #f)
      (let ((s2-0 (-> this joints))
            (s1-0 (-> arg0 head)))
        (cond
          ((zero? arg1)
           (let ((f30-0 (* 0.5 (+ (-> arg0 bbox min x) (-> arg0 bbox max x)))))
             (while (>= s1-0 0)
               (let ((s0-0 (-> s2-0 joint s1-0)))
                 (cond
                   ((>= (-> s0-0 mat vector 3 x) f30-0)
                    (set! sv-16 (joint-exploder-method-26 this arg0 s1-0))
                    (joint-exploder-method-20 this (the-as joint-exploder-list s3-0) s1-0)
                    (set! s1-0 sv-16)
                    (joint-exploder-method-21 this (the-as joint-exploder-list s3-0) s0-0))
                   (else (joint-exploder-method-21 this arg0 s0-0) (set! s1-0 (-> s0-0 next))))))))
          ((= arg1 1)
           (let ((f30-1 (* 0.5 (+ (-> arg0 bbox min y) (-> arg0 bbox max y)))))
             (while (>= s1-0 0)
               (let ((s0-1 (-> s2-0 joint s1-0)))
                 (cond
                   ((>= (-> s0-1 mat vector 3 y) f30-1)
                    (set! sv-32 (joint-exploder-method-26 this arg0 s1-0))
                    (joint-exploder-method-20 this (the-as joint-exploder-list s3-0) s1-0)
                    (set! s1-0 sv-32)
                    (joint-exploder-method-21 this (the-as joint-exploder-list s3-0) s0-1))
                   (else (joint-exploder-method-21 this arg0 s0-1) (set! s1-0 (-> s0-1 next))))))))
          ((= arg1 2)
           (let ((f30-2 (* 0.5 (+ (-> arg0 bbox min z) (-> arg0 bbox max z)))))
             (while (>= s1-0 0)
               (let ((s0-2 (-> s2-0 joint s1-0)))
                 (cond
                   ((>= (-> s0-2 mat vector 3 z) f30-2)
                    (set! sv-48 (joint-exploder-method-26 this arg0 s1-0))
                    (joint-exploder-method-20 this (the-as joint-exploder-list s3-0) s1-0)
                    (set! s1-0 sv-48)
                    (joint-exploder-method-21 this (the-as joint-exploder-list s3-0) s0-2))
                   (else (joint-exploder-method-21 this arg0 s0-2) (set! s1-0 (-> s0-2 next)))))))))))
    s4-0))

(defmethod joint-exploder-method-28 ((this joint-exploder) (arg0 joint-exploder-list))
  (when (and (-> arg0 bbox-valid?) (>= (-> arg0 head) 0))
    (cond
      ((< 20480.0 (- (-> arg0 bbox max x) (-> arg0 bbox min x)))
       (let ((a1-2 (joint-exploder-method-27 this arg0 0))) (if a1-2 (joint-exploder-method-28 this a1-2)))
       (joint-exploder-method-28 this arg0))
      ((< 20480.0 (- (-> arg0 bbox max y) (-> arg0 bbox min y)))
       (let ((a1-5 (joint-exploder-method-27 this arg0 1))) (if a1-5 (joint-exploder-method-28 this a1-5)))
       (joint-exploder-method-28 this arg0))
      ((< 20480.0 (- (-> arg0 bbox max z) (-> arg0 bbox min z)))
       (let ((a1-8 (joint-exploder-method-27 this arg0 2))) (if a1-8 (joint-exploder-method-28 this a1-8)))
       (joint-exploder-method-28 this arg0))))
  (none))

(defmethod joint-exploder-method-25 ((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 vector 3)))
        (set! (-> s2-0 prev-pos quad) (-> s1-0 quad))
        (+! (-> s2-0 transv y) f30-0)
        (vector-v+! s1-0 s1-0 (-> s2-0 transv))
        (let ((f0-3 0.99)
              (f2-1 (* (-> s2-0 rspeed) (seconds-per-frame)))
              (f5-0 (-> s2-0 rmat vector 0 x))
              (f4-0 (-> s2-0 rmat vector 0 y))
              (f3-0 (-> s2-0 rmat vector 1 x))
              (f1-2 (-> s2-0 rmat vector 1 y)))
          (set! (-> s2-0 rmat vector 0 x) (- (* f5-0 f0-3) (* f4-0 f2-1)))
          (set! (-> s2-0 rmat vector 0 y) (+ (* f5-0 f2-1) (* f4-0 f0-3)))
          (set! (-> s2-0 rmat vector 1 x) (- (* f3-0 f0-3) (* f1-2 f2-1)))
          (set! (-> s2-0 rmat vector 1 y) (+ (* f3-0 f2-1) (* f1-2 f0-3))))
        (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 (joint-exploder-method-24 this arg0 s3-0)))
          (else (joint-exploder-method-21 this arg0 s2-0) (set! s3-0 (-> s2-0 next)))))))
  #f)

(defmethod joint-exploder-method-22 ((this joint-exploder) (arg0 joint-exploder-list))
  (fill-using-bounding-box *collide-cache*
                           (-> arg0 bbox)
                           (collide-kind background)
                           this
                           (new 'static 'pat-surface :noentity #x1))
  (let ((gp-1 (-> this joints))
        (v1-2 (-> arg0 head)))
    (while (>= v1-2 0)
      (let ((s5-1 (-> gp-1 joint v1-2)))
        (let ((s4-0 (-> s5-1 mat vector 3))
              (a2-1 (new 'stack-no-clear 'vector))
              (s3-0 (new 'stack-no-clear 'collide-tri-result)))
          (vector-! a2-1 s4-0 (-> s5-1 prev-pos))
          (when (>= (probe-using-line-sphere *collide-cache*
                                             (-> s5-1 prev-pos)
                                             a2-1
                                             40.96
                                             (collide-kind background)
                                             s3-0
                                             (new 'static 'pat-surface :noentity #x1))
                    0.0)
            (set! (-> s4-0 quad) (-> s3-0 intersect quad))
            (let ((f28-0 (vector-xz-length (-> s5-1 transv))))
              (vector-reflect! (-> s5-1 transv) (-> s5-1 transv) (-> s3-0 normal))
              (let ((f30-0 (-> s5-1 transv y)))
                (set! (-> s5-1 transv y) 0.0)
                (vector-normalize! (-> s5-1 transv) (* 0.75 f28-0))
                (set! (-> s5-1 transv y) (* 0.7 f30-0))))
            (+! (-> s4-0 y) (* 40.96 (-> s3-0 normal y)))
            (set! (-> s4-0 w) 1.0)
            (set! (-> s5-1 rspeed) (/ (-> s5-1 rspeed) 2))))
        (set! v1-2 (-> s5-1 next)))))
  #f)

(defstate joint-exploder-shatter (joint-exploder)
  :enter
    (behavior ()
      (set-time! (-> self state-time)))
  :trans
    (behavior ()
      (let* ((f1-0 (the float (- (current-time) (-> self state-time))))
             (f0-2 (- 1.0 (/ f1-0 (the float (-> self tuning duration)))))
             (f1-2 (- 1.0 (/ f1-0 (* 0.75 (the float (-> self tuning duration)))))))
        (if (< f1-2 0.0) (set! f1-2 0.0))
        (set-vector! (-> self scale-vector) f0-2 f1-2 f0-2 1.0))
      (dotimes (v1-8 5)
        (set! (-> self lists v1-8 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?))
              (joint-exploder-method-25 self s5-0)
              (if (nonzero? gp-0) (joint-exploder-method-28 self s5-0))))))
      (let ((gp-1 (new 'stack-no-clear 'bounding-box)))
        (let ((v1-26 (-> self root trans))) (set! (-> gp-1 min quad) (-> v1-26 quad)) (set! (-> gp-1 max quad) (-> v1-26 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) (joint-exploder-method-22 self s4-0))))
        (let ((s5-2 (-> self draw bounds)))
          (set-vector! s5-2
                       (* 0.5 (+ (-> gp-1 min x) (-> gp-1 max x)))
                       (* 0.5 (+ (-> gp-1 min y) (-> gp-1 max y)))
                       (* 0.5 (+ (-> gp-1 min z) (-> gp-1 max z)))
                       1.0)
          (let ((f0-12 (+ 16384.0 (vector-vector-distance s5-2 (-> gp-1 max)))))
            (vector-! s5-2 s5-2 (-> self root trans))
            (set! (-> s5-2 w) f0-12))))
      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 joint-exploder-method-23 ((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))
          (set! (-> s3-0 rspeed) (-> this tuning rot-speed))
          (cond
            ((>= a0-6 0)
             (if (zero? a0-6) (set! a0-6 (-> v1-2 joint-index)))
             (let* ((a3-0 (-> this parent-override 0 node-list data a0-6 bone transform))
                    (a2-0 (-> s3-0 mat))
                    (v1-9 (-> a3-0 vector 0 quad))
                    (a0-8 (-> a3-0 vector 1 quad))
                    (a1-4 (-> a3-0 vector 2 quad))
                    (a3-1 (-> a3-0 vector 3 quad)))
               (set! (-> a2-0 vector 0 quad) v1-9)
               (set! (-> a2-0 vector 1 quad) a0-8)
               (set! (-> a2-0 vector 2 quad) a1-4)
               (set! (-> a2-0 vector 3 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 vector 0 quad))
                    (a0-11 (-> a3-2 vector 1 quad))
                    (a1-5 (-> a3-2 vector 2 quad))
                    (a3-3 (-> a3-2 vector 3 quad)))
               (set! (-> a2-1 vector 0 quad) v1-15)
               (set! (-> a2-1 vector 1 quad) a0-11)
               (set! (-> a2-1 vector 2 quad) a1-5)
               (set! (-> a2-1 vector 3 quad) a3-3))
             (matrix-identity! (-> s3-0 rmat)))))
        (case (-> this tuning explosion)
          ((1)
           (vector-! (-> s3-0 transv) (-> s3-0 mat vector 3) (-> 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 ((s1-1 (-> this tuning fountain-rand-transv-lo))
                 (s2-1 (-> this tuning fountain-rand-transv-hi)))
             (set-vector! (-> s3-0 transv)
                          (rand-vu-float-range (-> s1-1 x) (-> s2-1 x))
                          (rand-vu-float-range (-> s1-1 y) (-> s2-1 y))
                          (rand-vu-float-range (-> s1-1 z) (-> s2-1 z))
                          1.0))))))
    (when (nonzero? (-> gp-0 num-joints))
      (let ((v1-26 (-> gp-0 joint (+ (-> gp-0 num-joints) -1)))) (set! (-> v1-26 next) -1))
      (let ((v1-27 (the-as joint-exploder-list (&-> this stack 224))))
        (set! (-> v1-27 head) 0)
        (let ((s5-1 (-> v1-27 bbox)))
          (let ((v1-28 (the-as structure (-> gp-0 joint 0 mat vector 3))))
            (set! (-> s5-1 min quad) (-> (the-as matrix v1-28) vector 0 quad))
            (set! (-> s5-1 max quad) (-> (the-as matrix v1-28) vector 0 quad)))
          (dotimes (s4-1 (-> gp-0 num-joints))
            (add-point! s5-1 (the-as vector3s (+ (the-as uint (-> gp-0 joint 0 mat vector 3)) (* 176 s4-1)))))))
      #f)))

(defmethod relocate ((this joint-exploder) (offset int))
  (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 ((arg0 skeleton-group) (arg1 int) (arg2 joint-exploder-static-params) (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) 64)
  (set! (-> self joints) (new 'process 'joint-exploder-joints arg3))
  (dotimes (v1-1 5)
    (let ((a0-6 (-> self lists v1-1)))
      (set! (-> a0-6 head) -1)
      (set! (-> a0-6 bbox-valid?) #f)
      (set! (-> a0-6 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 arg0 '())
  (logior! (-> self skel status) (janim-status inited))
  (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)
  (joint-exploder-method-23 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) (arg0 int))
  (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) (the-as uint arg0))
      (set! (-> v0-0 duration) (seconds 2))
      (set! (-> v0-0 gravity) -286720.0)
      (set! (-> v0-0 rot-speed) 8.4)
      (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)))
      v0-0)))
