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

;; name: process-taskable.gc
;; name in dgo: process-taskable
;; dgos: GAME, COMMON

;; DECOMP BEGINS

;; WARN: Return type mismatch process-focusable vs process-taskable.
(defmethod relocate ((this process-taskable) (offset int))
  (if (nonzero? (-> this task))
      (&+! (-> this task) offset)
      )
  (the-as process-taskable ((method-of-type process-focusable relocate) this offset))
  )

(defbehavior process-taskable-anim-loop process-taskable ((arg0 (function process-taskable object)))
  "Takes in a function and loops as long as it's return value is truthy
   Seen take in - `true-func` which takes no args TODO - seems fishy
   - a `(process-taskable process) lambda"
  (while (arg0 self)
    (let ((s5-0 (get-art-elem self)))
      (when (!= (ja-group) s5-0)
        (ja-channel-push! 1 0)
        (set! (-> self skel root-channel 0 frame-group) (the-as art-joint-anim s5-0))
        )
      )
    (suspend)
    (if (ja-group)
        (ja :num! (loop!))
        )
    (process-taskable-method-36 self)
    )
  0
  (none)
  )

(defmethod process-taskable-method-34 ((this process-taskable))
  #t
  )

;; WARN: Return type mismatch art-joint-anim vs art-element.
(defmethod get-art-elem ((this process-taskable))
  "Checks various things such the current actor, task status, etc to determine the right art-group data to use
   @returns the appropriate [[art-element]] for the given NPC"
  (the-as art-element (if (> (-> this skel active-channels) 0)
                          (-> this skel root-channel 0 frame-group)
                          )
          )
  )

(defmethod process-taskable-method-36 ((this process-taskable))
  0
  (none)
  )

;; WARN: Return type mismatch object vs none.
(defmethod process-taskable-method-37 ((this process-taskable))
  (let ((v1-1 (-> this draw shadow-ctrl)))
    (cond
      ((and (-> this draw shadow)
            (zero? (-> this draw cur-lod))
            (logtest? (-> this draw status) (draw-control-status on-screen))
            )
       (probe-line-for-shadow v1-1 (-> this draw origin) -4096.0 4096.0 32768.0)
       )
      (else
        (logior! (-> v1-1 settings flags) (shadow-flags disable-draw))
        0
        )
      )
    )
  (none)
  )

(defstate hide (process-taskable)
  :virtual #t
  :event (behavior ((proc process) (argc int) (message symbol) (block event-message-block))
    (case message
      (('say)
       (let ((v0-0 (current-time)))
         (set! (-> self want-to-say) v0-0)
         v0-0
         )
       )
      )
    )
  :enter (behavior ()
    (set-time! (-> self state-time))
    (logior! (-> self draw status) (draw-control-status no-draw-bounds))
    (let ((v1-6 (-> self root root-prim)))
      (set! (-> v1-6 prim-core collide-as) (collide-spec))
      (set! (-> v1-6 prim-core collide-with) (collide-spec))
      )
    0
    )
  :exit (behavior ()
    (logclear! (-> self draw status) (draw-control-status no-draw-bounds))
    (let ((v1-3 (-> self root root-prim)))
      (set! (-> v1-3 prim-core collide-as) (-> self root backup-collide-as))
      (set! (-> v1-3 prim-core collide-with) (-> self root backup-collide-with))
      )
    )
  :trans (behavior ()
    (let ((v1-1 (get-current-task-event (-> self task))))
      (if (and (nonzero? (-> v1-1 action)) (or (not (logtest? (-> self draw status) (draw-control-status on-screen)))
                                               (logtest? (-> v1-1 flags) (game-task-flags gatflag-01))
                                               (not (time-elapsed? (-> self birth-time) (seconds 0.1)))
                                               )
               )
          (go-virtual idle)
          )
      )
    )
  :code sleep-code
  )

(defstate idle (process-taskable)
  :virtual #t
  :event (behavior ((proc process) (argc int) (message symbol) (block event-message-block))
    (case message
      (('attack)
       (if (-> self bounce-away)
           (send-event
             proc
             'shove
             #f
             (static-attack-info ((id (new-attack-id)) (shove-back (meters 3)) (shove-up (meters 1))))
             )
           )
       )
      (('touch)
       (send-shoves (-> self root) proc (the-as touching-shapes-entry (-> block param 0)) 0.7 6144.0 16384.0)
       )
      (('say)
       (let ((v0-0 (the-as object (current-time))))
         (set! (-> self want-to-say) (the-as time-frame v0-0))
         v0-0
         )
       )
      )
    )
  :enter (behavior ()
    (set-time! (-> self state-time))
    )
  :exit (behavior ()
    (logclear! (-> self draw status) (draw-control-status no-draw))
    )
  :trans (behavior ()
    (let ((gp-0 (get-current-task-event (-> self task))))
      (cond
        ((= (-> gp-0 action) (game-task-action hide))
         (if (or (not (logtest? (-> self draw status) (draw-control-status on-screen)))
                 (logtest? (-> gp-0 flags) (game-task-flags gatflag-01))
                 )
             (go-virtual hide)
             )
         )
        ((or (not *target*) *scene-player*)
         )
        ((not (-> self will-talk))
         (if (>= (- (-> *display* game-clock frame-counter) (-> self last-talk)) (seconds 5))
             (set! (-> self will-talk) #t)
             )
         )
        ((and (-> gp-0 scene)
              (begin
                (if (not (or (demo?)
                             (= (-> gp-0 action) (game-task-action play))
                             (-> *setting-control* user-current movie-name)
                             (name= (-> gp-0 scene) (-> *setting-control* user-current movie-name))
                             )
                         )
                    (gui-control-method-12
                      *gui-control*
                      self
                      (gui-channel art-load)
                      (gui-action queue)
                      (the-as string (-> gp-0 scene))
                      0
                      -99.0
                      (new 'static 'sound-id)
                      )
                    )
                (and (not (logtest? (focus-status dead in-air in-head pole flut tube pilot mech dark) (-> *target* focus-status)))
                     (and (or (and (< (-> (target-pos 0) y) (+ (-> self root root-prim prim-core world-sphere y) (-> self talk-height)))
                                   (let ((s5-0 (get-trans self 2))
                                         (f30-0 (if (= (-> gp-0 distance) 0.0)
                                                    (-> self talk-distance)
                                                    (-> gp-0 distance)
                                                    )
                                                )
                                         )
                                     ;; og:preserve-this added check so we don't use the wrong position for the distance check
                                     (and (not (logtest? (-> self draw status) (draw-control-status uninited)))
                                          (< (vector-vector-distance (target-pos 0) s5-0) f30-0))
                                     )
                                   )
                              (not (time-elapsed? (-> self want-to-say) (seconds 4)))
                              )
                          (or (not (load-in-progress? *level*)) (= (-> gp-0 action) (game-task-action say)))
                          (and (not (movie?))
                               (not (talker-displayed?))
                               (none-reserved? *art-control*)
                               (not *progress-process*)
                               (not (-> *setting-control* user-current movie))
                               )
                          )
                     )
                )
              )
         (when (and (or (= (-> gp-0 action) (game-task-action say))
                        (= (-> gp-0 action) (game-task-action talk))
                        (= (-> gp-0 action) (game-task-action trade))
                        (= (-> gp-0 action) (game-task-action play))
                        )
                    (process-taskable-method-34 self)
                    )
           (when (or (= (-> gp-0 action) (game-task-action say)) (not (time-elapsed? (-> self want-to-say) (seconds 4))))
             (case (-> gp-0 action)
               (((game-task-action play))
                (go-virtual play-game gp-0)
                )
               (else
                 (go-virtual active gp-0)
                 )
               )
             )
           (kill-current-talker (the-as symbol '()) '(daxter voicebox ambient) 'exit)
           (talker-surpress!)
           (when (can-display-query? self (the-as string #f) -99.0)
             (let ((s5-1
                     (new 'stack 'font-context *font-default-matrix* 32 280 0.0 (font-color default) (font-flags shadow kerning))
                     )
                   )
               (let ((v1-84 s5-1))
                 (set! (-> v1-84 width) (the float 340))
                 )
               (let ((v1-85 s5-1))
                 (set! (-> v1-85 height) (the float 80))
                 )
               (let ((v1-86 s5-1))
                 (set! (-> v1-86 scale) 0.9)
                 )
               (set! (-> s5-1 flags) (font-flags shadow kerning middle-vert large))
               (print-game-text (lookup-text! *common-text* (-> self talk-message) #f) s5-1 #f 44 (bucket-id progress))
               )
             (when (cpad-pressed? 0 triangle)
               (logclear! (-> *cpad-list* cpads 0 button0-abs 0) (pad-buttons triangle))
               (logclear! (-> *cpad-list* cpads 0 button0-rel 0) (pad-buttons triangle))
               (case (-> gp-0 action)
                 (((game-task-action play))
                  (go-virtual play-game gp-0)
                  )
                 (else
                   (go-virtual active gp-0)
                   )
                 )
               )
             )
           )
         )
        )
      )
    (process-taskable-method-37 self)
    )
  :code (behavior ()
    (process-taskable-anim-loop (the-as (function process-taskable object) true-func))
    )
  :post (behavior ()
    (if (and (-> self hide-during-movie) (movie?))
        (logior! (-> self draw status) (draw-control-status no-draw))
        (logclear! (-> self draw status) (draw-control-status no-draw))
        )
    (when (-> self look-at-me)
      ;; og:preserve-this macro
      (target-look-at-me! :trans (get-trans self 2))
      )
    (transform-post)
    )
  )

(defstate active (process-taskable)
  :virtual #t
  :event (-> (method-of-type process-taskable hide) event)
  :enter (behavior ((arg0 game-task-event))
    (set! (-> self want-to-say) 0)
    (process-entity-status! self (entity-perm-status no-kill) #t)
    (logclear! (-> self mask) (process-mask actor-pause))
    )
  :exit (behavior ()
    (set! (-> self last-talk) (-> *display* game-clock frame-counter))
    (if (not (time-elapsed? (-> self want-to-say) (seconds 4)))
        (set! (-> self will-talk) #t)
        (set! (-> self will-talk) #f)
        )
    (process-entity-status! self (entity-perm-status no-kill) #f)
    (logior! (-> self mask) (process-mask actor-pause))
    (logclear! (-> self draw status) (draw-control-status no-draw))
    (let ((v1-13 (-> self root root-prim)))
      (set! (-> v1-13 prim-core collide-as) (-> self root backup-collide-as))
      (set! (-> v1-13 prim-core collide-with) (-> self root backup-collide-with))
      )
    )
  :code (behavior ((arg0 game-task-event))
    (when (-> arg0 scene)
      (let ((gp-1 (ppointer->handle (process-spawn scene-player :init scene-player-init (-> arg0 scene) #t #f))))
        (while (and (handle->process (the-as handle gp-1)) (not (movie?)))
          (suspend)
          )
        (logior! (-> self draw status) (draw-control-status no-draw))
        (let ((v1-17 (-> self root root-prim)))
          (set! (-> v1-17 prim-core collide-as) (collide-spec))
          (set! (-> v1-17 prim-core collide-with) (collide-spec))
          )
        0
        (while (handle->process (the-as handle gp-1))
          (suspend)
          )
        )
      )
    (go-virtual hide)
    )
  )

(defstate play-game (process-taskable)
  :virtual #t
  :enter (-> (method-of-type process-taskable active) enter)
  :exit (-> (method-of-type process-taskable active) exit)
  :code (behavior ((arg0 game-task-event))
    (suspend-for (seconds 0.5))
    (go-virtual hide)
    )
  :post (-> (method-of-type process-taskable idle) post)
  )

(defmethod process-taskable-method-31 ((this process-taskable))
  (let ((s5-0 (new 'process 'collide-shape this (collide-list-enum usually-hit-by-player))))
    (let ((s4-0 (new 'process 'collide-shape-prim-group s5-0 (the-as uint 3) 0)))
      (set! (-> s5-0 total-prims) (the-as uint 4))
      (set! (-> s4-0 prim-core collide-as) (collide-spec civilian))
      (set! (-> s4-0 prim-core action) (collide-action solid no-standon))
      (set! (-> s4-0 transform-index) 0)
      (set-vector! (-> s4-0 local-sphere) 0.0 -1024.0 0.0 7372.8)
      (set! (-> s5-0 root-prim) s4-0)
      )
    (let ((v1-7 (new 'process 'collide-shape-prim-sphere s5-0 (the-as uint 0))))
      (set! (-> v1-7 prim-core collide-as) (collide-spec civilian))
      (set! (-> v1-7 prim-core action) (collide-action solid))
      (set! (-> v1-7 transform-index) 0)
      (set-vector! (-> v1-7 local-sphere) 0.0 -4096.0 0.0 4096.0)
      )
    (let ((v1-9 (new 'process 'collide-shape-prim-sphere s5-0 (the-as uint 0))))
      (set! (-> v1-9 prim-core collide-as) (collide-spec civilian))
      (set! (-> v1-9 prim-core action) (collide-action solid))
      (set! (-> v1-9 transform-index) 0)
      (set-vector! (-> v1-9 local-sphere) 0.0 -1024.0 0.0 4096.0)
      )
    (let ((v1-11 (new 'process 'collide-shape-prim-sphere s5-0 (the-as uint 0))))
      (set! (-> v1-11 prim-core collide-as) (collide-spec civilian))
      (set! (-> v1-11 prim-core action) (collide-action solid no-standon))
      (set! (-> v1-11 transform-index) 0)
      (set-vector! (-> v1-11 local-sphere) 0.0 2048.0 0.0 4096.0)
      )
    (set! (-> s5-0 nav-radius) (* 0.75 (-> s5-0 root-prim local-sphere w)))
    (let ((v1-14 (-> s5-0 root-prim)))
      (set! (-> s5-0 backup-collide-as) (-> v1-14 prim-core collide-as))
      (set! (-> s5-0 backup-collide-with) (-> v1-14 prim-core collide-with))
      )
    (set! (-> this root) s5-0)
    )
  0
  (none)
  )

(defmethod process-taskable-method-32 ((this process-taskable))
  (logior! (-> this skel status) (joint-control-status eye-anim))
  (set! (-> this talk-message) (text-id press-triangle-to-talk))
  (set! (-> this bounce-away) #t)
  (set! (-> this will-talk) #t)
  (set! (-> this look-at-me) #t)
  (set! (-> this hide-during-movie) #t)
  (set! (-> this neck-joint-index) -1)
  (set! (-> this talk-distance) (res-lump-float (-> this entity) 'distance :default 32768.0))
  (set! (-> this talk-height) (res-lump-float (-> this entity) 'height :default 8192.0))
  (set! (-> this slave) (the-as handle #f))
  (set! (-> this draw shadow-ctrl)
        (new 'process 'shadow-control 0.0 0.0 614400.0 (shadow-flags shdf02 shdf03 shdf04 disable-draw) 245760.0)
        )
  (let ((s5-0 0))
    (let ((v1-15 (the-as joint (get-art-by-name-method (-> this draw jgeo) "main" (the-as type #f)))))
      (if v1-15
          (set! s5-0 (+ (-> v1-15 number) 1))
          )
      )
    (let ((v1-19 (the-as collide-shape-prim-group (-> this root root-prim))))
      (set! (-> v1-19 transform-index) s5-0)
      (dotimes (a0-7 (the-as int (-> v1-19 num-children)))
        (set! (-> v1-19 child a0-7 transform-index) s5-0)
        )
      )
    )
  0
  (none)
  )

(defmethod init-art! ((this process-taskable))
  "@see [[initialize-skeleton]]"
  0
  (none)
  )

;; WARN: Return type mismatch object vs none.
(defmethod init-from-entity! ((this process-taskable) (arg0 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"
  (stack-size-set! (-> this main-thread) 512)
  (process-taskable-method-31 this)
  (process-drawable-from-entity! this arg0)
  (set! (-> this task)
        (new 'process 'game-task-control (res-lump-value arg0 'task-actor game-task-actor :time -1000000000.0))
        )
  (init-art! this)
  (process-taskable-method-32 this)
  (when (logtest? #x1000000 (res-lump-value arg0 'options uint128 :time -1000000000.0))
    (let* ((s5-1 *level*)
           (s4-2 (method-of-object s5-1 art-group-get-by-name))
           )
      (format (clear *temp-string*) "skel-~S" (-> this draw art-group name))
      (let ((s4-3 (s4-2 s5-1 *temp-string* (the-as (pointer uint32) #f))))
        (when s4-3
          (let ((s5-2 (process-spawn manipy :init manipy-init (-> this root trans) (-> this entity) s4-3 #f 0 :to this)))
            (send-event (ppointer->process s5-2) 'anim-mode 'mirror)
            (send-event (ppointer->process s5-2) 'mirror #t)
            )
          )
        )
      )
    )
  (set! (-> this event-hook) (-> (method-of-object this idle) event))
  (go (method-of-object this hide))
  (none)
  )
