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

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

;; DECOMP BEGINS

(defun can-display-query? ((arg0 process) (arg1 string) (arg2 float))
  (let ((a1-2 (gui-control-method-12
                *gui-control*
                arg0
                (gui-channel query)
                (gui-action play)
                (if arg1
                    arg1
                    (symbol->string (-> arg0 type symbol))
                    )
                0
                arg2
                (new 'static 'sound-id)
                )
              )
        )
    (= (get-status *gui-control* a1-2) (gui-status active))
    )
  )

(defun talker-surpress! ()
  (set! (-> *game-info* hint-play-time) (-> *display* base-clock frame-counter))
  0
  )

(defun talker-displayed? ()
  (if (-> *setting-control* user-current hint)
      #t
      #f
      )
  )

(defun kill-current-talker ((arg0 pair) (arg1 pair) (arg2 symbol))
  (if (not (member 'daxter arg1))
      (set-action!
        *gui-control*
        (gui-action stop)
        (the-as sound-id 1)
        (gui-channel daxter)
        (gui-action none)
        (the-as string #f)
        (the-as (function gui-connection symbol) #f)
        (the-as process #f)
        )
      )
  (if (not (member 'pecker arg1))
      (set-action!
        *gui-control*
        (gui-action stop)
        (the-as sound-id 1)
        (gui-channel pecker)
        (gui-action none)
        (the-as string #f)
        (the-as (function gui-connection symbol) #f)
        (the-as process #f)
        )
      )
  (if (not (member 'voicebox arg1))
      (set-action!
        *gui-control*
        (gui-action stop)
        (the-as sound-id 1)
        (gui-channel voicebox)
        (gui-action none)
        (the-as string #f)
        (the-as (function gui-connection symbol) #f)
        (the-as process #f)
        )
      )
  (if (not (member 'message arg1))
      (set-action!
        *gui-control*
        (gui-action stop)
        (the-as sound-id 1)
        (gui-channel message)
        (gui-action none)
        (the-as string #f)
        (the-as (function gui-connection symbol) #f)
        (the-as process #f)
        )
      )
  (when (not (member 'notice arg1))
    (set-action!
      *gui-control*
      (gui-action stop)
      (the-as sound-id 1)
      (gui-channel notice)
      (gui-action none)
      (the-as string #f)
      (the-as (function gui-connection symbol) #f)
      (the-as process #f)
      )
    (set-action!
      *gui-control*
      (gui-action stop)
      (the-as sound-id 1)
      (gui-channel notice-low)
      (gui-action none)
      (the-as string #f)
      (the-as (function gui-connection symbol) #f)
      (the-as process #f)
      )
    )
  0
  (none)
  )

(defun string->talker-speech ((arg0 string))
  (dotimes (s5-0 365)
    (let ((s4-0 (-> *talker-speech* s5-0)))
      (if (string= arg0 (-> s4-0 name))
          (return s4-0)
          )
      )
    )
  (-> *talker-speech* 0)
  )

(defmethod should-play? ((this talker-speech-class))
  "Return if the talker is in a state where it should play."
  (and (>= (-> *game-info* talker-state (* (-> this speech) 2)) (-> this pos))
       (>= (-> this neg) (-> *game-info* talker-state (+ (* (-> this speech) 2) 1)))
       )
  )

(defmethod mark-played! ((this talker-speech-class))
  "Mark something as played by making its state UINT16_MAX"
  (set! (-> *game-info* talker-state (+ (* (-> this speech) 2) 1)) (the-as uint #xffff))
  0
  (none)
  )

(defmethod reset-state! ((this talker-speech-class))
  "Reset the state of this talker to 0 (the initial value)"
  (set! (-> *game-info* talker-state (+ (* (-> this speech) 2) 1)) (the-as uint 0))
  0
  (none)
  )

(defmethod yes-play! ((this talker-speech-class) (arg0 int))
  (if (>= arg0 0)
      (set! (-> *game-info* talker-state (* (-> this speech) 2))
            (the-as uint (seekl (the-as int (-> *game-info* talker-state (* (-> this speech) 2))) #xfff0 arg0))
            )
      (set! (-> *game-info* talker-state (* (-> this speech) 2))
            (the-as uint (seekl (the-as int (-> *game-info* talker-state (* (-> this speech) 2))) 0 (- arg0)))
            )
      )
  (if (should-play? this)
      (talker-spawn-func this *entity-pool* (target-pos 0) (the-as region #f))
      )
  0
  (none)
  )

(defmethod no-play! ((this talker-speech-class) (arg0 int))
  (if (>= arg0 0)
      (set! (-> *game-info* talker-state (+ (* (-> this speech) 2) 1))
            (the-as uint (seekl (the-as int (-> *game-info* talker-state (+ (* (-> this speech) 2) 1))) #xfff0 arg0))
            )
      (set! (-> *game-info* talker-state (+ (* (-> this speech) 2) 1))
            (the-as uint (seekl (the-as int (-> *game-info* talker-state (+ (* (-> this speech) 2) 1))) 0 (- arg0)))
            )
      )
  0
  (none)
  )

;; WARN: Return type mismatch int vs sound-id.
(defun talker-spawn-func ((arg0 talker-speech-class) (arg1 process-tree) (arg2 vector) (arg3 region))
  (local-vars (s2-0 int))
  (when (or (not arg0) (zero? (-> arg0 speech)) (not (should-play? arg0)))
    (set! s2-0 0)
    (goto cfg-27)
    )
  (if (and (or (not (-> *setting-control* user-current play-hints))
               (= (-> *setting-control* user-current dialog-volume) 0.0)
               )
           (logtest? (-> arg0 flags) (talker-flags play-only-once))
           )
      (mark-played! arg0)
      )
  (set! s2-0
        (the-as int (lookup-gui-connection-id *gui-control* (-> arg0 name) (-> arg0 channel) (gui-action none)))
        )
  (set! s2-0 (cond
               ((zero? (the-as sound-id s2-0))
                (let ((v1-17 (process-spawn talker :init talker-init arg0 arg2 arg3 :name "talker" :to arg1)))
                  (cond
                    (v1-17
                      (if (nonzero? (-> (the-as talker (-> v1-17 0)) voice-id))
                          (the-as int (-> (the-as talker (-> v1-17 0)) voice-id))
                          (the-as int (-> (the-as talker (-> v1-17 0)) message-id))
                          )
                      )
                    (else
                      (empty)
                      s2-0
                      )
                    )
                  )
                )
               (else
                 (empty)
                 s2-0
                 )
               )
        )
  (label cfg-27)
  (the-as sound-id s2-0)
  )

(defbehavior talker-init talker ((arg0 talker-speech-class) (arg1 vector) (arg2 region))
  (vector-copy! (-> self trans) arg1)
  (let ((v1-2 (shr (the-as int (-> arg0 channel)) 4)))
    (when (not (or (or (= v1-2 4) (= v1-2 5))
                   (or (not (-> *setting-control* user-current play-hints))
                       (= (-> *setting-control* user-current dialog-volume) 0.0)
                       )
                   )
               )
      (set! (-> self voice-id)
            (add-process *gui-control* self (-> arg0 channel) (gui-action queue) (-> arg0 name) 81920.0 0)
            )
      (sound-params-set!
        *gui-control*
        (-> self voice-id)
        #f
        -1
        -1
        -1
        (-> *setting-control* user-current talker-volume)
        )
      )
    )
  (when (nonzero? (-> arg0 text-message))
    (let* ((a0-7 *gui-control*)
           (t9-2 (method-of-object a0-7 add-process))
           (a1-4 self)
           (v1-18 (shr (the-as int (-> arg0 channel)) 4))
           )
      (set! (-> self message-id) (t9-2
                                   a0-7
                                   a1-4
                                   (if (or (= v1-18 4) (= v1-18 5))
                                       (the-as gui-channel (the-as int (-> arg0 channel)))
                                       (gui-channel message)
                                       )
                                   (gui-action play)
                                   (-> arg0 name)
                                   81920.0
                                   0
                                   )
            )
      )
    )
  (set! (-> self message) arg0)
  (set! (-> self region) arg2)
  (set! (-> self total-time) 0)
  (set! (-> self total-off-time) 0)
  (set-time! (-> self start-time))
  (set! (-> self voicebox) (the-as handle #f))
  (set! (-> self save?) #f)
  (set! (-> self grab?) #f)
  (if (logtest? (-> self message flags) (talker-flags fade-in slide-in))
      (set! (-> self interp) 0.0)
      (set! (-> self interp) 1.0)
      )
  (go-virtual idle)
  0
  (none)
  )

(defmethod deactivate ((this talker))
  "Make a process dead, clean it up, remove it from the active pool, and return to dead pool."
  (send-event (handle->process (-> this voicebox)) 'die)
  (call-parent-method this)
  (none)
  )

(defmethod draw-text ((this talker))
  (let ((gp-0
          (new 'stack 'font-context *font-default-matrix* 36 310 0.0 (font-color default) (font-flags shadow kerning))
          )
        )
    (let ((f0-0 320.0))
      (set-scale! gp-0 0.75)
      (case (-> this message channel)
        (((gui-channel notice))
         (cond
           ((logtest? (-> this message flags) (talker-flags bigger-font))
            (set-origin! gp-0 36 140)
            )
           (else
             (set-scale! gp-0 0.6)
             (set-origin! gp-0 36 160)
             )
           )
         (set! f0-0 160.0)
         )
        )
      (set-width! gp-0 440)
      (set-height! gp-0 140)
      (set! (-> gp-0 flags) (font-flags shadow kerning middle large))
      (if (logtest? (-> this message flags) (talker-flags fade-in))
          (set! (-> gp-0 alpha) (-> this interp))
          (set! (-> gp-0 alpha) 1.0)
          )
      (if (logtest? (-> this message flags) (talker-flags slide-in))
          (set-origin! gp-0 36 (the int (lerp-scale 400.0 f0-0 (-> this interp) 0.0 1.0)))
          )
      )
    (let ((f0-17 (print-game-text
                   (lookup-text! *common-text* (-> this message text-message) #f)
                   gp-0
                   #t
                   44
                   (bucket-id hud-draw-hud-alpha)
                   )
                 )
          )
      (if (< 98.0 f0-17)
          (set-scale! gp-0 0.6)
          )
      )
    (let ((s4-2 print-game-text)
          (a0-14 (lookup-text! *common-text* (-> this message text-message) #f))
          (a2-5 #f)
          (a3-3 44)
          (v1-36 (-> this message channel))
          )
      (s4-2
        a0-14
        gp-0
        a2-5
        a3-3
        (if (or (= v1-36 (gui-channel notice)) (= v1-36 (gui-channel notice-low)) (= v1-36 (gui-channel subtitle)))
            (bucket-id hud-draw-pris2)
            (bucket-id hud-draw-hud-alpha)
            )
        )
      )
    )
  0
  (none)
  )

(defstate idle (talker)
  :virtual #t
  :code (behavior ()
    (suspend-for (the-as time-frame (-> self message delay))
      )
    (while (or (not (time-elapsed? (-> self start-time) (the-as time-frame (+ (-> self message delay) 300))))
               (and (logtest? (-> self message flags) (talker-flags long-timeout))
                    (not (time-elapsed? (-> self start-time) (seconds 180)))
                    )
               )
      (when (and (or (zero? (-> self voice-id)) (= (get-status *gui-control* (-> self voice-id)) (gui-status ready)))
                 (or (zero? (-> self message-id)) (= (get-status *gui-control* (-> self message-id)) (gui-status active)))
                 )
        (case (-> self message channel)
          (((gui-channel voicebox))
           (if (and (not (handle->process (-> self voicebox))) *target*)
               (set! (-> self voicebox) (ppointer->handle (voicebox-spawn *target* (target-pos 0))))
               )
           )
          )
        (go-virtual active)
        )
      (suspend)
      )
    (go-virtual exit)
    )
  )

(defstate active (talker)
  :virtual #t
  :enter (behavior ()
    (set-time! (-> self state-time))
    (if (logtest? (-> self message flags) (talker-flags play-only-once))
        (mark-played! (-> self message))
        )
    (set-setting! 'hint (process->ppointer self) 0.0 0)
    (set-setting! 'speech-control #f 0.0 0)
    (if (nonzero? (-> self voice-id))
        (set-action!
          *gui-control*
          (gui-action play)
          (-> self voice-id)
          (gui-channel none)
          (gui-action none)
          (the-as string #f)
          (the-as (function gui-connection symbol) #f)
          (the-as process #f)
          )
        )
    (when (and (nonzero? (-> self voice-id)) (logtest? (-> self message flags) (talker-flags reduce-volume)))
      (add-setting! 'music-volume 'rel 0.25 0)
      (add-setting! 'sfx-volume 'rel 0.75 0)
      (add-setting! 'dialog-volume 'rel (-> *setting-control* user-current dialog-volume-talker) 0)
      )
    (if (logtest? (-> self message flags) (talker-flags auto-save-on-each-start))
        (auto-save-user)
        )
    (apply-settings *setting-control*)
    )
  :exit (behavior ()
    (if (and (-> self grab?) *target*)
        (process-release? *target*)
        )
    (let ((gp-0 (-> self message on-close)))
      (when gp-0
        (let ((v1-9 (as-type (handle->process (-> self voicebox)) process-drawable)))
          (script-eval gp-0 :vector (if v1-9
                                        (-> (the-as process-drawable v1-9) root trans)
                                        )
                       )
          )
        )
      )
    (when (and (logtest? (-> self message flags) (talker-flags auto-save-once-on-exit)) (not (-> self save?)))
      (set! (-> self save?) #t)
      (auto-save-user)
      )
    (if (nonzero? (-> self voice-id))
        (set-action!
          *gui-control*
          (gui-action stop)
          (-> self voice-id)
          (gui-channel none)
          (gui-action none)
          (the-as string #f)
          (the-as (function gui-connection symbol) #f)
          (the-as process #f)
          )
        )
    (if (nonzero? (-> self message-id))
        (set-action!
          *gui-control*
          (gui-action stop)
          (-> self message-id)
          (gui-channel none)
          (gui-action none)
          (the-as string #f)
          (the-as (function gui-connection symbol) #f)
          (the-as process #f)
          )
        )
    (remove-setting! 'music-volume)
    (remove-setting! 'sfx-volume)
    (remove-setting! 'dialog-volume)
    (remove-setting! 'hint)
    (remove-setting! 'speech-control)
    (remove-setting! 'camera-name)
    (apply-settings *setting-control*)
    )
  :code (behavior ()
    (local-vars (v1-50 symbol))
    (let ((gp-0 #t))
      (while (or (and (nonzero? (-> self voice-id))
                      (let ((v1-41 (get-status *gui-control* (-> self voice-id))))
                        (or (= v1-41 (gui-status ready)) (= v1-41 (gui-status active)))
                        )
                      (begin
                        (dotimes (s5-2 4)
                          (when (and (string-charp= (-> self message name) (-> *sound-iop-info* stream-name s5-2 name))
                                     (= (-> self voice-id) (-> *sound-iop-info* stream-id s5-2))
                                     (logtest? (-> *sound-iop-info* stream-status s5-2) (stream-status ss6))
                                     )
                            (set! v1-50 #f)
                            (goto cfg-47)
                            )
                          )
                        (set! v1-50 #t)
                        (label cfg-47)
                        (and v1-50 (not (time-elapsed? (-> self state-time) (seconds 120))))
                        )
                      )
                 (and (nonzero? (-> self message-id))
                      (= (get-status *gui-control* (-> self message-id)) (gui-status active))
                      (or (not (time-elapsed? (-> self state-time) (the-as time-frame (-> self message text-duration))))
                          (and (logtest? (-> self message flags) (talker-flags only-play-in-region))
                               (-> self region)
                               (point-in-region-debug! (-> self region) (target-pos 0))
                               )
                          )
                      )
                 (not (time-elapsed? (-> self state-time) (seconds 0.05)))
                 )
        (when (and (nonzero? (-> self voice-id)) (not gp-0) (zero? (get-status *gui-control* (-> self voice-id))))
          (remove-setting! 'music-volume)
          (remove-setting! 'sfx-volume)
          (remove-setting! 'dialog-volume)
          (set! gp-0 #t)
          )
        (when (and (-> self message camera) (not (-> self grab?)) *target*)
          (when (process-grab? *target* #f)
            (set! (-> self grab?) #t)
            (set-setting! 'entity-name (-> self message camera) 0.0 0)
            )
          )
        (when (and (nonzero? (-> self message-id))
                   (= (get-status *gui-control* (-> self message-id)) (gui-status active))
                   (not (paused?))
                   )
          (if (logtest? (-> self message flags) (talker-flags fade-in))
              (seek! (-> self interp) 1.0 (* 0.5 (seconds-per-frame)))
              (seek! (-> self interp) 1.0 (* 4.0 (seconds-per-frame)))
              )
          (draw-text self)
          )
        (suspend)
        )
      )
    (when (and (nonzero? (-> self message-id)) (logtest? (-> self message flags) (talker-flags fade-in slide-in)))
      (while (!= (-> self interp) 0.0)
        (if (logtest? (-> self message flags) (talker-flags fade-in))
            (seek! (-> self interp) 0.0 (* 0.5 (seconds-per-frame)))
            (seek! (-> self interp) 0.0 (* 4.0 (seconds-per-frame)))
            )
        (if (and (= (get-status *gui-control* (-> self message-id)) (gui-status active)) (not (paused?)))
            (draw-text self)
            )
        (suspend)
        )
      )
    (when (and (logtest? (-> self message flags) (talker-flags auto-save-once-on-exit)) (not (-> self save?)))
      (suspend-for (seconds 1)
        )
      (set! (-> self save?) #t)
      (auto-save-user)
      )
    (go-virtual exit)
    )
  )

(defstate exit (talker)
  :virtual #t
  :code nothing
  )
