;;-*-Lisp-*-
(in-package goal)
(bundles "ENGINE.CGO" "GAME.CGO")
(require "engine/game/projectiles-h.gc")
(require "engine/physics/dynamics-h.gc")
(require "engine/gfx/mood/weather-part.gc")
(require "engine/anim/joint-mod-h.gc")
(require "engine/collide/collide-mesh-h.gc")
(require "engine/camera/camera.gc")

;; TODO - for basebutton

;; Needed here
(define-extern camera-master-debug (function camera-master none))

;; DECOMP BEGINS

(deftype camera-master-bank (basic)
  ((onscreen-head-height            meters)
   (onscreen-foot-height            meters)
   (target-height                   meters)
   (up-move-to-pitch-ratio-in-air   float)
   (down-move-to-pitch-ratio-in-air float)
   (up-move-to-pitch-on-ground      float)
   (down-move-to-pitch-on-ground    float)
   (pitch-off-blend                 float)))


(define *CAMERA_MASTER-bank*
  (new 'static
       'camera-master-bank
       :onscreen-head-height (meters 2.65)
       :onscreen-foot-height (meters -0.5)
       :target-height (meters 2.15)
       :up-move-to-pitch-ratio-in-air 1.0
       :down-move-to-pitch-ratio-in-air 0.5
       :up-move-to-pitch-on-ground 0.9
       :down-move-to-pitch-on-ground 0.9
       :pitch-off-blend 0.5))

(defbehavior reset-follow camera-master ()
  (set! (-> self tpos-old quad) (-> (target-cam-pos) quad))
  (set! (-> self tpos-curr quad) (-> self tpos-old quad))
  (set! (-> self tpos-old-adj quad) (-> self tpos-old quad))
  (set! (-> self tpos-curr-adj quad) (-> self tpos-old quad))
  (set! (-> self tpos-tgt quad) (-> self tpos-old quad))
  (set! (-> self upspeed) 0.0))

(defbehavior reset-target-tracking camera-master ()
  (set! (-> self tpos-old quad) (-> (target-cam-pos) quad))
  (set! (-> self tpos-curr quad) (-> self tpos-old quad))
  (set! (-> self tpos-old-adj quad) (-> self tpos-old quad))
  (set! (-> self tpos-curr-adj quad) (-> self tpos-old quad))
  (set! (-> self tpos-tgt quad) (-> self tpos-old quad))
  (quaternion->matrix (-> self tgt-rot-mat) (-> *target* control dir-targ))
  (quaternion->matrix (-> self tgt-face-mat) (-> *target* control unknown-quaternion00))
  (vector-reset! (-> self pitch-off))
  (set! (-> self upspeed) 0.0)
  (set! (-> self foot-offset) (-> *CAMERA_MASTER-bank* onscreen-foot-height))
  (set! (-> self head-offset) (-> *CAMERA_MASTER-bank* onscreen-head-height))
  (set! (-> self target-height) (-> *CAMERA_MASTER-bank* target-height))
  (set! (-> self on-ground)
        (not (and (logtest? (-> *target* control unknown-surface00 flags) (surface-flags jump))
                  (not (logtest? (-> *target* control status) (cshape-moving-flags onsurf))))))
  (set! (-> self on-pole) #f)
  (set! (-> self ease-t) 1.0)
  (set! (-> self string-max target y) (-> self stringMaxHeight))
  (set! (-> self string-max target z) (-> self stringMaxLength))
  (set! (-> self string-push-z) (fmax (-> self string-min value z) (-> *CAMERA-bank* default-string-push-z)))
  (cond
    ((time-elapsed? (the-as time-frame (if *target* (the-as int (-> *target* neck notice-time)) 0))
                    (-> *CAMERA-bank* attack-timeout))
     (set! (-> self being-attacked) #f))
    (else
     (set-time! (-> self attack-start))
     (set! (-> self being-attacked) #t)
     (when (and (not (logtest? (-> self master-options) 64))
                (or (!= (-> last-try-to-look-at-data horz) 0.0) (!= (-> last-try-to-look-at-data vert) 0.0)))
       (set! (-> self string-max target y) (fmax (-> self string-max target y) (-> last-try-to-look-at-data vert)))
       (set! (-> self string-max target z) (fmax (-> self string-max target z) (-> last-try-to-look-at-data horz)))
       (set! (-> self string-push-z) (fmax (-> self string-push-z) (-> self string-max target z))))))
  (cond
    ((and (logtest? (-> *target* water flags) (water-flags wt12))
          (not (logtest? (-> *target* water flags) (water-flags wt04))))
     (set! (-> self under-water) 2))
    (else (set! (-> self under-water) 0) 0))
  (let ((gp-1 (new 'stack-no-clear 'vector)))
    (vector--float*! gp-1 (-> self tpos-curr-adj) (-> self local-down) (-> self target-height))
    (the-as symbol (tracking-spline-method-10 (-> self target-spline) gp-1))))

(defbehavior reset-drawable-follow camera-master ()
  (let ((v1-2 (the-as target (-> self drawable-target process 0))))
    (if (nonzero? (-> v1-2 node-list))
      (vector<-cspace! (-> self tpos-old) (-> v1-2 node-list data (-> self which-bone)))
      (set! (-> self tpos-old quad) (-> v1-2 control trans quad))))
  (set! (-> self tpos-curr quad) (-> self tpos-old quad))
  (set! (-> self tpos-old-adj quad) (-> self tpos-old quad))
  (set! (-> self tpos-curr-adj quad) (-> self tpos-old quad))
  (set! (-> self upspeed) 0.0))

(defbehavior reset-drawable-tracking camera-master ()
  (let ((gp-0 (the-as target (-> self drawable-target process 0))))
    (cond
      ((nonzero? (-> gp-0 node-list))
       (vector<-cspace! (-> self tpos-old) (-> gp-0 node-list data (-> self which-bone)))
       (let* ((v1-6 (-> self tgt-rot-mat))
              (a3-0 (-> gp-0 node-list data (-> self which-bone) bone transform))
              (a0-4 (-> a3-0 vector 0 quad))
              (a1-4 (-> a3-0 vector 1 quad))
              (a2-0 (-> a3-0 vector 2 quad))
              (a3-1 (-> a3-0 vector 3 quad)))
         (set! (-> v1-6 vector 0 quad) a0-4)
         (set! (-> v1-6 vector 1 quad) a1-4)
         (set! (-> v1-6 vector 2 quad) a2-0)
         (set! (-> v1-6 vector 3 quad) a3-1))
       (set! (-> self tgt-rot-mat vector 3 quad) (the-as uint128 0))
       (let* ((v1-8 (-> self tgt-face-mat))
              (a3-2 (-> self tgt-rot-mat))
              (a0-5 (-> a3-2 vector 0 quad))
              (a1-5 (-> a3-2 vector 1 quad))
              (a2-1 (-> a3-2 vector 2 quad))
              (a3-3 (-> a3-2 vector 3 quad)))
         (set! (-> v1-8 vector 0 quad) a0-5)
         (set! (-> v1-8 vector 1 quad) a1-5)
         (set! (-> v1-8 vector 2 quad) a2-1)
         (set! (-> v1-8 vector 3 quad) a3-3)))
      (else
       (set! (-> self tpos-old quad) (-> gp-0 control trans quad))
       (quaternion->matrix (-> self tgt-rot-mat) (-> gp-0 control quat))
       (let* ((v1-11 (-> self tgt-face-mat))
              (a3-4 (-> self tgt-rot-mat))
              (a0-10 (-> a3-4 vector 0 quad))
              (a1-7 (-> a3-4 vector 1 quad))
              (a2-2 (-> a3-4 vector 2 quad))
              (a3-5 (-> a3-4 vector 3 quad)))
         (set! (-> v1-11 vector 0 quad) a0-10)
         (set! (-> v1-11 vector 1 quad) a1-7)
         (set! (-> v1-11 vector 2 quad) a2-2)
         (set! (-> v1-11 vector 3 quad) a3-5)))))
  (set! (-> self tpos-curr quad) (-> self tpos-old quad))
  (set! (-> self tpos-old-adj quad) (-> self tpos-old quad))
  (set! (-> self tpos-curr-adj quad) (-> self tpos-old quad))
  (vector-reset! (-> self pitch-off))
  (set! (-> self upspeed) 0.0)
  (set! (-> self foot-offset) (-> *CAMERA_MASTER-bank* onscreen-foot-height))
  (set! (-> self head-offset) (-> *CAMERA_MASTER-bank* onscreen-head-height))
  (set! (-> self target-height) (-> *CAMERA_MASTER-bank* target-height))
  (set! (-> self on-ground) #t)
  (set! (-> self on-pole) #f)
  (set! (-> self ease-t) 1.0)
  (set! (-> self being-attacked) #f)
  (set! (-> self string-max target y) (-> self stringMaxHeight))
  (set! (-> self string-max target z) (-> self stringMaxLength))
  (set! (-> self string-push-z) (fmax (-> self string-min value z) (-> *CAMERA-bank* default-string-push-z)))
  (set! (-> self under-water) 0)
  (let ((gp-1 (new 'stack-no-clear 'vector)))
    (vector--float*! gp-1 (-> self tpos-curr-adj) (-> self local-down) (-> self target-height))
    (the-as symbol (tracking-spline-method-10 (-> self target-spline) gp-1))))

(defbehavior master-track-target camera-master ()
  (cond
    ((and (logtest? (-> self master-options) 2)
          (!= (-> self drawable-target) #f)
          (not (handle->process (-> self drawable-target))))
     (logand! (-> self master-options) -3)
     (set! (-> self drawable-target) (the-as handle #f)))
    ((and (logtest? (-> self master-options) 2) (handle->process (-> self drawable-target)))
     (let ((gp-0 (-> self drawable-target process 0)))
       (if (paused?) (return (the-as symbol #f)))
       (set! (-> self tpos-old quad) (-> self tpos-curr quad))
       (set! (-> self tpos-old-adj quad) (-> self tpos-curr-adj quad))
       (cond
         ((nonzero? (-> (the-as target gp-0) node-list))
          (let* ((v1-24 (-> self tgt-rot-mat))
                 (a3-0 (-> (the-as target gp-0) node-list data (-> self which-bone) bone transform))
                 (a0-17 (-> a3-0 vector 0 quad))
                 (a1-4 (-> a3-0 vector 1 quad))
                 (a2-0 (-> a3-0 vector 2 quad))
                 (a3-1 (-> a3-0 vector 3 quad)))
            (set! (-> v1-24 vector 0 quad) a0-17)
            (set! (-> v1-24 vector 1 quad) a1-4)
            (set! (-> v1-24 vector 2 quad) a2-0)
            (set! (-> v1-24 vector 3 quad) a3-1))
          (set! (-> self tgt-rot-mat vector 3 quad) (the-as uint128 0))
          (let* ((a2-1 (-> self tgt-face-mat))
                 (a3-2 (-> self tgt-rot-mat))
                 (v1-26 (-> a3-2 vector 0 quad))
                 (a0-18 (-> a3-2 vector 1 quad))
                 (a1-5 (-> a3-2 vector 2 quad))
                 (a3-3 (-> a3-2 vector 3 quad)))
            (set! (-> a2-1 vector 0 quad) v1-26)
            (set! (-> a2-1 vector 1 quad) a0-18)
            (set! (-> a2-1 vector 2 quad) a1-5)
            (set! (-> a2-1 vector 3 quad) a3-3))
          (vector<-cspace! (-> self tpos-curr) (-> (the-as target gp-0) node-list data (-> self which-bone))))
         (else
          (quaternion->matrix (-> self tgt-rot-mat) (-> (the-as target gp-0) control quat))
          (let* ((a2-3 (-> self tgt-face-mat))
                 (a3-4 (-> self tgt-rot-mat))
                 (v1-31 (-> a3-4 vector 0 quad))
                 (a0-21 (-> a3-4 vector 1 quad))
                 (a1-9 (-> a3-4 vector 2 quad))
                 (a3-5 (-> a3-4 vector 3 quad)))
            (set! (-> a2-3 vector 0 quad) v1-31)
            (set! (-> a2-3 vector 1 quad) a0-21)
            (set! (-> a2-3 vector 2 quad) a1-9)
            (set! (-> a2-3 vector 3 quad) a3-5)))))
     (let ((v1-32 (new-stack-vector0)))
       0.0
       (vector-! v1-32 (-> self tpos-curr-adj) (-> self tpos-curr))
       (let* ((f0-2 (vector-dot v1-32 (-> self local-down)))
              (f0-3 (if (< 0.0 f0-2)
                      (* f0-2 (-> *CAMERA_MASTER-bank* up-move-to-pitch-on-ground))
                      (* f0-2 (-> *CAMERA_MASTER-bank* down-move-to-pitch-on-ground)))))
         (vector+float*! (-> self tpos-curr-adj) (-> self tpos-curr) (-> self local-down) f0-3)))
     (let ((gp-1 (new 'stack-no-clear 'vector)))
       (vector--float*! gp-1 (-> self tpos-curr-adj) (-> self local-down) (-> self target-height))
       (tracking-spline-method-17 (-> self target-spline) gp-1 2048.0 0.0 #f))
     (tracking-spline-method-22 (-> self target-spline) 40960.0))
    ((handle->process (-> self drawable-target)) (logior! (-> self master-options) 2) (reset-drawable-tracking)))
  (the-as symbol
          (cond
            ((handle->process (-> self drawable-target)) #f)
            ((and *target* (logtest? (-> self master-options) 2))
             (if (paused?) (return (the-as symbol #f)))
             (cond
               ((time-elapsed? (the-as time-frame (if *target* (the-as int (-> *target* neck notice-time)) 0))
                               (-> *CAMERA-bank* attack-timeout))
                (set! (-> self being-attacked) #f))
               (else
                (if (not (-> self being-attacked)) (set-time! (-> self attack-start)))
                (set! (-> self being-attacked) #t)
                (when (and (not (logtest? (-> self master-options) 64))
                           (or (!= (-> last-try-to-look-at-data horz) 0.0) (!= (-> last-try-to-look-at-data vert) 0.0)))
                  (set! (-> self string-max target y) (fmax (-> self string-max target y) (-> last-try-to-look-at-data vert)))
                  (set! (-> self string-max target z) (fmax (-> self string-max target z) (-> last-try-to-look-at-data horz)))
                  (set! (-> self string-push-z) (fmax (-> self string-push-z) (-> self string-max target z))))))
             (cond
               ((and (logtest? (-> *target* water flags) (water-flags wt12))
                     (not (logtest? (-> *target* water flags) (water-flags wt04))))
                (set! (-> self under-water) 2))
               ((> (-> self under-water) 0) (+! (-> self under-water) -1)))
             (set! (-> self tpos-old quad) (-> self tpos-curr quad))
             (set! (-> self tpos-old-adj quad) (-> self tpos-curr-adj quad))
             (quaternion->matrix (-> self tgt-rot-mat) (-> *target* control dir-targ))
             (quaternion->matrix (-> self tgt-face-mat) (-> *target* control unknown-quaternion00))
             (cond
               ((< (-> self ease-t) 1.0)
                (new 'stack-no-clear 'vector)
                (cond
                  ((logtest? (-> self master-options) 32)
                   (vector-lerp! (-> self tpos-curr) (-> self ease-from) (-> self ease-to) (parameter-ease-sin-clamp (-> self ease-t)))
                   (logand! (-> self master-options) -33))
                  (else
                   (vector-lerp! (-> self tpos-curr) (-> self ease-from) (target-cam-pos) (parameter-ease-sin-clamp (-> self ease-t)))))
                (+! (-> self ease-t) (-> self ease-step)))
               (else (set! (-> self tpos-curr quad) (-> (target-cam-pos) quad))))
             (when (logtest? (-> *target* control root-prim prim-core action) (collide-action edgegrab-cam))
               (if *display-cam-los-debug* (format *stdcon* "ride edge~%"))
               (let ((s4-2 (new 'stack-no-clear 'collide-tri-result))
                     (gp-5 (new 'stack-no-clear 'vector))
                     (s5-2 (new 'stack-no-clear 'vector)))
                 (vector--float*! s5-2 (-> self tpos-curr) (-> self local-down) (-> self target-height))
                 (vector-float*! gp-5 (-> self tgt-rot-mat vector 2) 4915.2)
                 (vector-! s5-2 s5-2 gp-5)
                 (let ((f0-20 (fill-and-probe-using-line-sphere *collide-cache*
                                                                s5-2
                                                                gp-5
                                                                4300.8
                                                                (collide-kind background)
                                                                (the-as process #f)
                                                                s4-2
                                                                (new 'static 'pat-surface :nocamera #x1 :nolineofsight #x1))))
                   (if (and (< 0.0 f0-20) (< f0-20 1.0)) (vector+float*! (-> self tpos-curr) (-> self tpos-curr) gp-5 (+ -1.0 f0-20))))))
             (set! (-> self on-ground)
                   (not (and (logtest? (-> *target* control unknown-surface00 flags) (surface-flags jump))
                             (not (logtest? (-> *target* control status) (cshape-moving-flags onsurf))))))
             (let ((gp-6 (new-stack-vector0)))
               0.0
               (cond
                 ((and (and (logtest? (-> *target* control unknown-surface00 flags) (surface-flags jump))
                            (not (logtest? (-> *target* control status) (cshape-moving-flags onsurf))))
                       (!= (-> *target* control unknown-surface00 name) 'launch-jump))
                  (if *display-cam-los-debug* (format *stdcon* "air tracking~%"))
                  (vector+float*! (-> self tpos-curr-adj) (-> self tpos-curr-adj) (-> self local-down) (-> self upspeed))
                  (vector+float*! (-> self tpos-tgt) (-> self tpos-tgt) (-> self local-down) (-> self upspeed))
                  (vector-! gp-6 (-> self tpos-curr) (-> self tpos-tgt))
                  (let ((f30-0 (vector-dot gp-6 (-> self local-down))))
                    (vector--float*! gp-6 gp-6 (-> self local-down) f30-0)
                    (if (< 0.0 f30-0) (set! (-> self upspeed) (/ (-> self upspeed) 2)))
                    (vector+! (-> self tpos-tgt) (-> self tpos-tgt) gp-6)
                    (let ((f0-30 (/ f30-0 20))) (vector+float*! (-> self tpos-tgt) (-> self tpos-tgt) (-> self local-down) f0-30)))
                  (vector-! gp-6 (-> self tpos-curr-adj) (-> self tpos-tgt))
                  (let* ((f0-32 (vector-dot gp-6 (-> self local-down)))
                         (f0-33 (if (< 0.0 f0-32)
                                  (* f0-32 (-> *CAMERA_MASTER-bank* up-move-to-pitch-ratio-in-air))
                                  (* f0-32 (-> *CAMERA_MASTER-bank* down-move-to-pitch-ratio-in-air)))))
                    (vector+float*! (-> self tpos-curr-adj) (-> self tpos-tgt) (-> self local-down) f0-33))
                  (vector-! gp-6 (-> *target* control shadow-pos) (-> self tpos-curr-adj))
                  (let* ((f0-35 (vector-dot gp-6 (-> self local-down)))
                         (f0-36 (* 0.03 f0-35)))
                    (if (and (< f0-36 0.0) (< f0-36 (-> self upspeed))) (set! (-> self upspeed) f0-36))))
                 (else
                  (if *display-cam-los-debug* (format *stdcon* "ground tracking~%"))
                  (vector-! gp-6 (-> self tpos-curr) (-> self tpos-old))
                  (let ((f0-38 (vector-dot gp-6 (-> self local-down))))
                    (cond
                      ((logtest? (-> *target* water flags) (water-flags wt09)) (set! (-> self upspeed) 0.0))
                      ((< 0.0 f0-38) (set! (-> self upspeed) 0.0))
                      (else (set! (-> self upspeed) f0-38))))
                  (set! (-> self tpos-tgt quad) (-> self tpos-curr quad))
                  (vector-! gp-6 (-> self tpos-curr-adj) (-> self tpos-curr))
                  (let* ((f0-42 (vector-dot gp-6 (-> self local-down)))
                         (f0-43 (if (< 0.0 f0-42)
                                  (* f0-42 (-> *CAMERA_MASTER-bank* up-move-to-pitch-on-ground))
                                  (* f0-42 (-> *CAMERA_MASTER-bank* down-move-to-pitch-on-ground)))))
                    (vector+float*! (-> self tpos-curr-adj) (-> self tpos-curr) (-> self local-down) f0-43)))))
             (if (not (logtest? (-> self slave-options) 16)) (reset-follow))
             (let ((v1-196 (-> *target* water flags)))
               (when (and (logtest? v1-196 (water-flags wt09)) (logtest? v1-196 (water-flags wt11 wt12)))
                 (let ((f0-45 (- (-> *target* water base-height) (-> self target-height))))
                   (if (< (-> self tpos-curr-adj y) f0-45) (set! (-> self tpos-curr-adj y) f0-45)))))
             (vector+! (-> self pitch-off) (-> self pitch-off) (-> self tpos-curr))
             (vector-! (-> self pitch-off) (-> self pitch-off) (-> self tpos-old))
             (vector-float*! (-> self pitch-off) (-> self pitch-off) (-> *CAMERA_MASTER-bank* pitch-off-blend))
             (let ((gp-7 (new 'stack-no-clear 'vector)))
               (vector--float*! gp-7 (-> self tpos-curr-adj) (-> self local-down) (-> self target-height))
               (let ((v1-207 (new 'stack-no-clear 'vector)))
                 0.0
                 (vector-! v1-207 (-> *target* control shadow-pos) gp-7)
                 (let* ((f0-50 (vector-dot v1-207 (-> self local-down)))
                        (f0-51 (+ -4096.0 f0-50)))
                   (if (< f0-51 0.0) (vector+float*! gp-7 gp-7 (-> self local-down) f0-51))))
               (tracking-spline-method-17 (-> self target-spline) gp-7 2048.0 0.0 #f))
             (the-as symbol (tracking-spline-method-22 (-> self target-spline) 40960.0)))
            (*target* (logior! (-> self master-options) 2) (reset-target-tracking))
            ((logtest? (-> self master-options) 2)
             (let ((v0-1 (the-as symbol (logand -3 (-> self master-options)))))
               (set! (-> self master-options) (the-as uint v0-1))
               v0-1)))))

(defun in-cam-entity-volume? ((arg0 vector) (arg1 entity) (arg2 float) (arg3 symbol))
  (local-vars (sv-16 res-tag))
  (let ((s2-0 0))
    (loop
      (set! sv-16 (new 'static 'res-tag))
      (let ((v1-1 (the-as object
                          ((method-of-type res-lump get-property-data)
                           arg1
                           arg3
                           'exact
                           (the float s2-0)
                           (the-as pointer #f)
                           (& sv-16)
                           *res-static-buf*))))
        (cond
          ((not (the-as pointer v1-1)) (return #f))
          (else
           (dotimes (a0-2 (the-as int (-> sv-16 elt-count)))
             (if (< arg2
                    (- (vector-dot arg0 (-> (the-as (inline-array vector) v1-1) a0-2)) (-> (the-as (inline-array vector) v1-1) a0-2 w)))
               (goto cfg-12)))
           (return #t))))
      (label cfg-12)
      (+! s2-0 1)))
  (the-as symbol #f))

(defbehavior master-unset-region camera-master ()
  (when (-> self cam-entity)
    (set! (-> self cam-entity) #f)
    (logand! (-> self master-options) -65)
    (set! (-> self stringMinHeight) (-> *CAMERA-bank* default-string-min-y))
    (set! (-> self stringMaxHeight) (-> *CAMERA-bank* default-string-max-y))
    (set! (-> self stringMinLength) (-> *CAMERA-bank* default-string-min-z))
    (set! (-> self stringMaxLength) (-> *CAMERA-bank* default-string-max-z))
    (set! (-> self stringCliffHeight) 163840.0)
    (send-event *camera* 'point-of-interest #f)
    (set! (-> *camera-combiner* tracking point-of-interest-blend target) 0.0)
    (if (not (send-event *camera* 'query-state *camera-base-mode*))
      (send-event *camera* 'change-state *camera-base-mode* (seconds 1.5)))
    (set! (-> *camera-combiner* tracking tilt-adjust target) (-> *CAMERA-bank* default-tilt-adjust))
    (send-event *camera* 'clear-slave-option #x10000)))

(defbehavior master-base-region camera-master ((arg0 entity))
  (logior! (-> self master-options) 64)
  (set! (-> self stringMinHeight) (cam-slave-get-float arg0 'stringMinHeight (-> *CAMERA-bank* default-string-min-y)))
  (set! (-> self stringMaxHeight) (cam-slave-get-float arg0 'stringMaxHeight (-> *CAMERA-bank* default-string-max-y)))
  (set! (-> self stringMinLength) (cam-slave-get-float arg0 'stringMinLength (-> *CAMERA-bank* default-string-min-z)))
  (set! (-> self stringMaxLength) (cam-slave-get-float arg0 'stringMaxLength (-> *CAMERA-bank* default-string-max-z)))
  (let ((s5-0 (new 'stack-no-clear 'vector)))
    (if (cam-slave-get-vector-with-offset (the-as entity-actor arg0) s5-0 'interesting)
      (send-event *camera* 'point-of-interest s5-0)))
  (if (< 405504.0 (-> self stringMaxLength)) (set! (-> self stringMaxLength) (-> *CAMERA-bank* default-string-max-z)))
  (set! (-> self stringCliffHeight) (cam-slave-get-float arg0 'stringCliffHeight 163840.0))
  (if (not (send-event *camera* 'query-state *camera-base-mode*))
    (send-event *camera* 'change-state *camera-base-mode* (seconds 1.5)))
  (if (logtest? #x10000 (cam-slave-get-flags (-> self cam-entity) 'flags)) (send-event *camera* 'set-slave-option #x10000))
  (set! (-> *camera-combiner* tracking tilt-adjust target)
        (cam-slave-get-float arg0 'tiltAdjust (-> *CAMERA-bank* default-tilt-adjust))))

(defun setup-slave-for-hopefull ((arg0 camera-slave))
  (when (= (-> arg0 blend-to-type) 2)
    (cam-calc-follow! (-> arg0 tracking) (-> arg0 trans) #f)
    (slave-set-rotation! (-> arg0 tracking) (-> arg0 trans) (the-as float (-> arg0 options)) (-> arg0 fov) #f))
  (none))

(defbehavior master-is-hopeful-better? camera-master ((arg0 camera-slave) (arg1 camera-slave))
  (if (not *camera-combiner*)
    #f
    (< (vector-dot (-> arg0 tracking inv-mat vector 2) (-> *camera-combiner* inv-camera-rot vector 2))
       (vector-dot (-> arg1 tracking inv-mat vector 2) (-> *camera-combiner* inv-camera-rot vector 2)))))

(defbehavior master-switch-to-entity camera-master ((arg0 entity))
  (local-vars (v0-21 object) (gp-0 (pointer process)) (sv-16 res-tag) (sv-112 process) (sv-128 string) (sv-144 string))
  (set! (-> self cam-entity) arg0)
  10
  (let ((s4-0 (cam-state-from-entity arg0)))
    (cond
      ((= s4-0 *camera-base-mode*) (master-base-region arg0) (return #t))
      (s4-0
       (let ((s3-0 (get-process *camera-dead-pool* camera-slave #x4000)))
         (set! gp-0
               (when s3-0
                 (let ((t9-3 (method-of-type camera-slave activate)))
                   (t9-3 (the-as camera-slave s3-0) self 'camera-slave (the-as pointer #x70004000)))
                 (run-now-in-process s3-0 cam-slave-init s4-0 arg0)
                 (-> s3-0 ppointer))))
       (when (not gp-0)
         (format 0 "ERROR <GMJ>: primary region activate failed~%")
         (return #f))
       (setup-slave-for-hopefull (the-as camera-slave (ppointer->process gp-0))))
      (else
       (format 0 "ERROR <GMJ>: camera region '~S' didn't produce a state~%" (res-lump-struct arg0 'name structure))
       (return #f))))
  (set! sv-16 (new 'static 'res-tag))
  (let ((s4-2 (res-lump-data arg0 'alternates (pointer string) :tag-ptr (& sv-16))))
    (when s4-2
      (dotimes (s3-2 (the-as int (-> sv-16 elt-count)))
        (let ((s2-0 (entity-by-name (-> s4-2 s3-2))))
          (set! v0-21
                (cond
                  (s2-0
                   (let ((s0-0 (cam-state-from-entity s2-0)))
                     (cond
                       ((= s0-0 *camera-base-mode*) (deactivate (-> gp-0 0)) (master-base-region s2-0) (return #t) v0-21)
                       (s0-0
                        (set! sv-112 (get-process *camera-dead-pool* camera-slave #x4000))
                        (let ((s1-0 (when sv-112
                                      (let ((t9-15 (method-of-type camera-slave activate)))
                                        (t9-15 (the-as camera-slave sv-112) self 'camera-slave (the-as pointer #x70004000)))
                                      (run-now-in-process sv-112 cam-slave-init s0-0 s2-0)
                                      (-> sv-112 ppointer))))
                          (cond
                            (s1-0
                             (setup-slave-for-hopefull (the-as camera-slave (ppointer->process s1-0)))
                             (cond
                               ((master-is-hopeful-better? (the-as camera-slave (ppointer->process gp-0))
                                                           (the-as camera-slave (ppointer->process s1-0)))
                                (deactivate (-> gp-0 0))
                                (set! gp-0 s1-0)
                                gp-0)
                               (else (deactivate (-> s1-0 0)))))
                            (else (format 0 "ERROR <GMJ>: alternate region activate failed~%")))))
                       (else
                        (let ((s1-1 format)
                              (s0-1 0))
                          (set! sv-128 "ERROR <GMJ>: alternate camera region '~S' didn't produce a state~%")
                          (let ((a2-10 (res-lump-struct s2-0 'name structure))) (s1-1 s0-1 sv-128 a2-10)))))))
                  (else
                   (let ((s2-1 format)
                         (s1-2 0)
                         (s0-2 "ERROR <GMJ>: alternate '~S' not found for '~S'~%"))
                     (set! sv-144 (-> s4-2 s3-2))
                     (let ((a3-8 (res-lump-struct arg0 'name structure))) (s2-1 s1-2 s0-2 sv-144 a3-8))))))))))
  (let ((v1-48 (the int (* 300.0 (cam-slave-get-interp-time (-> (the-as camera-slave (-> gp-0 0)) cam-entity))))))
    (if (nonzero? (-> self force-blend)) (set! v1-48 (min v1-48 (the-as int (-> self force-blend-time)))))
    (send-event *camera* 'change-state (ppointer->process gp-0) v1-48))
  #t)

(defbehavior master-check-regions camera-master ()
  (cond
    ((send-event *camera* 'query-state cam-eye) #f)
    ((or (not *target*) (logtest? (-> self master-options) 1)) (master-unset-region))
    ((and (logtest? (-> self master-options) 4)
          (not (-> self on-ground))
          (or (not (-> self cam-entity)) (not (logtest? #x20000 (cam-slave-get-flags (-> self cam-entity) 'flags)))))
     #f)
    ((and (-> self cam-entity)
          (not (in-cam-entity-volume? (target-pos 0) (-> self cam-entity) 0.0 'cutoutvol))
          (or (in-cam-entity-volume? (target-pos 0) (-> self cam-entity) 1024.0 'pvol)
              (in-cam-entity-volume? (target-pos 0) (-> self cam-entity) 1024.0 'vol)
              (and (not ((method-of-type res-lump get-property-data)
                         (-> self cam-entity)
                         'pvol
                         'exact
                         0.0
                         (the-as pointer #f)
                         (the-as (pointer res-tag) #f)
                         *res-static-buf*))
                   (not ((method-of-type res-lump get-property-data)
                         (-> self cam-entity)
                         'vol
                         'exact
                         0.0
                         (the-as pointer #f)
                         (the-as (pointer res-tag) #f)
                         *res-static-buf*)))))
     #f)
    (else
     (let ((v1-17 (-> *camera-engine* alive-list next0)))
       *camera-engine*
       (let ((gp-5 (-> v1-17 next0)))
         (while (!= v1-17 (-> *camera-engine* alive-list-end))
           (let ((s5-1 (-> (the-as connection v1-17) param1)))
             (when (and (not (in-cam-entity-volume? (target-pos 0) (the-as entity s5-1) 1024.0 'cutoutvol))
                        (in-cam-entity-volume? (target-pos 0) (the-as entity s5-1) 0.0 'vol))
               (if (master-switch-to-entity (the-as entity s5-1)) (return #t))))
           (set! v1-17 gp-5)
           *camera-engine*
           (set! gp-5 (-> gp-5 next0)))))
     (master-unset-region))))

(defstate cam-master-active (camera-master)
  :event
    (behavior ((proc process) (argc int) (message symbol) (block event-message-block))
      (local-vars (v0-0 object))
      (rlet ((vf0 :class vf))
        (init-vf0-vector)
        (let ((v1-0 message))
          (cond
            ((= v1-0 'dist-from-interp-src)
             (set! v0-0
                   (cond
                     ((not *camera-combiner*) 409600.0)
                     ((= (-> *camera-combiner* interp-val) 0.0) 0.0)
                     (else (-> *camera-combiner* dist-from-src)))))
            ((= v1-0 'dist-from-interp-dest)
             (set! v0-0
                   (cond
                     ((not *camera-combiner*) 0.0)
                     ((= (-> *camera-combiner* interp-val) 0.0) 409600.0)
                     (else (-> *camera-combiner* dist-from-dest)))))
            ((= v1-0 'level-deactivate)
             (set! v0-0
                   (if (and (-> self cam-entity) (= (-> (get-level (-> self cam-entity)) name) (-> block param 0))) (master-unset-region))))
            ((= v1-0 'clear-entity) (set! v0-0 (master-unset-region)))
            ((= v1-0 'no-intro) (set! v0-0 3) (set! (-> self no-intro) (the-as uint v0-0)))
            ((= v1-0 'force-blend)
             (set! (-> self force-blend) (the-as uint 3))
             (set! v0-0 (-> block param 0))
             (set! (-> self force-blend-time) (the-as uint v0-0)))
            ((= v1-0 'teleport-to-transformq)
             (set! v0-0
                   (when (> argc 0)
                     (let ((gp-1 (the-as object (-> block param 0))))
                       (send-event self 'change-state cam-free-floating 0)
                       (dotimes (s5-1 (-> self num-slaves))
                         (set! (-> self slave s5-1 0 trans quad) (-> (the-as matrix gp-1) vector 0 quad))
                         (quaternion->matrix (the-as matrix (-> self slave s5-1 0 tracking)) (the-as quaternion (+ (the-as uint gp-1) 16)))))
                     (send-event self 'teleport))))
            ((= v1-0 'teleport-to-other-start-string)
             (let ((gp-2 (new 'stack-no-clear 'vector)))
               (set! (-> *camera-combiner* trans quad) (-> *camera-other-trans* quad))
               (vector-! gp-2 (-> self tpos-curr-adj) *camera-other-trans*)
               (vector-normalize! gp-2 1.0)
               (forward-down->inv-matrix (-> *camera-combiner* inv-camera-rot) gp-2 (new 'static 'vector :y -1.0)))
             (send-event self 'change-state cam-free-floating 0)
             (send-event self 'teleport)
             (let ((a1-10 (new 'stack-no-clear 'event-message-block)))
               (set! (-> a1-10 from) self)
               (set! (-> a1-10 num-params) 2)
               (set! (-> a1-10 message) 'change-state)
               (set! (-> a1-10 param 0) (the-as uint *camera-base-mode*))
               (set! (-> a1-10 param 1) (the-as uint 0))
               (set! v0-0 (send-event-function self a1-10))))
            ((= v1-0 'teleport-to-vector-start-string)
             (set! v0-0
                   (when (> argc 0)
                     (let ((v1-43 (the-as object (-> block param 0)))
                           (gp-3 (new 'stack-no-clear 'vector)))
                       (set! (-> *camera-combiner* trans quad) (-> (the-as vector v1-43) quad))
                       (vector-! gp-3 (-> self tpos-curr-adj) (the-as vector v1-43))
                       (vector-normalize! gp-3 1.0)
                       (forward-down->inv-matrix (-> *camera-combiner* inv-camera-rot) gp-3 (new 'static 'vector :y -1.0)))
                     (send-event self 'change-state cam-free-floating 0)
                     (send-event self 'change-state *camera-base-mode* 0))))
            ((= v1-0 'change-pov)
             (let ((v1-52 (the-as object (-> block param 0))))
               (cond
                 ((< argc 2) (set! (-> self pov-bone) 0) 0)
                 (else (set! (-> self pov-bone) (the-as int (-> block param 1)))))
               (set! v0-0
                     (cond
                       ((not (the-as process v1-52)) (set! (-> self pov-handle) (the-as handle #f)) #f)
                       (else (set! v0-0 (process->handle (the-as process v1-52))) (set! (-> self pov-handle) (the-as handle v0-0)) v0-0)))))
            ((= v1-0 'change-target-bone) (set! v0-0 (-> block param 0)) (set! (-> self which-bone) (the-as int v0-0)))
            ((= v1-0 'change-target)
             (let ((v1-56 (the-as object (-> block param 0))))
               (cond
                 ((< argc 2) (set! (-> self which-bone) 0) 0)
                 (else (set! (-> self which-bone) (the-as int (-> block param 1)))))
               (cond
                 ((not (the-as process v1-56)) (set! (-> self drawable-target) (the-as handle #f)) (logand! (-> self master-options) -3))
                 ((= (the-as process v1-56) *target*)
                  (set! (-> self drawable-target) (the-as handle #f))
                  (logior! (-> self master-options) 2)
                  (reset-target-tracking))
                 (else
                  (set! (-> self drawable-target) (process->handle (the-as process v1-56)))
                  (logior! (-> self master-options) 2)
                  (reset-drawable-tracking))))
             (set! (-> *camera-combiner* tracking no-follow) #f)
             (set! v0-0 #f))
            ((= v1-0 'reset-root)
             (dotimes (gp-4 (-> self num-slaves))
               (set! (-> self slave gp-4 0 trans quad) (the-as uint128 0))
               (matrix-identity! (the-as matrix (-> self slave gp-4 0 tracking))))
             (vector-reset! (-> *camera-combiner* trans))
             (set! v0-0 (matrix-identity! (the-as matrix (-> *camera-combiner* tracking)))))
            ((= v1-0 'set-fov)
             (set! (-> *camera-combiner* fov) (the-as float (-> block param 0)))
             (dotimes (v1-86 (-> self num-slaves))
               (set! (-> self slave v1-86 0 fov) (the-as float (-> block param 0))))
             (set! v0-0 #f))
            ((= v1-0 'query-fov) (set! v0-0 (if (> (-> self num-slaves) 0) (-> self slave 0 0 fov) 11650.845)))
            ((= v1-0 'intro-done?)
             (set! v0-0 #t)
             (dotimes (v1-91 (-> self num-slaves))
               (if (< (-> self slave v1-91 0 intro-t) 1.0) (set! v0-0 #f))))
            ((= v1-0 'query-state)
             (let ((v1-95 (+ (-> self num-slaves) -1)))
               (while (not (or (< v1-95 0) (= (-> self slave v1-95 0 next-state) (-> block param 0))))
                 (+! v1-95 -1))
               (set! v0-0 (and (>= v1-95 0) (= (-> self slave v1-95 0 next-state) (-> block param 0))))))
            ((= v1-0 'change-to-entity-by-name)
             (let ((a0-75 (entity-by-name (the-as string (-> block param 0)))))
               (set! v0-0
                     (if a0-75
                       (master-switch-to-entity a0-75)
                       (format 0 "ERROR <GMJ>: camera entity '~S' not found for change-to-entity-by-name~%" (-> block param 0))))))
            ((= v1-0 'change-state)
             (let ((s1-0 (the-as uint #f))
                   (s2-0 (the-as (pointer process) #f))
                   (s5-2 (the-as (pointer camera-slave) #f)))
               (let ((s3-0 (the-as object #f))
                     (s4-1 (the-as (pointer camera-slave) #f)))
                 (let ((t9-22 type-type?)
                       (v1-101 (-> block param 0)))
                   (cond
                     ((t9-22 (rtype-of v1-101) state) (set! s1-0 (-> block param 0)))
                     ((let ((t9-23 type-type?)
                            (v1-103 (-> block param 0)))
                        (t9-23 (rtype-of v1-103) camera-slave))
                      (set! s2-0 (process->ppointer (the-as process (-> block param 0)))))
                     (else
                      (let ((t9-24 format)
                            (a0-82 0)
                            (a1-25 "ERROR <GMJ>: invalid type '~A' to *camera* change-state~%")
                            (v1-106 (-> block param 0)))
                        (t9-24 a0-82 a1-25 (rtype-of v1-106))))))
                 (if (and (> (-> self num-slaves) 0)
                          (or (= (-> self slave 0 0 next-state name) 'cam-stick) (= (-> self slave 0 0 next-state name) 'cam-string)))
                   (set! (-> self view-off-param-save) (-> self slave 0 0 view-off-param)))
                 (set! (-> self changer) (the-as uint (process->ppointer proc)))
                 (cond
                   ((<= (-> self num-slaves) 0)
                    (cond
                      (s2-0
                       (let ((a1-26 (new 'stack-no-clear 'event-message-block)))
                         (set! (-> a1-26 from) self)
                         (set! (-> a1-26 num-params) 1)
                         (set! (-> a1-26 message) 'slave-activated)
                         (let ((v1-126 s2-0)) (set! (-> a1-26 param 0) (the-as uint (if v1-126 (-> (the-as camera-slave (-> v1-126 0)) self)))))
                         (send-event-function self a1-26)))
                      (else
                       (let ((gp-5 (the-as camera-slave (get-process *camera-dead-pool* camera-slave #x4000))))
                         (set! s2-0
                               (when gp-5
                                 (let ((t9-27 (method-of-type camera-slave activate))) (t9-27 gp-5 self 'camera-slave (the-as pointer #x70004000)))
                                 (run-now-in-process gp-5 cam-slave-init s1-0 #f)
                                 (-> gp-5 ppointer))))
                       (cond
                         (s2-0)
                         (else (format 0 "ERROR <GMJ>: replacement slave failed to activate~%")))))
                    (when s2-0
                      (send-event *camera-combiner* 'stop-tracking)
                      (if (= (-> (the-as camera-slave (-> s2-0 0)) blend-to-type) 2)
                        (send-event *camera-combiner* 'start-tracking (if s2-0 (-> (the-as camera-slave (-> s2-0 0)) self))))))
                   ((zero? (-> block param 1))
                    (if *math-camera* (set! (-> *math-camera* reset) 1))
                    (when (< 1 (-> self num-slaves))
                      (if (= (-> self changer) (-> self slave 1)) (set! s5-2 (-> self slave 1)) (deactivate (-> self slave 1 0)))
                      (set! (-> self slave 1) (the-as (pointer camera-slave) #f))
                      (+! (-> self num-slaves) -1))
                    (cond
                      (s2-0
                       (if (= (-> self changer) (-> self slave 0)) (set! s5-2 (-> self slave 0)) (deactivate (-> self slave 0 0)))
                       (set! (-> self slave 0) (the-as (pointer camera-slave) #f))
                       (+! (-> self num-slaves) -1)
                       (let ((a1-33 (new 'stack-no-clear 'event-message-block)))
                         (set! (-> a1-33 from) self)
                         (set! (-> a1-33 num-params) 1)
                         (set! (-> a1-33 message) 'slave-activated)
                         (let ((v1-166 s2-0)) (set! (-> a1-33 param 0) (the-as uint (if v1-166 (-> (the-as camera-slave (-> v1-166 0)) self)))))
                         (send-event-function self a1-33)))
                      ((not (and (= (-> self slave 0 0 next-state) *camera-base-mode*) (= (-> self slave 0 0 next-state) s1-0)))
                       (send-event (ppointer->process (-> self slave 0)) 'change-state-no-go s1-0)
                       (set! s4-1 (-> self slave 0))
                       (set! s3-0 s1-0)
                       (set! s2-0 (-> self slave 0))))
                    (when s2-0
                      (send-event *camera-combiner* 'stop-tracking)
                      (when (= (-> (the-as camera-slave (-> s2-0 0)) blend-to-type) 2)
                        (let ((a1-36 (new 'stack-no-clear 'event-message-block)))
                          (set! (-> a1-36 from) self)
                          (set! (-> a1-36 num-params) 1)
                          (set! (-> a1-36 message) 'start-tracking)
                          (let ((v1-191 s2-0)) (set! (-> a1-36 param 0) (the-as uint (if v1-191 (-> (the-as camera-slave (-> v1-191 0)) self)))))
                          (send-event-function *camera-combiner* a1-36)))))
                   (else
                    (when (< 1 (-> self num-slaves))
                      (if (= (-> self changer) (-> self slave 0)) (set! s5-2 (-> self slave 0)) (deactivate (-> self slave 0 0)))
                      (set! (-> self slave 0) (-> self slave 1))
                      (set! (-> self slave 1) (the-as (pointer camera-slave) #f))
                      (+! (-> self num-slaves) -1))
                    (when (< 0.0 (-> self slave 0 0 intro-t-step))
                      (set! (-> self outro-t) (-> self slave 0 0 intro-t))
                      (set! (-> self outro-t-step) (/ -5.0 (the float (-> block param 1))))
                      (set! (-> self outro-exit-value) (-> self slave 0 0 outro-exit-value))
                      (curve-copy! (-> self outro-curve) (-> self slave 0 0 intro-curve)))
                    (if (nonzero? (-> self no-intro)) (set! (-> self outro-t) 0.0))
                    (when (not (and (= (-> self slave 0 0 next-state) *camera-base-mode*) (= (-> self slave 0 0 next-state) s1-0)))
                      (cond
                        (s2-0
                         (let ((a1-38 (new 'stack-no-clear 'event-message-block)))
                           (set! (-> a1-38 from) self)
                           (set! (-> a1-38 num-params) 1)
                           (set! (-> a1-38 message) 'slave-activated)
                           (let ((v1-228 s2-0)) (set! (-> a1-38 param 0) (the-as uint (if v1-228 (-> (the-as camera-slave (-> v1-228 0)) self)))))
                           (send-event-function self a1-38)))
                        (else
                         (let ((s2-1 (get-process *camera-dead-pool* camera-slave #x4000)))
                           (set! s2-0
                                 (when s2-1
                                   (let ((t9-42 (method-of-type camera-slave activate)))
                                     (t9-42 (the-as camera-slave s2-1) self 'camera-slave (the-as pointer #x70004000)))
                                   (run-now-in-process s2-1 cam-slave-init s1-0 #f)
                                   (-> s2-1 ppointer))))
                         (cond
                           (s2-0)
                           (else (format #t "ERROR <GMJ>: secondary slave activate failed~%")))))
                      (when s2-0
                        (send-event *camera-combiner* 'set-interpolation (-> block param 1))
                        (set! s4-1 (-> self slave 0))
                        (cond
                          ((zero? (-> self slave 0 0 blend-from-type))
                           (send-event (ppointer->process (-> self slave 0)) 'change-state-no-go cam-fixed)
                           (send-event *camera-combiner* 'stop-tracking)
                           (set! s3-0 cam-fixed))
                          (else (send-event (ppointer->process (-> self slave 0)) 'change-state-no-go cam-decel) (set! s3-0 cam-decel)))
                        (let ((v1-261 (-> *camera-combiner* tracking-status)))
                          (cond
                            ((zero? v1-261)
                             (let ((v1-263 (-> (the-as camera-slave (-> s2-0 0)) blend-to-type)))
                               (cond
                                 ((zero? v1-263))
                                 ((= v1-263 1))
                                 ((= v1-263 2)
                                  (if (= (-> self slave 0 0 blend-from-type) 1)
                                    (send-event *camera-combiner* 'copy-tracking (ppointer->process (-> self slave 0)))
                                    (send-event *camera-combiner* 'start-tracking (ppointer->process (-> self slave 0))))
                                  (set! (-> *camera-combiner* tracking-status) (the-as uint 2))))))
                            ((= v1-261 1)
                             (let ((v1-280 (-> (the-as camera-slave (-> s2-0 0)) blend-to-type)))
                               (cond
                                 ((zero? v1-280) (set! (-> *camera-combiner* tracking-status) (the-as uint 3)))
                                 ((= v1-280 1) (set! (-> *camera-combiner* tracking-status) (the-as uint 3)))
                                 ((= v1-280 2)))))
                            ((= v1-261 2)
                             (let ((v1-286 (-> (the-as camera-slave (-> s2-0 0)) blend-to-type)))
                               (cond
                                 ((zero? v1-286) (set! (-> *camera-combiner* tracking-status) (the-as uint 0)) 0)
                                 ((= v1-286 1) (set! (-> *camera-combiner* tracking-status) (the-as uint 0)) 0)
                                 ((= v1-286 2)))))
                            ((= v1-261 3)
                             (let ((v1-295 (-> (the-as camera-slave (-> s2-0 0)) blend-to-type)))
                               (cond
                                 ((zero? v1-295) (set! (-> *camera-combiner* tracking-status) (the-as uint 0)) 0)
                                 ((= v1-295 1) (set! (-> *camera-combiner* tracking-status) (the-as uint 0)) 0)
                                 ((= v1-295 2) (set! (-> *camera-combiner* tracking-status) (the-as uint 2))))))))))))
                 (if s4-1 (send-event (if s4-1 (-> (the-as camera-slave (-> s4-1 0)) self)) 'go s3-0)))
               (if s5-2 (deactivate (-> s5-2 0))))
             (set! v0-0 #t))
            ((= v1-0 'slave-activated)
             (set! v0-0
                   (cond
                     ((< (-> self num-slaves) 2)
                      (set! (-> self slave (-> self num-slaves))
                            (the-as (pointer camera-slave) (process->ppointer (the-as process (-> block param 0)))))
                      (+! (-> self num-slaves) 1)
                      (logior! (-> self master-options) 8)
                      (set! (-> *camera-combiner* tracking tilt-adjust target) (-> (the-as projectile (-> block param 0)) max-turn)))
                     (else
                      (format 0 "ERROR: ERROR <GMJ>: Exceeded maximum number of camera slaves!~%")
                      (deactivate (the-as camera-slave (-> block param 0)))))))
            ((= v1-0 'ease-in)
             (cond
               ((< argc 1) (set! (-> self ease-t) 0.0) (logand! (-> self master-options) -33))
               ((< argc 2)
                (if (< (the-as float (-> block param 0)) (-> self ease-t)) (set! (-> self ease-t) (the-as float (-> block param 0))))
                (logand! (-> self master-options) -33))
               (else
                (if (< (the-as float (-> block param 0)) (-> self ease-t)) (set! (-> self ease-t) (the-as float (-> block param 0))))
                (set! (-> self ease-to quad) (-> (the-as vector (-> block param 1)) quad))
                (logior! (-> self master-options) 32)))
             (set! (-> self ease-step) 0.033333335)
             (set! v0-0 (-> self ease-from))
             (set! (-> (the-as vector v0-0) quad) (-> self tpos-curr-adj quad)))
            ((= v1-0 'damp-up) (let ((f0-22 0.0)) (set! (-> self upspeed) f0-22) (set! v0-0 f0-22)))
            ((= v1-0 'reset-follow)
             (set! v0-0 (if (handle->process (-> self drawable-target)) (reset-drawable-follow) (reset-follow))))
            ((= v1-0 'teleport)
             (cond
               ((and (logtest? (-> self master-options) 2) (handle->process (-> self drawable-target))) (reset-drawable-tracking))
               ((and *target* (logtest? (-> self master-options) 2)) (reset-target-tracking)))
             (countdown (gp-6 (-> self num-slaves))
               (send-event (ppointer->process (-> self slave gp-6)) message))
             (let ((a1-54 (new 'stack-no-clear 'event-message-block)))
               (set! (-> a1-54 from) self)
               (set! (-> a1-54 num-params) 0)
               (set! (-> a1-54 message) message)
               (set! v0-0 (send-event-function *camera-combiner* a1-54))))
            ((= v1-0 'toggle-slave-option)
             (logxor! (-> self slave-options) (-> block param 0))
             (let ((a0-193 (-> self slave 0))
                   (v1-360 (-> self slave 1)))
               (if a0-193 (logxor! (-> a0-193 0 options) (-> block param 0)))
               (set! v0-0
                     (when v1-360
                       (set! v0-0 (logxor (-> v1-360 0 options) (-> block param 0)))
                       (set! (-> v1-360 0 options) (the-as uint v0-0))
                       v0-0))))
            (else
             (set! v0-0
                   (cond
                     ((= v1-0 'slave-option?)
                      (if (nonzero? (-> self num-slaves)) (logtest? (-> self slave (+ (-> self num-slaves) -1) 0 options) (-> block param 0))))
                     ((= v1-0 'set-slave-option)
                      (when (nonzero? (-> self num-slaves))
                        (set! v0-0 (logior (-> self slave (+ (-> self num-slaves) -1) 0 options) (-> block param 0)))
                        (set! (-> self slave (+ (-> self num-slaves) -1) 0 options) (the-as uint v0-0))
                        v0-0))
                     ((= v1-0 'clear-slave-option)
                      (when (nonzero? (-> self num-slaves))
                        (set! v0-0 (logclear (-> self slave (+ (-> self num-slaves) -1) 0 options) (-> block param 0)))
                        (set! (-> self slave (+ (-> self num-slaves) -1) 0 options) (the-as uint v0-0))
                        v0-0))
                     ((= v1-0 'no-follow)
                      (when (nonzero? (-> self num-slaves))
                        (set! (-> self slave (+ (-> self num-slaves) -1) 0 tracking no-follow) #t)
                        (vector-reset! (-> self slave (+ (-> self num-slaves) -1) 0 tracking follow-off)))
                      (set! (-> *camera-combiner* tracking no-follow) #t)
                      (set! v0-0 (-> *camera-combiner* tracking follow-off))
                      (.svf (&-> (the-as vector v0-0) quad) vf0)
                      v0-0)
                     ((= v1-0 'yes-follow)
                      (if (nonzero? (-> self num-slaves)) (set! (-> self slave (+ (-> self num-slaves) -1) 0 tracking no-follow) #f))
                      (set! (-> *camera-combiner* tracking no-follow) #f)
                      #f)
                     ((= v1-0 'blend-from-as-fixed)
                      (when (nonzero? (-> self num-slaves))
                        (set! (-> self slave (+ (-> self num-slaves) -1) 0 blend-from-type) (the-as uint 0))
                        0))
                     ((= v1-0 'point-of-interest)
                      (when (nonzero? (-> self num-slaves))
                        (let ((a1-60 (new 'stack-no-clear 'event-message-block)))
                          (set! (-> a1-60 from) proc)
                          (set! (-> a1-60 num-params) argc)
                          (set! (-> a1-60 message) message)
                          (set! (-> a1-60 param 0) (-> block param 0))
                          (set! (-> a1-60 param 1) (-> block param 1))
                          (set! (-> a1-60 param 2) (-> block param 2))
                          (set! (-> a1-60 param 3) (-> block param 3))
                          (set! (-> a1-60 param 4) (-> block param 4))
                          (set! (-> a1-60 param 5) (-> block param 5))
                          (set! (-> a1-60 param 6) (-> block param 6))
                          (send-event-function (ppointer->process (-> self slave (+ (-> self num-slaves) -1))) a1-60)))
                      (let ((a1-61 (new 'stack-no-clear 'event-message-block)))
                        (set! (-> a1-61 from) proc)
                        (set! (-> a1-61 num-params) argc)
                        (set! (-> a1-61 message) message)
                        (set! (-> a1-61 param 0) (-> block param 0))
                        (set! (-> a1-61 param 1) (-> block param 1))
                        (set! (-> a1-61 param 2) (-> block param 2))
                        (set! (-> a1-61 param 3) (-> block param 3))
                        (set! (-> a1-61 param 4) (-> block param 4))
                        (set! (-> a1-61 param 5) (-> block param 5))
                        (set! (-> a1-61 param 6) (-> block param 6))
                        (send-event-function *camera-combiner* a1-61)))
                     ((= v1-0 'part-water-drip)
                      (set-time! (-> self water-drip-time))
                      (set! (-> self water-drip-mult) (the-as float (-> block param 0)))
                      (set! (-> self water-drip-speed) (the-as float (-> block param 1))))
                     (else
                      (countdown (s3-1 (-> self num-slaves))
                        (let ((a1-62 (new 'stack-no-clear 'event-message-block)))
                          (set! (-> a1-62 from) proc)
                          (set! (-> a1-62 num-params) argc)
                          (set! (-> a1-62 message) message)
                          (set! (-> a1-62 param 0) (-> block param 0))
                          (set! (-> a1-62 param 1) (-> block param 1))
                          (set! (-> a1-62 param 2) (-> block param 2))
                          (set! (-> a1-62 param 3) (-> block param 3))
                          (set! (-> a1-62 param 4) (-> block param 4))
                          (set! (-> a1-62 param 5) (-> block param 5))
                          (set! (-> a1-62 param 6) (-> block param 6))
                          (send-event-function (ppointer->process (-> self slave s3-1)) a1-62)))
                      #f))))))
        v0-0))
  :enter
    (behavior ()
      (if (and (nonzero? camera-master-debug) *debug-segment*)
        (add-connection *debug-engine* self camera-master-debug self #f #f)))
  :trans
    (behavior ()
      (when (not (paused?))
        (vector-negate! (-> self local-down) (vector-normalize-copy! (-> self local-down) (-> *standard-dynamics* gravity) 1.0))
        (cam-master-effect)))
  :code
    (behavior ()
      (loop
        (if (and *dproc* *debug-segment*)
          (add-frame (-> *display* frames (-> *display* on-screen) frame profile-bar 0)
                     'camera
                     (new 'static 'rgba :r #x40 :b #x40 :a #x80)))
        (set! (-> self string-min target y) (-> self stringMinHeight))
        (set! (-> self string-max target y) (-> self stringMaxHeight))
        (set! (-> self string-min target z) (-> self stringMinLength))
        (set! (-> self string-max target z) (-> self stringMaxLength))
        (set! (-> self string-push-z) (fmax (-> self string-min value z) (-> *CAMERA-bank* default-string-push-z)))
        (master-track-target)
        (set! (-> last-try-to-look-at-data horz) 0.0)
        (set! (-> last-try-to-look-at-data vert) 0.0)
        (when (send-event *camera* 'slave-option? #x4000)
          (set! (-> self string-min target y) 18432.0)
          (set! (-> self string-max target y) 18432.041))
        (when (not (paused?))
          (update! (-> self string-min) (the-as vector #f))
          (update! (-> self string-max) (the-as vector #f))
          (master-check-regions))
        (set! (-> self string-min value x) (fmin (-> self string-min value x) (+ -4.096 (-> self string-max value x))))
        (set! (-> self string-min value y) (fmin (-> self string-min value y) (+ -4.096 (-> self string-max value y))))
        (set! (-> self string-min value z) (fmin (-> self string-min value z) (+ -4.096 (-> self string-max value z))))
        (if (nonzero? (-> self no-intro)) (+! (-> self no-intro) -1))
        (if (nonzero? (-> self force-blend)) (+! (-> self force-blend) -1))
        (suspend))))

(deftype list-keeper (process)
  ((dummy float)))


(defstate list-keeper-active (camera-master)
  :code
    (behavior ()
      (loop
        (change-to-last-brother self)
        (suspend))))

(defbehavior list-keeper-init camera-master ()
  (go list-keeper-active)
  0
  (none))

(defbehavior cam-master-init camera-master ()
  (set! *camera* self)
  (stack-size-set! (-> self main-thread) 512)
  (logclear! (-> self mask) (process-mask menu))
  (set! (-> self master-options) (the-as uint 4))
  (set! (-> self num-slaves) 0)
  (dotimes (v1-5 2)
    (set! (-> self slave v1-5) (the-as (pointer camera-slave) #f)))
  (set! (-> self slave-options) (the-as uint 560))
  (set! (-> self view-off-param-save) 1.0)
  (set! (-> self changer) (the-as uint (process->ppointer self)))
  (set! (-> self cam-entity) #f)
  (set! (-> self stringMinHeight) (-> *CAMERA-bank* default-string-min-y))
  (set! (-> self stringMaxHeight) (-> *CAMERA-bank* default-string-max-y))
  (set! (-> self stringMinLength) (-> *CAMERA-bank* default-string-min-z))
  (set! (-> self stringMaxLength) (-> *CAMERA-bank* default-string-max-z))
  (set! (-> self stringCliffHeight) 163840.0)
  (set! (-> self no-intro) (the-as uint 0))
  (set! (-> self force-blend) (the-as uint 0))
  (set! (-> self string-push-z) (-> *CAMERA-bank* default-string-push-z))
  (let ((gp-0 (new-stack-vector0)))
    (set! (-> gp-0 y) (-> *CAMERA-bank* default-string-min-y))
    (set! (-> gp-0 z) (-> *CAMERA-bank* default-string-min-z))
    (init! (-> self string-min) gp-0 40.96 409.6 0.9)
    (set! (-> gp-0 y) (-> *CAMERA-bank* default-string-max-y))
    (set! (-> gp-0 z) (-> *CAMERA-bank* default-string-max-z))
    (init! (-> self string-max) gp-0 40.96 409.6 0.9))
  (set! (-> self outro-t-step) 0.0)
  (set! (-> self drawable-target) (the-as handle #f))
  (set! (-> self which-bone) 0)
  (let ((a1-3 (new-stack-vector0))) (tracking-spline-method-10 (-> self target-spline) a1-3))
  (set! (-> self pov-handle) (the-as handle #f))
  (set! (-> self pov-bone) 0)
  (cond
    ((process-spawn-function list-keeper list-keeper-init :from *camera-dead-pool* :to self))
    (else (format 0 "ERROR <GMJ>: master camera list keeper failed to activate~%")))
  (cond
    ((process-spawn-function camera-slave cam-slave-init cam-free-floating #f :from *camera-dead-pool* :to self))
    (else (format 0 "ERROR <GMJ>: first slave failed to activate~%")))
  (set! (-> self water-drip) (create-launch-control group-rain-screend-drop self))
  (set! (-> self water-drip-time) (seconds -60))
  (go cam-master-active)
  0
  (none))
