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

;; name: debris.gc
;; name in dgo: debris
;; dgos: GAME

;; DECOMP BEGINS

(deftype debris-static-joint-params (structure)
  ((parent-joint-index  int16)
   (group               string)
   (offset              vector)
   )
  )


(deftype debris-static-params (basic)
  ((joints        (array debris-static-joint-params))
   (collide-spec  collide-spec)
   (sound-hit     sound-name)
   (art-level     symbol)
   )
  )


(deftype debris (basic)
  ((root             transformq  :inline)
   (node-list        cspace-array)
   (draw             draw-control)
   (duration         float)
   (hit-xz-reaction  float)
   (hit-y-reaction   float)
   (prev-pos         vector      :inline)
   (gravity          float)
   (rot-axis         vector      :inline)
   (rot-angle        float)
   (transv           vector      :inline)
   (time-fade-out    time-frame)
   (params           debris-static-params)
   )
  )


(deftype debris-box (structure)
  ((start  uint32)
   (num    uint32)
   (bbox   bounding-box  :inline)
   )
  )


(deftype debris-group (process)
  ((dead-debris-num  int32)
   (debris-num       int32)
   (debris           (array debris))
   (max-probe-width  float)
   (state-time       time-frame)
   (num-boxes        uint32)
   (boxes            debris-box  16 :inline)
   )
  (:state-methods
    idle
    )
  (:methods
    (do-collision (_type_ int) none)
    (update-box! (_type_ int) none)
    )
  )


(deftype debris-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)
   (scale-rand-lo                float)
   (scale-rand-hi                float)
   )
  (:methods
    (new (symbol type uint) _type_)
    )
  )


;; WARN: Return type mismatch structure vs debris-tuning.
(defmethod new debris-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 (t9-0 allocation v1-1)))
      (set! (-> (the-as debris-tuning v0-0) explosion) arg0)
      (set! (-> (the-as debris-tuning v0-0) duration) (seconds 1))
      (set! (-> (the-as debris-tuning v0-0) gravity) -286720.0)
      (set! (-> (the-as debris-tuning v0-0) rot-speed) 180.0)
      (set! (-> (the-as debris-tuning v0-0) bounds-inflate) 16384.0)
      (set! (-> (the-as debris-tuning v0-0) max-probe-width) 40960.0)
      (set! (-> (the-as debris-tuning v0-0) max-probe-height) 24576.0)
      (set! (-> (the-as debris-tuning v0-0) max-probe-depth) 20480.0)
      (set! (-> (the-as debris-tuning v0-0) hit-xz-reaction) 0.75)
      (set! (-> (the-as debris-tuning v0-0) hit-y-reaction) 0.7)
      (set! (-> (the-as debris-tuning v0-0) scale-rand-lo) 0.8)
      (set! (-> (the-as debris-tuning v0-0) scale-rand-hi) 2.0)
      (cond
        ((zero? arg0)
         (set-vector! (-> (the-as debris-tuning v0-0) fountain-rand-transv-lo) -81920.0 20480.0 -81920.0 1.0)
         (set-vector! (-> (the-as debris-tuning v0-0) fountain-rand-transv-hi) 81920.0 61440.0 81920.0 1.0)
         )
        ((= arg0 1)
         (vector-reset! (-> (the-as debris-tuning v0-0) fountain-rand-transv-lo))
         (set! (-> (the-as debris-tuning v0-0) fountain-rand-transv-hi x) 49152.0)
         (set! (-> (the-as debris-tuning v0-0) fountain-rand-transv-hi y) 163840.0)
         (set! (-> (the-as debris-tuning v0-0) fountain-rand-transv-hi z) 20480.0)
         (set! (-> (the-as debris-tuning v0-0) fountain-rand-transv-hi w) 61440.0)
         )
        )
      (the-as debris-tuning v0-0)
      )
    )
  )

(defmethod update-box! ((this debris-group) (idx int))
  (let ((debris-box (-> this boxes idx)))
    (dotimes (i (the-as int (-> debris-box num)))
      (let ((debris (-> this debris (+ i (-> debris-box start)))))
        (if (zero? i)
            (set-to-point! (-> debris-box bbox) (-> debris root trans))
            (add-point! (-> debris-box bbox) (-> debris root trans))
            )
        )
      )
    )
  0
  (none)
  )

(defmethod do-collision ((this debris-group) (idx int))
  (local-vars
    (sv-80 (function sound-name sound-id int int int sound-group object sound-id :behavior process-drawable))
    (name sound-name)
    )
  (let* ((debris-box (-> this boxes idx))
         (box-num (-> debris-box num))
         (box-start (-> debris-box start))
         (bbox (-> debris-box bbox))
         )
    (when (> box-num 0)
      (let ((cquery (new 'static 'collide-query)))
        (let ((debris-start (-> this debris box-start)))
          (let ((a3-0 (-> cquery bbox))
                (a1-2 (-> bbox min))
                (a2-0 (new 'stack-no-clear 'vector))
                )
            (set! (-> a2-0 x) 4096.0)
            (set! (-> a2-0 y) 4096.0)
            (set! (-> a2-0 z) 4096.0)
            (set! (-> a2-0 w) 1.0)
            (vector-! (-> a3-0 min) a1-2 a2-0)
            )
          (let ((a1-3 (-> cquery bbox max))
                (a0-2 (-> bbox max))
                (a2-1 (new 'stack-no-clear 'vector))
                )
            (set! (-> a2-1 x) 4096.0)
            (set! (-> a2-1 y) 4096.0)
            (set! (-> a2-1 z) 4096.0)
            (set! (-> a2-1 w) 1.0)
            (vector+! a1-3 a0-2 a2-1)
            )
          (set! (-> cquery collide-with) (-> debris-start params collide-spec))
          )
        (set! (-> cquery ignore-process0) #f)
        (set! (-> cquery ignore-process1) #f)
        (set! (-> cquery ignore-pat)
              (new 'static 'pat-surface :noentity #x1 :nojak #x1 :probe #x1 :noendlessfall #x1 :board #x1)
              )
        (set! (-> cquery action-mask) (collide-action solid))
        (fill-using-bounding-box *collide-cache* cquery)
        (dotimes (s2-0 (the-as int box-num))
          (let ((s1-0 (-> this debris (+ s2-0 box-start))))
            (when (not (logtest? (-> this debris (+ s2-0 box-start) draw status) (draw-control-status no-draw)))
              (let ((f0-9 (* (-> s1-0 gravity) (seconds-per-frame)))
                    (s0-0 (new 'stack-no-clear 'quaternion))
                    )
                (vector-copy! (-> s1-0 prev-pos) (-> s1-0 root trans))
                (+! (-> s1-0 transv y) f0-9)
                (vector-v+! (-> s1-0 root trans) (-> s1-0 root trans) (-> s1-0 transv))
                (quaternion-vector-angle! s0-0 (-> s1-0 rot-axis) (* (-> s1-0 rot-angle) (seconds-per-frame)))
                (quaternion*! (-> s1-0 root quat) (-> s1-0 root quat) s0-0)
                )
              (quaternion-normalize! (-> s1-0 root quat))
              (set! (-> s1-0 rot-angle) (- (-> s1-0 rot-angle) (* (seconds-per-frame) (-> s1-0 rot-angle))))
              (when (nonzero? (-> s1-0 params collide-spec))
                (let ((s0-1 (new 'stack-no-clear 'vector)))
                  (vector-! (-> cquery move-dist) (-> s1-0 root trans) (-> s1-0 prev-pos))
                  (vector-copy! (-> cquery start-pos) (-> s1-0 prev-pos))
                  (let ((v1-34 cquery))
                    (set! (-> v1-34 radius) 2048.0)
                    (set! (-> v1-34 collide-with) (-> s1-0 params collide-spec))
                    (set! (-> v1-34 ignore-process0) #f)
                    (set! (-> v1-34 ignore-process1) #f)
                    (set! (-> v1-34 ignore-pat)
                          (new 'static 'pat-surface :noentity #x1 :nojak #x1 :probe #x1 :noendlessfall #x1 :board #x1)
                          )
                    (set! (-> v1-34 action-mask) (collide-action solid))
                    )
                  (let ((f0-16 (probe-using-line-sphere *collide-cache* cquery)))
                    (when (>= f0-16 0.0)
                      (vector+*! s0-1 (-> cquery start-pos) (-> cquery move-dist) f0-16)
                      (let* ((v1-38 (-> s1-0 transv))
                             (f30-0 (sqrtf (+ (* (-> v1-38 x) (-> v1-38 x)) (* (-> v1-38 z) (-> v1-38 z)))))
                             )
                        (let ((f28-0 (vector-length (-> s1-0 transv))))
                          (when (< (-> s1-0 transv y) -61440.0)
                            (set! sv-80 sound-play-by-name)
                            (set! name (-> s1-0 params sound-hit))
                            (let ((a1-14 (new-sound-id))
                                  (a2-5 1024)
                                  (a3-6 0)
                                  (t0-4 0)
                                  (t1-0 0)
                                  (t2-0 (-> s1-0 root))
                                  )
                              (sv-80 name a1-14 a2-5 a3-6 t0-4 (the-as sound-group t1-0) t2-0)
                              )
                            )
                          (vector-reflect! (-> s1-0 transv) (-> s1-0 transv) (-> cquery best-other-tri normal))
                          (vector-reflect! (-> s1-0 rot-axis) (-> s1-0 rot-axis) (-> cquery best-other-tri normal))
                          (set! (-> s1-0 rot-angle) f28-0)
                          )
                        (let ((f28-1 (-> s1-0 transv y)))
                          (vector-xz-normalize! (-> s1-0 transv) (* f30-0 (-> s1-0 hit-xz-reaction)))
                          (set! (-> s1-0 transv y) (* f28-1 (-> s1-0 hit-y-reaction)))
                          )
                        )
                      (+! (-> s0-1 y) (* 40.96 (-> cquery best-other-tri normal y)))
                      (set! (-> s0-1 w) 1.0)
                      (set! (-> s1-0 root trans quad) (-> s0-1 quad))
                      )
                    )
                  )
                )
              )
            )
          )
        )
      )
    )
  0
  (none)
  )

(defstate idle (debris-group)
  :virtual #t
  :enter (behavior ()
    (set-time! (-> self state-time))
    )
  :trans (behavior ()
    (set! (-> self dead-debris-num) (-> self debris-num))
    (dotimes (i (-> self debris-num))
      (let ((debris (-> self debris i))
            (draw-ctrl (-> self debris i draw))
            )
        (matrix<-transformq+trans!
          (-> draw-ctrl skeleton bones 3 transform)
          (-> debris root)
          (-> draw-ctrl skeleton bones 0 transform trans)
          )
        (logclear! (-> draw-ctrl status) (draw-control-status no-draw-temp uninited))
        (vector+! (-> draw-ctrl origin) (-> draw-ctrl skeleton bones 3 transform trans) (-> draw-ctrl bounds))
        (set! (-> draw-ctrl origin w) (-> draw-ctrl bounds w))
        (cond
          ((zero? (-> debris time-fade-out))
           (if (or (< (vector-length (-> debris transv)) 4096.0)
                   (time-elapsed? (-> self state-time) (the int (-> debris duration)))
                   )
               (set-time! (-> debris time-fade-out))
               )
           )
          ((time-elapsed? (-> debris time-fade-out) (seconds 0.5))
           (logior! (-> draw-ctrl status) (draw-control-status no-draw))
           (+! (-> self dead-debris-num) -1)
           )
          (else
            (logior! (-> draw-ctrl status) (draw-control-status force-fade))
            (set! (-> draw-ctrl force-fade)
                  (the-as uint (the int (- 128.0 (* 0.85333335 (the float (- (current-time) (-> debris time-fade-out)))))))
                  )
            )
          )
        )
      )
    (if (zero? (-> self dead-debris-num))
        (deactivate self)
        )
    (dotimes (ii (the-as int (-> self num-boxes)))
      (let* ((debris-box (-> self boxes ii))
             (box-num (-> debris-box num))
             (box-start (-> debris-box start))
             (bbox (-> debris-box bbox))
             (s2-0 0)
             )
        (update-box! self ii)
        (if (< (- (-> bbox max data s2-0) (-> bbox min data s2-0)) (- (-> bbox max y) (-> bbox min y)))
            (set! s2-0 1)
            )
        (if (< (- (-> bbox max data s2-0) (-> bbox min data s2-0)) (- (-> bbox max z) (-> bbox min z)))
            (set! s2-0 2)
            )
        (when (and (< (-> self max-probe-width) (- (-> debris-box bbox max data s2-0) (-> bbox min data s2-0)))
                   (< (-> self num-boxes) (the-as uint 15))
                   )
          0.0
          (let ((a1-3 (new 'static 'boxed-array :type debris :length 0 :allocated-length 32))
                (a0-12 0)
                (v1-72 0)
                (a2-4 (-> self boxes (-> self num-boxes)))
                )
            (let ((f0-14 (* 0.5 (+ (-> debris-box bbox min data s2-0) (-> debris-box bbox max data s2-0)))))
              (dotimes (a3-6 (the-as int box-num))
                (let ((t0-4 (-> self debris (+ a3-6 (-> debris-box start)))))
                  (cond
                    ((< (-> t0-4 root trans data s2-0) f0-14)
                     (set! (-> self debris (+ a0-12 box-start)) (-> self debris (+ a3-6 box-start)))
                     (+! a0-12 1)
                     )
                    (else
                      (set! (-> a1-3 v1-72) (-> self debris (+ a3-6 box-start)))
                      (+! v1-72 1)
                      )
                    )
                  )
                )
              )
            (dotimes (a3-9 v1-72)
              (set! (-> self debris (+ a0-12 box-start a3-9)) (-> a1-3 a3-9))
              )
            (set! (-> debris-box num) (the-as uint a0-12))
            (set! (-> a2-4 start) (+ box-start a0-12))
            (set! (-> a2-4 num) (the-as uint v1-72))
            )
          (update-box! self ii)
          (update-box! self (the-as int (-> self num-boxes)))
          (+! (-> self num-boxes) 1)
          )
        )
      )
    (dotimes (gp-2 (the-as int (-> self num-boxes)))
      (do-collision self gp-2)
      )
    )
  :code sleep-code
  )

;; WARN: Return type mismatch process vs debris-group.
(defmethod relocate ((this debris-group) (offset int))
  (dotimes (v1-0 (-> this debris length))
    (if (nonzero? (-> this debris v1-0 node-list))
        (&+! (-> this debris v1-0 node-list) offset)
        )
    (if (nonzero? (-> this debris v1-0 draw))
        (&+! (-> this debris v1-0 draw) offset)
        )
    (if (nonzero? (-> this debris v1-0))
        (&+! (-> this debris v1-0) offset)
        )
    )
  (if (nonzero? (-> this debris))
      (&+! (-> this debris) offset)
      )
  (the-as debris-group ((method-of-type process relocate) this offset))
  )

(defbehavior debris-group-init-by-other debris-group ((tuning debris-tuning) (params debris-static-params) (pdraw process-drawable))
  (local-vars (tuning-scale vector) (debris-scale vector) (sv-80 vector) (sv-96 vector) (sv-112 vector))
  (rlet ((vf0 :class vf)
         (vf4 :class vf)
         (vf5 :class vf)
         (vf6 :class vf)
         )
    (init-vf0-vector)
    (stack-size-set! (-> self main-thread) 512)
    (set! (-> self debris-num) (-> params joints length))
    (set! (-> self debris) (new 'process 'boxed-array debris (-> self debris-num)))
    (set! (-> self debris length) (-> self debris allocated-length))
    (dotimes (i (-> params joints length))
      (set! (-> self debris i) (new 'process 'debris))
      (let ((skel (art-group-get-by-name *level* (-> params joints i group) (the-as (pointer level) #f)))
            (debris (-> self debris i))
            )
        (cond
          ((and skel (nonzero? skel))
           (set! (-> debris params) params)
           (let ((joint-transform (-> pdraw node-list data (-> params joints i parent-joint-index) bone transform)))
             (matrix->quaternion (-> debris root quat) joint-transform)
             (matrix->trans joint-transform (-> debris root trans))
             (vector-copy! (-> debris root scale) (-> pdraw root scale))
             (if (nonzero? (-> params joints i offset))
                 (vector-matrix*! (-> debris root trans) (-> params joints i offset) joint-transform)
                 )
             )
           (set! debris-scale (-> debris root scale))
           (let ((s0-1 (-> debris root scale)))
             (set! tuning-scale (new 'stack-no-clear 'vector))
             (set! (-> tuning-scale x) (rand-vu-float-range (-> tuning scale-rand-lo) (-> tuning scale-rand-hi)))
             (set! (-> tuning-scale y) (rand-vu-float-range (-> tuning scale-rand-lo) (-> tuning scale-rand-hi)))
             (set! (-> tuning-scale z) (rand-vu-float-range (-> tuning scale-rand-lo) (-> tuning scale-rand-hi)))
             (set! (-> tuning-scale w) 1.0)
             (.lvf vf4 (&-> s0-1 quad))
             )
           (.lvf vf5 (&-> tuning-scale quad))
           (.add.x.vf.w vf6 vf0 vf0)
           (.mul.vf.xyz vf6 vf4 vf5)
           (.svf (&-> debris-scale quad) vf6)
           (case (-> tuning explosion)
             ((1)
              (vector-! (-> debris transv) (-> debris root trans) (-> tuning fountain-rand-transv-lo))
              (let ((s0-2 vector-normalize!))
                (set! sv-80 (-> debris transv))
                (let ((a1-17 (rand-vu-float-range (-> tuning fountain-rand-transv-hi x) (-> tuning fountain-rand-transv-hi y))))
                  (s0-2 sv-80 a1-17)
                  )
                )
              (+! (-> debris transv y)
                  (rand-vu-float-range (-> tuning fountain-rand-transv-hi z) (-> tuning fountain-rand-transv-hi w))
                  )
              (set! (-> debris transv w) 1.0)
              )
             (else
               (set! sv-96 (-> tuning fountain-rand-transv-lo))
               (set! sv-112 (-> tuning fountain-rand-transv-hi))
               (set-vector!
                 (-> debris transv)
                 (rand-vu-float-range (-> sv-96 x) (-> sv-112 x))
                 (rand-vu-float-range (-> sv-96 y) (-> sv-112 y))
                 (rand-vu-float-range (-> sv-96 z) (-> sv-112 z))
                 1.0
                 )
               )
             )
           (let ((s0-5 (new 'stack-no-clear 'vector)))
             (rand-vu-sphere-point-uniform! s0-5 1.0)
             (vector-normalize! s0-5 1.0)
             (vector-copy! (-> debris rot-axis) s0-5)
             )
           (set! (-> debris rot-angle) (* 182.04445 (-> tuning rot-speed)))
           (set! (-> debris duration) (the float (-> tuning duration)))
           (set! (-> debris hit-xz-reaction) (-> tuning hit-xz-reaction))
           (set! (-> debris hit-y-reaction) (-> tuning hit-y-reaction))
           (set! (-> debris gravity) (-> tuning gravity))
           (set! (-> debris time-fade-out) 0)
           (let ((draw (skeleton-group->draw-control
                         (the-as process-drawable self)
                         (the-as skeleton-group skel)
                         (&-> debris node-list)
                         )
                       )
                 )
             (set! (-> debris draw) draw)
             (vector-copy! (-> draw skeleton bones 0 transform trans) *null-vector*)
             )
           )
          (else
            )
          )
        )
      )
    (set! (-> self max-probe-width) (-> tuning max-probe-width))
    (set! (-> self num-boxes) (the-as uint 1))
    (set! (-> self boxes 0 start) (the-as uint 0))
    (set! (-> self boxes 0 num) (the-as uint (-> self debris-num)))
    (go-virtual idle)
    )
  )

;; WARN: Return type mismatch (pointer process) vs (pointer debris-group).
(defun debris-spawn ((arg0 process-drawable) (arg1 debris-tuning) (arg2 debris-static-params) (arg3 process-drawable))
  (if (not arg3)
      (set! arg3 arg0)
      )
  (process-spawn debris-group arg1 arg2 arg3 :name "debris-group" :to arg0 :stack-size #x8000)
  )

(defskelgroup skel-kg-debris-a kg-debris kg-debris-a-lod0-jg -1
              ((kg-debris-a-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-kg-debris-b kg-debris kg-debris-b-lod0-jg -1
              ((kg-debris-b-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-kg-debris-c kg-debris kg-debris-c-lod0-jg -1
              ((kg-debris-c-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-kg-debris-d kg-debris kg-debris-d-lod0-jg -1
              ((kg-debris-d-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-neo-debris-a neo-debris neo-debris-a-lod0-jg -1
              ((neo-debris-a-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-neo-debris-b neo-debris neo-debris-b-lod0-jg -1
              ((neo-debris-b-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-neo-debris-c neo-debris neo-debris-c-lod0-jg -1
              ((neo-debris-c-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-neo-debris-d neo-debris neo-debris-d-lod0-jg -1
              ((neo-debris-d-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-v-marauder-debris-ring interceptor interceptor-debris-ring-lod0-jg -1
              ((interceptor-debris-ring-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-v-marauder-debris-nut interceptor interceptor-debris-nut-lod0-jg -1
              ((interceptor-debris-nut-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-v-marauder-debris-rod interceptor interceptor-debris-rod-lod0-jg -1
              ((interceptor-debris-rod-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-v-marauder-debris-panel interceptor interceptor-debris-panel-lod0-jg -1
              ((interceptor-debris-panel-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-dm-debris-a dm-debris dm-debris-a-lod0-jg -1
              ((dm-debris-a-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-dm-debris-b dm-debris dm-debris-b-lod0-jg -1
              ((dm-debris-b-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-dm-debris-c dm-debris dm-debris-c-lod0-jg -1
              ((dm-debris-c-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )

(defskelgroup skel-dm-debris-d dm-debris dm-debris-d-lod0-jg -1
              ((dm-debris-d-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 2)
              )
