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

;; name: smush-control-h.gc
;; name in dgo: smush-control-h
;; dgos: GAME

;; DECOMP BEGINS

(deftype smush-control (structure)
  "This holds information about the current state of an object's smush."
  ((start-time   time-frame)
   (period       float)
   (duration     float)
   (amp          float)
   (damp-amp     float)
   (damp-period  float)
   (ticks        float)
   )
  (:methods
    (set-zero! (_type_) _type_)
    (update! (_type_) float)
    (get-no-update (_type_) float)
    (activate! (_type_ float int int float float clock) _type_)
    (nonzero-amplitude? (_type_) symbol)
    (die-on-next-update! (_type_) _type_)
    )
  )


(defmethod nonzero-amplitude? ((this smush-control))
  "Is the smush currently active?"
  (!= (-> this amp) 0.0)
  )

(defmethod set-zero! ((this smush-control))
  "Reset this [[smush-control]]."
  (set! (-> this period) 0.0)
  (set! (-> this duration) 0.0)
  (set! (-> this amp) 0.0)
  (set! (-> this damp-amp) 0.0)
  (set! (-> this damp-period) 0.0)
  (set! (-> this ticks) 0.0)
  this
  )

(defmethod update! ((this smush-control))
  "Calculate the next smush amplitude and update the smush state."
  (cond
    ((!= (-> this amp) 0.0)
     (let* ((elapsed-time (the float (- (current-time) (-> this start-time))))
            (period (-> this period))
            (f28-0 (- elapsed-time (* (the float (the int (/ elapsed-time period))) period)))
            )
       (when (>= (- elapsed-time (-> this ticks)) (-> this period))
         (set! (-> this amp) (* (-> this amp) (-> this damp-amp)))
         (set! (-> this period) (* (-> this period) (-> this damp-period)))
         (set! (-> this ticks) elapsed-time)
         (if (< (-> this damp-period) 0.0)
             (set-zero! this)
             )
         )
       (if (>= elapsed-time (-> this duration))
           (set-zero! this)
           )
       (* (sin (/ (* 65536.0 f28-0) (-> this period)))
          (* (-> this amp) (/ (- (-> this duration) elapsed-time) (-> this duration)))
          )
       )
     )
    (else
      0.0
      )
    )
  )

(defmethod get-no-update ((this smush-control))
  "Get the next amplitude, but do not update the smush state."
  (cond
    ((!= (-> this amp) 0.0)
     (let* ((elapsed-time (the float (- (current-time) (-> this start-time))))
            (period (-> this period))
            (f0-4 (- elapsed-time (* (the float (the int (/ elapsed-time period))) period)))
            )
       (* (sin (/ (* 65536.0 f0-4) (-> this period)))
          (* (-> this amp) (/ (- (-> this duration) elapsed-time) (-> this duration)))
          )
       )
     )
    (else
      0.0
      )
    )
  )

(defmethod die-on-next-update! ((this smush-control))
  "Set the dampening period so the smush stops on the next update."
  (if (!= (-> this amp) 0.0)
      (set! (-> this damp-period) -1.0)
      )
  this
  )

(defmethod activate! ((this smush-control)
                     (amplitude float)
                     (period int)
                     (duration int)
                     (damp-amplitude float)
                     (damp-period float)
                     (clock clock)
                     )
  "Start the smush with the given parameters."
  (when (>= (fabs (/ (-> this amp) 5)) (fabs (get-no-update this)))
    (set! (-> this amp) amplitude)
    (set! (-> this period) (the float period))
    (set! (-> this duration) (the float duration))
    (set! (-> this damp-amp) damp-amplitude)
    (set! (-> this damp-period) damp-period)
    (set! (-> this ticks) 0.0)
    (set! (-> this start-time) (-> clock frame-counter))
    )
  this
  )
