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

;; name: water-flow.gc
;; name in dgo: water-flow
;; dgos: ENGINE, GAME

;; DECOMP BEGINS

(defun ray-plane-equation-intersect ((arg0 vector) (arg1 vector) (arg2 vector) (arg3 vector))
  (let* ((f0-1 (vector4-dot arg3 arg1))
         (f1-1 (vector-dot arg3 arg2))
         (f30-0 (/ (- f0-1) f1-1))
         )
    (vector-v*float+! arg0 arg1 arg2 f30-0)
    f30-0
    )
  )

(deftype flow-section (structure)
  ((start       vector  :inline)
   (trailing    plane   :inline)
   (pull-dir    vector  :inline)
   (radial-dir  vector  :inline)
   )
  )


(deftype flow-section-array (inline-array-class)
  ((data  flow-section  :inline :dynamic)
   )
  )


(set! (-> flow-section-array heap-base) (the-as uint 64))

(deftype flow-control (basic)
  ((path            path-control)
   (speed           float)
   (belt-radius     float)
   (sections        flow-section-array)
   (leading         plane   :inline)
   (collide-bounds  sphere  :inline)
   )
  (:methods
    (new (symbol type process-drawable res-lump) _type_)
    (draw-path (_type_) none)
    (setup (_type_) none)
    (push-process (_type_ process-focusable) none)
    (find-and-push-things (_type_) none)
    )
  )


(defmethod relocate ((this flow-control) (arg0 int))
  (if (nonzero? (-> this sections))
      (&+! (-> this sections) arg0)
      )
  (if (nonzero? (-> this path))
      (&+! (-> this path) arg0)
      )
  (call-parent-method this arg0)
  )

(defmethod draw-path ((this flow-control))
  (let ((a0-1 (-> this path)))
    (if (nonzero? a0-1)
        (debug-draw a0-1)
        )
    )
  0
  (none)
  )

;; WARN: Function (method 11 flow-control) has a return type of none, but the expression builder found a return statement.
(defmethod push-process ((this flow-control) (arg0 process-focusable))
  (rlet ((acc :class vf)
         (vf0 :class vf)
         (vf4 :class vf)
         (vf5 :class vf)
         (vf6 :class vf)
         (vf7 :class vf)
         )
    (init-vf0-vector)
    (let ((s5-0 (new 'stack-no-clear 'vector)))
      (set! (-> s5-0 quad) (-> (get-trans arg0 0) quad))
      (set! (-> s5-0 w) 1.0)
      (when (>= (vector4-dot s5-0 (the-as vector (-> this leading))) 0.0)
        (let* ((v1-7 (-> this sections))
               (a0-3 (-> v1-7 length))
               (a3-0 (the-as object (-> this leading)))
               )
          (dotimes (s3-1 a0-3)
            (let ((s2-0 (-> v1-7 data s3-1)))
              (when (< (vector4-dot s5-0 (the-as vector (-> s2-0 trailing))) 0.0)
                (let ((v1-8 (new 'stack-no-clear 'vector)))
                  (vector-! v1-8 s5-0 (-> s2-0 start))
                  (when (>= (-> this belt-radius) (fabs (vector-dot v1-8 (-> s2-0 radial-dir))))
                    (let* ((f0-7 (vector-dot v1-8 (-> s2-0 pull-dir)))
                           (f0-9 (- (-> v1-8 y) (* (-> s2-0 pull-dir y) f0-7)))
                           )
                      (when (and (>= f0-9 -41984.0) (>= 41779.2 f0-9))
                        (let* ((a0-11 (new 'stack-no-clear 'vector))
                               (s1-0 (new 'stack-no-clear 'vector))
                               (f30-0 (ray-plane-equation-intersect a0-11 s5-0 (-> s2-0 pull-dir) (the-as vector a3-0)))
                               (f0-10 (ray-plane-equation-intersect s1-0 s5-0 (-> s2-0 pull-dir) (-> s2-0 trailing)))
                               )
                          (let ((a0-13 (new 'stack-no-clear 'vector)))
                            (let ((v1-13 (-> s2-0 start)))
                              (let ((a1-12 (-> s2-0 pull-dir)))
                                (let ((a2-6 12288.0))
                                  (.mov vf7 a2-6)
                                  )
                                (.lvf vf5 (&-> a1-12 quad))
                                )
                              (.lvf vf4 (&-> v1-13 quad))
                              )
                            (.add.x.vf.w vf6 vf0 vf0)
                            (.mul.x.vf.xyz acc vf5 vf7)
                            (.add.mul.w.vf.xyz vf6 vf4 vf0 acc)
                            (.svf (&-> a0-13 quad) vf6)
                            )
                          0
                          (let ((f0-12 (/ f30-0 (- f30-0 f0-10)))
                                (s2-1 (new 'stack-no-clear 'vector))
                                )
                            (displacement-between-two-points-normalized! (-> this path) s2-1 (+ (the float s3-1) f0-12))
                            (let ((v1-17 (new 'stack-no-clear 'vector)))
                              (vector-float*! v1-17 s2-1 (* (-> this speed) (seconds-per-frame)))
                              (let ((a1-15 (new 'stack-no-clear 'vector)))
                                (let ((a0-17 v1-17))
                                  (let ((a2-9 2048.0))
                                    (.mov vf7 a2-9)
                                    )
                                  (.lvf vf5 (&-> a0-17 quad))
                                  )
                                (.lvf vf4 (&-> s5-0 quad))
                                (.add.x.vf.w vf6 vf0 vf0)
                                (.mul.x.vf.xyz acc vf5 vf7)
                                (.add.mul.w.vf.xyz vf6 vf4 vf0 acc)
                                (.svf (&-> a1-15 quad) vf6)
                                )
                              0
                              (send-event arg0 'push-trans v1-17 (seconds 10))
                              )
                            )
                          )
                        )
                      )
                    )
                  )
                (return #f)
                )
              )
            (set! a3-0 (+ (the-as uint (-> v1-7 data 0 trailing)) (* s3-1 64)))
            )
          )
        )
      )
    0
    (none)
    )
  )

(defmethod find-and-push-things ((this flow-control))
  (local-vars (a0-10 float) (a2-5 float) (a2-12 float))
  (rlet ((acc :class vf)
         (vf0 :class vf)
         (vf1 :class vf)
         (vf2 :class vf)
         (vf3 :class vf)
         (vf4 :class vf)
         )
    (init-vf0-vector)
    (set! *actor-list-length* 0)
    (if #t
        (set! *actor-list-length* (fill-actor-list-for-sphere *actor-hash* (-> this collide-bounds) *actor-list* 256))
        )
    (when #t
      (let ((a0-2 (-> *collide-player-list* alive-list next0)))
        *collide-player-list*
        (let ((v1-11 (-> a0-2 next0)))
          (while (!= a0-2 (-> *collide-player-list* alive-list-end))
            (let* ((a0-3 (-> (the-as connection a0-2) param1))
                   (a1-1 (-> (the-as collide-shape a0-3) root-prim))
                   )
              (when (logtest? (-> a1-1 prim-core collide-as) (collide-spec jak bot enemy hit-by-others-list player-list))
                (let ((a1-2 (-> a1-1 prim-core)))
                  (let ((a2-4 a1-2)
                        (a3-1 (-> this collide-bounds))
                        )
                    (.lvf vf2 (&-> a2-4 world-sphere quad))
                    (.lvf vf3 (&-> a3-1 quad))
                    )
                  (.sub.vf vf1 vf3 vf2)
                  (.mul.vf vf1 vf1 vf1)
                  (.add.y.vf.x vf1 vf1 vf1)
                  (.add.z.vf.x vf1 vf1 vf1)
                  (.mov a2-5 vf1)
                  (let ((f0-0 a2-5)
                        (f1-1 (+ (-> a1-2 world-sphere w) (-> this collide-bounds r)))
                        )
                    (when (< f0-0 (* f1-1 f1-1))
                      (when (< *actor-list-length* 256)
                        (set! (-> *actor-list* *actor-list-length*) (the-as collide-shape a0-3))
                        (set! *actor-list-length* (+ *actor-list-length* 1))
                        )
                      )
                    )
                  )
                )
              )
            (set! a0-2 v1-11)
            *collide-player-list*
            (set! v1-11 (-> v1-11 next0))
            )
          )
        )
      )
    (b! (not #f) cfg-20 :delay (empty-form))
    (let ((a0-5 (-> *collide-hit-by-player-list* alive-list next0)))
      *collide-hit-by-player-list*
      (let ((v1-18 (-> a0-5 next0)))
        (b! #t cfg-18 :delay (nop!))
        (label cfg-13)
        (let ((a0-6 (-> (the-as connection a0-5) param1)))
          (let ((a1-13 (-> (the-as collide-shape a0-6) root-prim)))
            (b!
              (not (logtest? (-> a1-13 prim-core collide-as) (collide-spec jak bot enemy hit-by-others-list player-list)))
              cfg-17
              :delay (empty-form)
              )
            (let ((a1-14 (-> a1-13 prim-core)))
              (let ((a2-11 a1-14)
                    (a3-2 (-> this collide-bounds))
                    )
                (.lvf vf2 (&-> a2-11 world-sphere quad))
                (.lvf vf3 (&-> a3-2 quad))
                )
              (.sub.vf vf1 vf3 vf2)
              (.mul.vf vf1 vf1 vf1)
              (.add.y.vf.x vf1 vf1 vf1)
              (.add.z.vf.x vf1 vf1 vf1)
              (.mov a2-12 vf1)
              (let ((f0-1 a2-12)
                    (f1-5 (+ (-> a1-14 world-sphere w) (-> this collide-bounds r)))
                    )
                (b! (>= f0-1 (* f1-5 f1-5)) cfg-17 :delay #f)
                )
              )
            )
          (b! (>= *actor-list-length* 256) cfg-17 :delay #f)
          (set! (-> *actor-list* *actor-list-length*) (the-as collide-shape a0-6))
          )
        (set! *actor-list-length* (+ *actor-list-length* 1))
        (label cfg-17)
        (set! a0-5 v1-18)
        *collide-hit-by-player-list*
        (set! v1-18 (-> v1-18 next0))
        )
      (label cfg-18)
      (b! (!= a0-5 (-> *collide-hit-by-player-list* alive-list-end)) cfg-13 :delay (nop!))
      )
    (label cfg-20)
    (let ((s5-0 0))
      (b! #t cfg-29 :delay (nop!))
      (label cfg-21)
      (let* ((v1-23 (-> *actor-list* s5-0))
             (a0-9 (-> v1-23 root-prim))
             )
        (when (logtest? (-> a0-9 prim-core collide-as) (collide-spec jak bot enemy hit-by-others-list player-list))
          (.lvf vf1 (&-> this collide-bounds quad))
          (.lvf vf2 (&-> a0-9 prim-core world-sphere quad))
          (.sub.vf vf3 vf1 vf2)
          (.add.w.vf.w vf4 vf1 vf2)
          (.mul.vf.xyz vf3 vf3 vf3)
          (.mul.w.vf.w vf4 vf4 vf4)
          (.mul.x.vf.w acc vf0 vf3)
          (.add.mul.y.vf.w acc vf0 vf3 acc)
          (.add.mul.z.vf.w vf3 vf0 vf3 acc)
          (.sub.w.vf.w vf3 vf3 vf4)
          (let ((f0-2 0.0))
            (.add.w.vf.x vf3 vf0 vf3)
            (.mov a0-10 vf3)
            (let ((s4-0 (-> v1-23 process)))
              (b! (< f0-2 a0-10) cfg-27)
              (let ((a1-29 (if (type? s4-0 process-focusable)
                               s4-0
                               )
                           )
                    )
                (if a1-29
                    (push-process this (the-as process-focusable a1-29))
                    )
                )
              )
            )
          (label cfg-27)
          0
          )
        )
      (+! s5-0 1)
      (label cfg-29)
      (b! (< s5-0 *actor-list-length*) cfg-21)
      )
    0
    (none)
    )
  )

(defmethod setup ((this flow-control))
  (local-vars (sv-32 flow-section) (sv-48 flow-section))
  (let* ((s5-0 (-> this path))
         (s4-0 (-> s5-0 curve num-cverts))
         (s3-0 (new 'stack-no-clear 'vector))
         )
    (let ((s2-0 (new 'process 'flow-section-array (+ s4-0 -1))))
      (set! (-> this sections) s2-0)
      (set! (-> this collide-bounds quad) (the-as uint128 0))
      (get-point-in-path! s5-0 s3-0 0.0 'interp)
      (vector+! (the-as vector (-> this collide-bounds)) (the-as vector (-> this collide-bounds)) s3-0)
      (let ((s1-0 (+ s4-0 -1)))
        (set! sv-32 (the-as flow-section #f))
        (dotimes (s0-0 s1-0)
          (set! sv-48 (-> s2-0 data s0-0))
          (set! (-> sv-48 start quad) (-> s3-0 quad))
          (get-point-in-path! s5-0 s3-0 (the float (+ s0-0 1)) 'interp)
          (vector+! (the-as vector (-> this collide-bounds)) (the-as vector (-> this collide-bounds)) s3-0)
          (vector-! (-> sv-48 pull-dir) s3-0 (-> sv-48 start))
          (vector-normalize! (-> sv-48 pull-dir) 1.0)
          (set! (-> sv-48 trailing quad) (-> sv-48 pull-dir quad))
          (set! (-> sv-48 trailing y) 0.0)
          (vector-normalize! (-> sv-48 trailing) 1.0)
          (set-vector! (-> sv-48 radial-dir) (- (-> sv-48 trailing z)) 0.0 (-> sv-48 trailing x) 1.0)
          (set! (-> sv-48 trailing w) (- (vector-dot s3-0 (the-as vector (-> sv-48 trailing)))))
          (when sv-32
            (vector+!
              (the-as vector (-> sv-32 trailing))
              (the-as vector (-> sv-32 trailing))
              (the-as vector (-> sv-48 trailing))
              )
            (vector-normalize! (-> sv-32 trailing) 1.0)
            (set! (-> sv-32 trailing w) (- (vector-dot (-> sv-48 start) (the-as vector (-> sv-32 trailing)))))
            )
          (set! sv-32 sv-48)
          sv-32
          )
        )
      )
    (let ((s2-1 (-> this sections data)))
      (set! (-> this leading quad) (-> s2-1 0 pull-dir quad))
      (set! (-> this leading y) 0.0)
      (vector-normalize! (-> this leading) 1.0)
      (set! (-> this leading w) (- (vector-dot (the-as vector (-> s2-1 0)) (the-as vector (-> this leading)))))
      )
    (let ((f0-19 (/ 1.0 (the float s4-0)))
          (f30-0 0.0)
          )
      (vector-float*! (the-as vector (-> this collide-bounds)) (the-as vector (-> this collide-bounds)) f0-19)
      (dotimes (s2-2 s4-0)
        (get-point-in-path! s5-0 s3-0 (the float s2-2) 'interp)
        (let ((f0-22 (vector-vector-distance-squared s3-0 (-> this collide-bounds))))
          (if (< f30-0 f0-22)
              (set! f30-0 f0-22)
              )
          )
        )
      (set! (-> this collide-bounds r) (+ (sqrtf f30-0) (-> this belt-radius)))
      )
    )
  0
  (none)
  )

(defmethod new flow-control ((allocation symbol) (type-to-make type) (arg0 process-drawable) (arg1 res-lump))
  (if (not arg1)
      (set! arg1 (-> arg0 entity))
      )
  (let ((s5-0 (object-new allocation type-to-make (the-as int (-> type-to-make size)))))
    (when (nonzero? s5-0)
      (let ((v1-6 (new 'process 'curve-control arg0 'flow -1000000000.0)))
        (cond
          ((nonzero? v1-6)
           (set! (-> s5-0 path) v1-6)
           (logior! (-> v1-6 flags) (path-control-flag display draw-line draw-point draw-text))
           (if (< (-> v1-6 curve num-cverts) 2)
               (go process-drawable-art-error "bad flow path")
               )
           (set! (-> s5-0 speed) (res-lump-float arg1 'speed :default 12288.0))
           (set! (-> s5-0 belt-radius) (res-lump-float arg1 'extra-radius :default 16384.0))
           (setup s5-0)
           )
          (else
            (go process-drawable-art-error "no flow path")
            )
          )
        )
      )
    s5-0
    )
  )
