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

;; name: mountain-obs2.gc
;; name in dgo: mountain-obs2
;; dgos: MTN

;; DECOMP BEGINS

(deftype mtn-iris-door (process-drawable)
  ((root  collide-shape :override)
   )
  (:state-methods
    open
    close
    )
  )


(defskelgroup skel-mtn-iris-door mtn-iris-door mtn-iris-door-lod0-jg mtn-iris-door-idle-ja
              ((mtn-iris-door-lod0-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 13.5)
              :origin-joint-index 3
              )

(defstate close (mtn-iris-door)
  :virtual #t
  :trans (behavior ()
    (if (task-node-closed? (game-task-node canyon-insert-items-door))
        (go-virtual open)
        )
    )
  :code (behavior ()
    (let ((root-prim (-> self root root-prim)))
      (set! (-> root-prim prim-core collide-as) (-> self root backup-collide-as))
      (set! (-> root-prim prim-core collide-with) (-> self root backup-collide-with))
      )
    (ja :num-func num-func-identity :frame-num 0.0)
    (ja-post)
    (sleep-code)
    )
  )

(defstate open (mtn-iris-door)
  :virtual #t
  :trans (behavior ()
    (if (not (task-node-closed? (game-task-node canyon-insert-items-door)))
        (go-virtual close)
        )
    )
  :code (behavior ()
    (let ((root-prim (-> self root root-prim)))
      (set! (-> root-prim prim-core collide-as) (collide-spec))
      (set! (-> root-prim prim-core collide-with) (collide-spec))
      )
    0
    (ja :num-func num-func-identity :frame-num max)
    (ja-post)
    (sleep-code)
    )
  )

;; WARN: Return type mismatch object vs none.
(defmethod init-from-entity! ((this mtn-iris-door) (entity entity-actor))
  "Typically the method that does the initial setup on the process, potentially using the [[entity-actor]] provided as part of that.
This commonly includes things such as:
- stack size
- collision information
- loading the skeleton group / bones
- sounds"
  (let ((cshape (new 'process 'collide-shape this (collide-list-enum hit-by-player))))
    (let ((prim-mesh (new 'process 'collide-shape-prim-mesh cshape (the-as uint 0) (the-as uint 0))))
      (set! (-> prim-mesh prim-core collide-as) (collide-spec obstacle))
      (set! (-> prim-mesh prim-core collide-with) (collide-spec jak player-list))
      (set! (-> prim-mesh prim-core action) (collide-action solid))
      (set! (-> prim-mesh transform-index) 3)
      (set-vector! (-> prim-mesh local-sphere) 0.0 0.0 0.0 40960.0)
      (set! (-> cshape total-prims) (the-as uint 1))
      (set! (-> cshape root-prim) prim-mesh)
      )
    (set! (-> cshape nav-radius) (* 0.75 (-> cshape root-prim local-sphere w)))
    (let ((root-prim (-> cshape root-prim)))
      (set! (-> cshape backup-collide-as) (-> root-prim prim-core collide-as))
      (set! (-> cshape backup-collide-with) (-> root-prim prim-core collide-with))
      )
    (set! (-> this root) cshape)
    )
  (process-drawable-from-entity! this entity)
  (initialize-skeleton
    this
    (the-as skeleton-group (art-group-get-by-name *level* "skel-mtn-iris-door" (the-as (pointer uint32) #f)))
    (the-as pair 0)
    )
  (go (method-of-object this close))
  (none)
  )

(deftype mtn-plat-shoot (plat)
  ((incoming-attack-id   uint32)
   (angle-flip           float)
   (angle-flip-vel       float)
   (axe-flip             vector  :inline)
   (state-flip           uint32)
   (hit-time             time-frame)
   (time-flip            float)
   (disable-track-under  basic)
   (dest-angle           float)
   (on-shake             symbol)
   (hint-count           float)
   )
  )


(defskelgroup skel-mtn-plat-shoot mtn-plat-shoot mtn-plat-shoot-lod0-jg mtn-plat-shoot-idle-ja
              ((mtn-plat-shoot-lod0-mg (meters 20)) (mtn-plat-shoot-lod1-mg (meters 999999)))
              :bounds (static-spherem 0 0 0 5.1)
              )

(defmethod get-art-group ((this mtn-plat-shoot))
  "@returns The associated [[art-group]]"
  (art-group-get-by-name *level* "skel-mtn-plat-shoot" (the-as (pointer uint32) #f))
  )

(defmethod init-plat-collision! ((this mtn-plat-shoot))
  "TODO - collision stuff for setting up the platform"
  (let ((cshape (new 'process 'collide-shape this (collide-list-enum usually-hit-by-player))))
    (let ((prim-mesh (new 'process 'collide-shape-prim-mesh cshape (the-as uint 0) (the-as uint 0))))
      (set! (-> prim-mesh prim-core collide-as) (collide-spec pusher))
      (set! (-> prim-mesh prim-core collide-with) (collide-spec jak player-list))
      (set! (-> prim-mesh prim-core action) (collide-action solid rideable))
      (set! (-> prim-mesh transform-index) 0)
      (set-vector! (-> prim-mesh local-sphere) 0.0 0.0 0.0 20889.6)
      (set! (-> cshape total-prims) (the-as uint 1))
      (set! (-> cshape root-prim) prim-mesh)
      )
    (pusher-init cshape)
    (set! (-> cshape nav-radius) (* 0.75 (-> cshape root-prim local-sphere w)))
    (let ((root-prim (-> cshape root-prim)))
      (set! (-> cshape backup-collide-as) (-> root-prim prim-core collide-as))
      (set! (-> cshape backup-collide-with) (-> root-prim prim-core collide-with))
      )
    (set! (-> this root) (the-as collide-shape-moving cshape))
    )
  0
  (none)
  )

(defmethod base-plat-method-32 ((this mtn-plat-shoot))
  0
  (none)
  )

(defmethod init-plat! ((this mtn-plat-shoot))
  "Does any necessary initial platform setup.
For example for an elevator pre-compute the distance between the first and last points (both ways) and clear the sound."
  (logclear! (-> this mask) (process-mask actor-pause))
  (logior! (-> this mask) (process-mask enemy))
  (set-vector! (-> this axe-flip) 1.0 0.0 0.0 1.0)
  (set! (-> this angle-flip) 180.0)
  (set! (-> this time-flip)
        (the float (the int (* 300.0 (res-lump-float (-> this entity) 'delay :default 4.0))))
        )
  (set! (-> this disable-track-under) #f)
  (if (>= (res-lump-value (-> this entity) 'extra-id int :default (the-as uint128 -1) :time -1000000000.0) 0)
      (set! (-> this disable-track-under) (the-as basic #t))
      )
  (set! (-> this hint-count) 0.0)
  (if (> (you-suck-stage *game-info* #f) 0)
      (set! (-> this hint-count) 5.0)
      )
  (set! (-> this sound)
        (new 'process 'ambient-sound (static-sound-spec "shoot-plat-lp" :fo-max 70) (-> this root trans))
        )
  0
  (none)
  )

(defstate plat-path-active (mtn-plat-shoot)
  :virtual #t
  :event (behavior ((proc process) (argc int) (message symbol) (block event-message-block))
    (case message
      (('bonk)
       (start-bouncing! self)
       )
      (('attack)
       (when (zero? (-> self state-flip))
         (let ((attack-info (the-as object (-> block param 1))))
           (when (!= (-> (the-as attack-info attack-info) id) (-> self incoming-attack-id))
             (set! (-> self incoming-attack-id) (-> (the-as attack-info attack-info) id))
             (let* ((attacking-proc proc)
                    (attacker (if (type? attacking-proc process-drawable)
                                  (the-as process-drawable attacking-proc)
                                  )
                              )
                    )
               (when attacker
                 (let* ((attacker-root (-> attacker root))
                        (cshape (if (type? attacker-root collide-shape)
                                    (the-as collide-shape attacker-root)
                                    )
                                )
                        )
                   (when cshape
                     (when (logtest? (-> cshape root-prim prim-core collide-as) (collide-spec projectile))
                       (when (zero? (-> self state-flip))
                         (sound-play "mtn-plat-flip1")
                         (set! (-> self state-flip) (the-as uint 1))
                         )
                       (set! (-> self hint-count) -1.0)
                       (vector-! (-> self axe-flip) (-> cshape trans) (-> self root trans))
                       (set! (-> self axe-flip y) 0.0)
                       (vector-normalize! (-> self axe-flip) 1.0)
                       (vector-rotate90-around-y! (-> self axe-flip) (-> self axe-flip))
                       (set! (-> self angle-flip-vel) -10.0)
                       (set-time! (-> self state-time))
                       )
                     )
                   )
                 )
               )
             #f
             )
           )
         )
       )
      (('hint)
       (when (>= (-> self hint-count) 0.0)
         (+! (-> self hint-count) (seconds-per-frame))
         (when (< (rand-vu-float-range 6.0 10.0) (-> self hint-count))
           (talker-spawn-func (-> *talker-speech* 56) *entity-pool* (target-pos 0) (the-as region #f))
           (set! (-> self hint-count) 0.0)
           )
         )
       )
      (('track)
       (cond
         ((-> block param 0)
          (if (zero? (-> self state-flip))
              #t
              'abort
              )
          )
         ((and *target*
               (-> self disable-track-under)
               (< (-> *target* control trans y) (+ -20480.0 (-> self root trans y)))
               )
          #f
          )
         (else
           (zero? (-> self state-flip))
           )
         )
       )
      )
    )
  :enter (behavior ()
    (let ((func (-> (method-of-type plat plat-path-active) enter)))
      (if func
          (func)
          )
      )
    (set! (-> self dest-angle) 180.0)
    (set! (-> self on-shake) #f)
    (set-time! (-> self state-time))
    )
  :trans (behavior ()
    (when (time-elapsed? (-> self state-time) (the int (-> self time-flip)))
      (set! (-> self state-flip) (the-as uint 0))
      0
      )
    (cond
      ((zero? (-> self state-flip))
       (set! (-> self on-shake) #f)
       (when (!= (-> self dest-angle) 180.0)
         (sound-play "mtn-plat-flip2")
         (set! (-> self dest-angle) 180.0)
         )
       )
      (else
        (if (!= (-> self dest-angle) 0.0)
            (set! (-> self dest-angle) 0.0)
            )
        )
      )
    (+! (-> self angle-flip-vel) (* -0.5 (seconds-per-frame) (- (-> self angle-flip) (-> self dest-angle))))
    (+! (-> self angle-flip-vel) (* -6.0 (seconds-per-frame) (-> self angle-flip-vel)))
    (+! (-> self angle-flip) (-> self angle-flip-vel))
    (quaternion-vector-angle! (-> self root quat) (-> self axe-flip) (* 182.04445 (-> self angle-flip)))
    (when (and (time-elapsed? (-> self state-time) (the int (+ -300.0 (-> self time-flip)))) (= 1 (-> self state-flip)))
      (when (not (-> self on-shake))
        (sound-play "mtn-plat-shake")
        (set! (-> self on-shake) #t)
        )
      (let ((s5-2 (new 'stack-no-clear 'vector))
            (gp-2 (new 'stack-no-clear 'quaternion))
            )
        (set-vector!
          s5-2
          (rand-vu-float-range -1.0 1.0)
          (rand-vu-float-range -1.0 1.0)
          (rand-vu-float-range -1.0 1.0)
          1.0
          )
        (vector-normalize! s5-2 1.0)
        (quaternion-vector-angle! gp-2 s5-2 1820.4445)
        (quaternion-pseudo-seek (-> self root quat) (-> self root quat) gp-2 (seconds-per-frame))
        )
      )
    (quaternion-normalize! (-> self root quat))
    (let ((func (-> (method-of-type plat plat-path-active) trans)))
      (if func
          (func)
          )
      )
    )
  :post (behavior ()
    (let ((func (-> (method-of-type plat plat-path-active) post)))
      (if func
          ((the-as (function none) func))
          )
      )
    )
  )

(set-subtask-hook!
  *game-info*
  (game-task-node canyon-insert-items-door)
  TASK_MANAGER_CODE_HOOK
  (lambda :behavior task-manager
    ()
    (let ((arrow-params (new 'stack-no-clear 'task-arrow-params)))
      (set! (-> arrow-params pos quad) (-> self info end-sphere quad))
      (quaternion-identity! (-> arrow-params quat))
      (set! (-> arrow-params flags) (task-arrow-flags))
      (set! (-> arrow-params map-icon) (the-as uint 15))
      (set! (-> self arrow) (process->handle (task-arrow-spawn arrow-params self)))
      )
    (until #f
      (let ((dist-from-target (vector-vector-distance (target-pos 0) (-> self info end-sphere))))
        (cond
          ((< dist-from-target (-> self info end-sphere r))
           (send-event (handle->process (-> self arrow)) 'leave)
           (go-virtual complete)
           )
          ((< dist-from-target (* 6.0 (-> self info end-sphere r)))
           (gui-control-method-12
             *gui-control*
             self
             (gui-channel art-load)
             (gui-action queue)
             (-> self info resolution-scene)
             0
             -99.0
             (new 'static 'sound-id)
             )
           )
          )
        )
      (suspend)
      )
    #f
    )
  )
