mirror of
https://github.com/open-goal/jak-project
synced 2026-08-06 09:54:10 -04:00
908 lines
43 KiB
Common Lisp
908 lines
43 KiB
Common Lisp
;;-*-Lisp-*-
|
|
(in-package goal)
|
|
(bundles "ENGINE.CGO" "GAME.CGO")
|
|
(require "engine/geometry/path-h.gc")
|
|
(require "engine/anim/joint-mod-h.gc")
|
|
(require "engine/game/task/task-control.gc")
|
|
(require "engine/common-obs/collectables.gc")
|
|
(require "engine/game/main.gc")
|
|
(defmacro is-nan-hack (flt)
|
|
`(and (< 0.0 ,flt) (< ,flt 0.0)))
|
|
|
|
(defmacro less-than-hack (a b)
|
|
`(if (is-nan-hack ,a) #f (< ,a ,b)))
|
|
|
|
;; DECOMP BEGINS
|
|
|
|
(defmethod setup-shadow-settings! ((this process-taskable))
|
|
"Set this character's shadow-control bottom and top plane W terms to 12288 and -4096."
|
|
(let ((shadow-ctrl (-> this draw shadow-ctrl)))
|
|
(when shadow-ctrl
|
|
(let ((shadow-ctrl-alias shadow-ctrl)) (set! (-> shadow-ctrl-alias settings bot-plane w) (- -12288.0)))
|
|
0
|
|
(set! (-> shadow-ctrl settings top-plane w) (- 4096.0))
|
|
0))
|
|
(none))
|
|
|
|
(defmethod init! ((this gui-query) (message string) (x-position int) (y-position int) (message-space int) (cancel-only? symbol) (cancel-message string))
|
|
"Initialize a prompt at x-position and y-position. message-space separates the question from
|
|
its response line; cancel-only? disables confirmation, and cancel-message labels that response."
|
|
(set! (-> this x-position) x-position)
|
|
(set! (-> this y-position) y-position)
|
|
(set! (-> this message-space) message-space)
|
|
(set! (-> this only-allow-cancel) cancel-only?)
|
|
(set! (-> this message) message)
|
|
(set! (-> this decision) 'undecided)
|
|
(set! (-> this no-msg) cancel-message)
|
|
0
|
|
(none))
|
|
|
|
(defmethod get-response ((this gui-query))
|
|
"Suppress hints and the HUD while displaying this prompt. Consume X as yes when confirmation
|
|
is allowed or triangle as no, then return yes, no, or undecided."
|
|
(kill-current-level-hint '() '(sidekick voicebox stinger) 'exit)
|
|
(level-hint-surpress!)
|
|
(hide-hud)
|
|
(when (hud-hidden?)
|
|
(when (-> this message)
|
|
(let ((message-font (new 'stack
|
|
'font-context
|
|
*font-default-matrix*
|
|
(-> this x-position)
|
|
(-> this y-position)
|
|
0.0
|
|
(font-color default)
|
|
(font-flags shadow kerning))))
|
|
(set-width! message-font (- 512 (-> this x-position)))
|
|
(set-height! message-font 40)
|
|
(set-scale! message-font 0.9)
|
|
(set-flags! message-font (font-flags shadow kerning middle-vert large))
|
|
(print-game-text (-> this message) message-font #f 128 22)))
|
|
;; og:preserve-this PAL patch here
|
|
(cond
|
|
((-> this only-allow-cancel)
|
|
(when (-> this no-msg)
|
|
(clear *temp-string*)
|
|
(format *temp-string* "; = ~S" (-> this no-msg))
|
|
(let ((response-font (new 'stack
|
|
'font-context
|
|
*font-default-matrix*
|
|
(-> this x-position)
|
|
(+ (-> this y-position) 5 (-> this message-space))
|
|
0.0
|
|
(font-color default)
|
|
(font-flags shadow kerning))))
|
|
(let ((v1-15 response-font)) (set! (-> v1-15 width) (the float 400)))
|
|
(let ((v1-16 response-font)) (set! (-> v1-16 height) (the float 100)))
|
|
(set-flags! response-font (font-flags shadow kerning large))
|
|
(print-game-text *temp-string* response-font #f 128 22))))
|
|
(else
|
|
(let ((response-font (new 'stack
|
|
'font-context
|
|
*font-default-matrix*
|
|
(-> this x-position)
|
|
(+ (-> this y-position) 5 (-> this message-space))
|
|
0.0
|
|
(font-color default)
|
|
(font-flags shadow kerning))))
|
|
(let ((v1-22 response-font)) (set! (-> v1-22 width) (the float 400)))
|
|
(let ((v1-23 response-font)) (set! (-> v1-23 height) (the float 100)))
|
|
(set-flags! response-font (font-flags shadow kerning large))
|
|
(print-game-text (lookup-text! *common-text* (text-id confirm) #f) response-font #f 128 22))))
|
|
(cond
|
|
((!= (-> this decision) 'undecided))
|
|
((and (cpad-pressed? 0 x) (not (-> this only-allow-cancel)))
|
|
(logclear! (-> *cpad-list* cpads 0 button0-abs 0) (pad-buttons x))
|
|
(logclear! (-> *cpad-list* cpads 0 button0-rel 0) (pad-buttons x))
|
|
(set! (-> this decision) 'yes))
|
|
((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))
|
|
(set! (-> this decision) 'no))))
|
|
(-> this decision))
|
|
|
|
(defmethod relocate ((this process-taskable) (offset int))
|
|
"Adjust every optional drawable controller owned by this process, then relocate the process
|
|
allocation."
|
|
(the-as process-taskable ((method-of-type process-drawable relocate) this offset)))
|
|
|
|
(defmethod update-music-and-flava! ((this process-taskable))
|
|
"Enable the configured sound flavor and music while the target is within 102400 world units,
|
|
counting vertical separation fourfold, and remove each setting after the target leaves that range."
|
|
(when (nonzero? (-> this sound-flava))
|
|
(let ((s5-1 (vector-! (new 'stack-no-clear 'vector) (target-pos 0) (-> this root root-prim prim-core world-sphere))))
|
|
(set! (-> s5-1 y) (* 4.0 (-> s5-1 y)))
|
|
(cond
|
|
;; og:preserve-this s5-1 can be nan on the first frame after something spawns
|
|
((less-than-hack (vector-length s5-1) 102400.0)
|
|
(when (not (-> this have-flava))
|
|
(set! (-> this have-flava) #t)
|
|
(set-setting! 'sound-flava #f 20.0 (-> this sound-flava))))
|
|
((-> this have-flava) (remove-setting! 'sound-flava) (set! (-> this have-flava) #f)))))
|
|
(when (-> this music)
|
|
(let ((to-target (vector-! (new 'stack-no-clear 'vector) (target-pos 0) (-> this root root-prim prim-core world-sphere))))
|
|
(set! (-> to-target y) (* 4.0 (-> to-target y)))
|
|
(cond
|
|
((< (vector-length to-target) 102400.0)
|
|
(when (not (-> this have-music))
|
|
(set! (-> this have-music) #t)
|
|
(set-setting! 'music (-> this music) 0.0 0)))
|
|
((-> this have-music) (remove-setting! 'music) (set! (-> this have-music) #f)))))
|
|
0
|
|
(none))
|
|
|
|
(defmethod get-art-elem ((this process-taskable))
|
|
"Return the art element on the active root animation channel."
|
|
(the-as art-element (if (> (-> this skel active-channels) 0) (-> this skel root-channel 0 frame-group))))
|
|
|
|
(defmethod play-anim! ((this process-taskable) (commit? symbol))
|
|
"Return this character's animation for the current task stage. commit? lets subtype
|
|
implementations apply progression changes when playback really begins; false only selects or
|
|
prefetches the animation."
|
|
(the-as basic #f))
|
|
|
|
(defmethod prefetch-play-anim! ((this process-taskable))
|
|
"Select the current play animation without committing progression and request it at streaming
|
|
priority -99 when it is spooled."
|
|
(let ((animation (play-anim! this #f)))
|
|
(if (type-type? (-> animation type) spool-anim)
|
|
(spool-push *art-control* (-> (the-as spool-anim animation) name) 0 this -99.0)))
|
|
0
|
|
(none))
|
|
|
|
(defmethod close-anim-file! ((this process-taskable))
|
|
"Return the streaming state of the current play animation's first part, or #f when it is not
|
|
a spooled animation."
|
|
(let* ((animation (play-anim! this #f))
|
|
(spooled-animation (if (and (nonzero? animation) (type-type? (-> animation type) spool-anim)) animation)))
|
|
(if spooled-animation (file-status *art-control* (-> (the-as spool-anim spooled-animation) name) 0))))
|
|
|
|
(defmethod get-accept-anim ((this process-taskable) (commit? symbol))
|
|
"Return the task-accept animation. commit? lets subtype implementations apply the accepted
|
|
choice when playback begins."
|
|
(the-as spool-anim #f))
|
|
|
|
(defmethod push-accept-anim ((this process-taskable))
|
|
"Select the task-accept animation without committing the choice and request it for streaming."
|
|
(let ((animation (get-accept-anim this #f)))
|
|
(if (type-type? (-> animation type) spool-anim) (spool-push *art-control* (-> animation name) 0 this -99.0)))
|
|
0
|
|
(none))
|
|
|
|
(defmethod get-reject-anim ((this process-taskable) (commit? symbol))
|
|
"Return the task-reject animation. commit? lets subtype implementations apply the rejected
|
|
choice when playback begins."
|
|
(the-as spool-anim #f))
|
|
|
|
(defmethod push-reject-anim ((this process-taskable))
|
|
"Select the task-reject animation without committing the choice and request it for streaming."
|
|
(let ((animation (get-reject-anim this #f)))
|
|
(if (type-type? (-> animation type) spool-anim) (spool-push *art-control* (-> animation name) 0 this -99.0)))
|
|
0
|
|
(none))
|
|
|
|
(defmethod goto-post-anim-state! ((this process-taskable))
|
|
"Enter give-cell when the task owes a reward, otherwise enter release."
|
|
(if (nonzero? (-> this cell-for-task)) (go (method-of-object this give-cell)))
|
|
(go (method-of-object this release))
|
|
(none))
|
|
|
|
(defbehavior process-taskable-anim-loop process-taskable ()
|
|
"Blend to the character's current art element when needed, then loop it indefinitely and try
|
|
ambient chatter while the next state is idle."
|
|
(when (!= (ja-group) (get-art-elem self))
|
|
(ja-channel-push! 1 (seconds 0.2))
|
|
(ja :group! (get-art-elem self)))
|
|
(loop
|
|
(suspend)
|
|
(ja :num! (loop!))
|
|
(if (= (-> self next-state name) 'idle) (try-play-ambient-chatter self)))
|
|
(the-as none 0)
|
|
(none))
|
|
|
|
(defstate release (process-taskable)
|
|
:virtual #t
|
|
:trans
|
|
(behavior ()
|
|
(when (process-release? *target*)
|
|
(send-event *target* 'trans 'restore (-> self old-target-pos))
|
|
(if (should-display? self) (go-virtual idle) (go-virtual hidden)))
|
|
(prefetch-play-anim! self)
|
|
((-> self cur-trans-hook)))
|
|
:code process-taskable-anim-loop
|
|
:post ja-post)
|
|
|
|
(defstate give-cell (process-taskable)
|
|
:virtual #t
|
|
:trans
|
|
(behavior ()
|
|
(cond
|
|
((nonzero? (-> self cell-for-task))
|
|
(let ((gp-0 (handle->process (-> self cell-x))))
|
|
(when gp-0
|
|
(send-event *target* 'trans 'reset)
|
|
(send-event gp-0 'pickup (target-pos 0))
|
|
(go-virtual idle)))
|
|
(format #t "ERROR<GMJ>: ~S no cell spawned~%" (-> self name))
|
|
(send-event *target* 'get-pickup 6 (the float (-> self cell-for-task))))
|
|
(else
|
|
(format #t
|
|
"ERROR<GMJ>: ~S got into give-cell with give-cell == #f task = ~S~%"
|
|
(-> self name)
|
|
(game-task->string (current-task (-> self tasks))))))
|
|
(go-virtual release)
|
|
(prefetch-play-anim! self)
|
|
((-> self cur-trans-hook)))
|
|
:code process-taskable-anim-loop
|
|
:post ja-post)
|
|
|
|
(defstate lose (process-taskable)
|
|
:virtual #t
|
|
:enter
|
|
(behavior ()
|
|
(set-time! (-> self state-time)))
|
|
:trans
|
|
(behavior ()
|
|
(if (and (time-elapsed? (-> self state-time) (seconds 5))
|
|
(or (not *target*) (< 20480.0 (vector-vector-distance (-> self root trans) (-> *target* control trans)))))
|
|
(go-virtual idle))
|
|
((-> self cur-trans-hook)))
|
|
:code process-taskable-anim-loop
|
|
:post ja-post)
|
|
|
|
(defstate enter-playing (process-taskable)
|
|
:virtual #t
|
|
:code process-taskable-anim-loop
|
|
:post ja-post)
|
|
|
|
(defbehavior process-taskable-play-anim-enter process-taskable ()
|
|
"Prepare task-animation playback: initialize the cancellation query, enable animation blending,
|
|
spawn the joint camera, clear reward and playback flags, and suppress ambient speech."
|
|
(init! (-> self query) (the-as string #f) 40 150 25 #t (the-as string #f))
|
|
(logior! (-> self skel status) (janim-status blerc))
|
|
(set! (-> self camera) (ppointer->handle (process-spawn othercam self (-> self cam-joint-index) #f #t :to self)))
|
|
(set! (-> self cell-for-task) (game-task none))
|
|
(set! (-> self skippable) #f)
|
|
(set! (-> self blend-on-exit) #f)
|
|
(set! (-> self will-talk) #f)
|
|
#f)
|
|
|
|
(defbehavior process-taskable-play-anim-exit process-taskable ()
|
|
"End task-animation playback by clearing blend state, stopping the joint camera, recording the
|
|
last-talk frame, and restoring the default shadow clipping planes."
|
|
(logclear! (-> self skel status) (janim-status blerc))
|
|
(let ((camera-process (handle->process (-> self camera)))) (if camera-process (deactivate camera-process)))
|
|
(set! (-> self last-talk) (-> *display* game-frame-counter))
|
|
(setup-shadow-settings! self)
|
|
(none))
|
|
|
|
(defbehavior process-taskable-play-anim-trans process-taskable ()
|
|
"Keep the other camera active, hold the letterbox transition, and update this character's shadow
|
|
during task-animation playback."
|
|
(if (nonzero? *camera-look-through-other*) (set! *camera-look-through-other* 2))
|
|
(set-letterbox-frames (seconds 0.017))
|
|
(draw-npc-shadow self)
|
|
(none))
|
|
|
|
(defbehavior process-taskable-play-anim-code process-taskable ((previous-animation art-joint-anim) (animation basic))
|
|
"Play animation for the current task interaction. Streamed animations coordinate target cloning,
|
|
movie audio levels, optional blending, and skip handling; resident joint animations seek to their
|
|
end while allowing debug cancellation. previous-animation supplies the blend source."
|
|
(when (nonzero? (-> self cell-for-task))
|
|
(if (name= (-> self state name) "play-anim")
|
|
(set! (-> self cell-x)
|
|
(ppointer->handle (process-spawn fuel-cell :init fuel-cell-init-as-clone (process->handle self) (-> self cell-for-task) :to self)))
|
|
(format #t "ERROR<GMJ>: ~S ~S trying to give cell on release~%" (-> self name) (-> self state name))))
|
|
(cond
|
|
((and animation (type-type? (-> animation type) spool-anim))
|
|
(when *target*
|
|
(while (not (send-event *target* 'clone-anim self))
|
|
(spool-push *art-control* (-> (the-as spool-anim animation) name) 0 self -99.0)
|
|
(format #t "WARNING: ~A stall on not cloning.~%" (-> self name))
|
|
(suspend))
|
|
(send-event (ppointer->process (-> *target* sidekick)) 'matrix 'play-anim)
|
|
(send-event *target* 'blend-shape #t))
|
|
(add-setting! 'music-volume 'rel (-> *setting-control* current music-volume-movie) 0)
|
|
(add-setting! 'sfx-volume 'rel (-> *setting-control* current sfx-volume-movie) 0)
|
|
(add-setting! 'ambient-volume 'rel (-> *setting-control* current ambient-volume-movie) 0)
|
|
(if (-> self blend-on-exit) (set! (-> self blend-on-exit) previous-animation))
|
|
;; og:preserve-this allow cutscene skipping on pc port
|
|
;; save a sort of timestamp just so we know if it took at least 1 frame
|
|
(#when PC_PORT
|
|
(define *play-anim-time* (current-time)))
|
|
(if (#if PC_PORT (= (-> *pc-settings* skip-movies?) #t) (and *debug-segment* *cheat-mode*))
|
|
(ja-play-spooled-anim (the-as spool-anim animation)
|
|
previous-animation
|
|
(-> self blend-on-exit)
|
|
(lambda ((taskable process-taskable))
|
|
(= (get-response (-> taskable query)) 'no)))
|
|
(ja-play-spooled-anim (the-as spool-anim animation)
|
|
previous-animation
|
|
(-> self blend-on-exit)
|
|
(the-as (function process-drawable symbol) false-func)))
|
|
;; og:preserve-this
|
|
(#when PC_PORT
|
|
(if (= (current-time) *play-anim-time*) (suspend)))
|
|
(remove-setting! 'music-volume)
|
|
(remove-setting! 'sfx-volume)
|
|
(remove-setting! 'ambient-volume)
|
|
(send-event *target* 'blend-shape #f))
|
|
(else
|
|
(when (not animation)
|
|
(format #t "ERROR<GMJ>: ~S ~S got #f from anim picker~%" (-> self name) (-> self state name))
|
|
(set! animation (ja-group)))
|
|
(when (not (type-type? (-> animation type) art-joint-anim))
|
|
(format 0
|
|
"ERROR<GMJ>: ~S ~S anim picker didn't return spool-anim or joint-art-anim (probably need to override it)~%"
|
|
(-> self name)
|
|
(-> self state name))
|
|
(set! animation (ja-group)))
|
|
(format #t "~S ~S anim ~S~%" (-> self name) (-> self state name) (-> (the-as art-joint-anim animation) name))
|
|
(ja-channel-push! 1 (seconds 0.2))
|
|
(set! (-> self skel root-channel 0 frame-group) (the-as art-joint-anim animation))
|
|
(when (< (ja-num-frames 0) 3)
|
|
(suspend)
|
|
(suspend)
|
|
0)
|
|
(ja-play :group! (ja-group)
|
|
:num! (seek!)
|
|
:frame-num 0.0
|
|
(if (and *debug-segment* (= (get-response (-> self query)) 'no)) (ja :num-func num-func-identity :frame-num max)))
|
|
#f)))
|
|
|
|
(defstate play-accept (process-taskable)
|
|
:virtual #t
|
|
:enter process-taskable-play-anim-enter
|
|
:exit process-taskable-play-anim-exit
|
|
:trans
|
|
(behavior ()
|
|
(process-taskable-play-anim-trans)
|
|
((-> self cur-trans-hook)))
|
|
:code
|
|
(behavior ()
|
|
(process-taskable-play-anim-code (the-as art-joint-anim (get-art-elem self)) (get-accept-anim self #t))
|
|
(while (not (process-release? *target*))
|
|
(suspend))
|
|
(go-virtual enter-playing))
|
|
:post ja-post)
|
|
|
|
(defstate play-reject (process-taskable)
|
|
:virtual #t
|
|
:enter process-taskable-play-anim-enter
|
|
:exit process-taskable-play-anim-exit
|
|
:trans
|
|
(behavior ()
|
|
(process-taskable-play-anim-trans)
|
|
((-> self cur-trans-hook)))
|
|
:code
|
|
(behavior ()
|
|
(process-taskable-play-anim-code (the-as art-joint-anim (get-art-elem self)) (get-reject-anim self #t))
|
|
(go-virtual release))
|
|
:post ja-post)
|
|
|
|
(defstate query (process-taskable)
|
|
:virtual #t
|
|
:enter
|
|
(behavior ()
|
|
(init! (-> self query)
|
|
(lookup-text! *common-text* (text-id confirm-play) #f)
|
|
40
|
|
150
|
|
25
|
|
#f
|
|
(lookup-text! *common-text* (text-id quit) #f)))
|
|
:exit process-taskable-play-anim-exit
|
|
:trans
|
|
(behavior ()
|
|
(case (current-status (-> self tasks))
|
|
(((task-status need-reminder-a))
|
|
(case (get-response (-> self query))
|
|
(('yes) (go-virtual play-accept))
|
|
(('no) (go-virtual play-reject)))
|
|
(push-accept-anim self))
|
|
(else
|
|
(let ((response (get-response (-> self query))))
|
|
(cond
|
|
((and (= response 'yes) (process-release? *target*)) (go-virtual enter-playing))
|
|
((= response 'no) (go-virtual play-reject))))))
|
|
(push-reject-anim self)
|
|
(set! *camera-look-through-other* 2)
|
|
((-> self cur-trans-hook)))
|
|
:code process-taskable-anim-loop
|
|
:post ja-post)
|
|
|
|
(defstate play-anim (process-taskable)
|
|
:virtual #t
|
|
:event
|
|
(behavior ((proc process) (argc int) (message symbol) (block event-message-block))
|
|
(case message
|
|
(('shadow)
|
|
(cond
|
|
((-> block param 0)
|
|
(let ((shadow (the-as object (-> self shadow-backup)))) (set! (-> self draw shadow) (the-as shadow-geo shadow)) shadow))
|
|
(else (set! (-> self draw shadow) #f) #f)))
|
|
(('shadow-min-max)
|
|
(let ((shadow-ctrl (-> self draw shadow-ctrl)))
|
|
(let ((shadow-ctrl-alias shadow-ctrl))
|
|
(set! (-> shadow-ctrl-alias settings bot-plane w) (- (the-as float (-> block param 0)))))
|
|
0
|
|
(set! (-> shadow-ctrl settings top-plane w) (- (the-as float (-> block param 1)))))
|
|
0)))
|
|
:enter process-taskable-play-anim-enter
|
|
:exit process-taskable-play-anim-exit
|
|
:trans
|
|
(behavior ()
|
|
(process-taskable-play-anim-trans)
|
|
(let ((reward-cell (handle->process (-> self cell-x))))
|
|
(if reward-cell (spool-push *art-control* (-> self fuel-cell-anim name) 0 reward-cell -99.0)))
|
|
((-> self cur-trans-hook)))
|
|
:code
|
|
(behavior ()
|
|
(process-taskable-play-anim-code (the-as art-joint-anim (get-art-elem self)) (play-anim! self #t))
|
|
(goto-post-anim-state! self))
|
|
:post ja-post)
|
|
|
|
(defbehavior process-taskable-clean-up-after-talking process-taskable ()
|
|
"Restore this character's visibility and animation initialization state, then remove the
|
|
conversation border and talking settings."
|
|
(logclear! (-> self draw status) (draw-status hidden))
|
|
(logclear! (-> self skel status) (janim-status inited))
|
|
(remove-setting! 'border-mode)
|
|
(remove-setting! 'talking)
|
|
(none))
|
|
|
|
(defmethod should-display? ((this process-taskable))
|
|
"Return whether this taskable character should be visible."
|
|
#t)
|
|
|
|
(defbehavior process-taskable-hide-handler process-taskable ((proc process) (argc int) (message symbol) (block event-message-block))
|
|
"Handle clone, play-anim, and hidden-other messages while this character is hidden."
|
|
(case message
|
|
(('clone) (go-virtual be-clone (the-as handle (-> block param 0))))
|
|
(('play-anim) (logclear! (-> self mask) (process-mask actor-pause)) (set! (-> self been-kicked) #t) (go-virtual idle))
|
|
(('hidden-other) (go-virtual hidden-other))))
|
|
|
|
(defbehavior process-taskable-hide-enter process-taskable ()
|
|
"Enter hidden mode by recording the state time, disabling shadow drawing, clearing conversation
|
|
settings and collision, selecting no animation channels, and finishing animation postprocessing."
|
|
(set-time! (-> self state-time))
|
|
(let ((shadow-ctrl (-> self draw shadow-ctrl))) (logior! (-> shadow-ctrl settings flags) (shadow-flags disable-draw)))
|
|
0
|
|
(process-taskable-clean-up-after-talking)
|
|
(clear-collide-with-as (-> self root))
|
|
(ja-channel-set! 0)
|
|
(the-as int (ja-post)))
|
|
|
|
(defbehavior process-taskable-hide-exit process-taskable ((staying-hidden? symbol))
|
|
"Leave no-kill disabled when remaining hidden. Otherwise restore animation, collision, no-kill,
|
|
and shadow drawing as the character becomes active."
|
|
(cond
|
|
(staying-hidden? (process-entity-status! self (entity-perm-status no-kill) #f))
|
|
(else
|
|
(ja-channel-set! 1)
|
|
(ja :group! (get-art-elem self))
|
|
(restore-collide-with-as (-> self root))
|
|
(process-entity-status! self (entity-perm-status no-kill) #t)
|
|
(let ((shadow-ctrl-alias (-> self draw shadow-ctrl)))
|
|
(logclear! (-> shadow-ctrl-alias settings flags) (shadow-flags disable-draw)))
|
|
0))
|
|
(none))
|
|
|
|
(defstate hidden (process-taskable)
|
|
:virtual #t
|
|
:event process-taskable-hide-handler
|
|
:enter process-taskable-hide-enter
|
|
:exit
|
|
(behavior ()
|
|
(process-taskable-hide-exit (= (-> self next-state name) 'hidden)))
|
|
:trans
|
|
(behavior ()
|
|
(if (time-elapsed? (-> self state-time) (seconds 1)) (process-entity-status! self (entity-perm-status no-kill) #f))
|
|
(if (or (-> self been-kicked) (should-display? self)) (go-virtual idle)))
|
|
:code anim-loop)
|
|
|
|
;; WARN: disable def twice: 4. This may happen when a cond (no else) is nested inside of another conditional, but it should be rare.
|
|
(defmethod target-far-away? ((this process-taskable))
|
|
"Return whether the target is more than 245760 world units from this character. Without a
|
|
target, compare the camera against the collision sphere using the corresponding squared distance."
|
|
(if *target*
|
|
(or (not *target*) (< 245760.0 (vector-vector-distance (-> this root trans) (-> *target* control trans))))
|
|
(< 60397978000.0 (vector-vector-distance-squared (-> this root root-prim prim-core world-sphere) (camera-pos)))))
|
|
|
|
(defstate hidden-other (process-taskable)
|
|
:virtual #t
|
|
:event process-taskable-hide-handler
|
|
:enter process-taskable-hide-enter
|
|
:exit
|
|
(behavior ()
|
|
(process-taskable-hide-exit (= (-> self next-state name) 'hidden-other)))
|
|
:trans
|
|
(behavior ()
|
|
(if (time-elapsed? (-> self state-time) (seconds 1)) (process-entity-status! self (entity-perm-status no-kill) #f))
|
|
(cond
|
|
((-> self been-kicked) (go-virtual idle))
|
|
((target-far-away? self) (if (should-display? self) (go-virtual idle) (go-virtual hidden)))))
|
|
:code anim-loop)
|
|
|
|
(defstate be-clone (process-taskable)
|
|
:virtual #t
|
|
:event
|
|
(behavior ((proc process) (argc int) (message symbol) (block event-message-block))
|
|
(the-as shadow-geo
|
|
(case message
|
|
(('shadow)
|
|
(the-as shadow-geo
|
|
(cond
|
|
((-> block param 0) (let ((v0-0 (-> self shadow-backup))) (set! (-> self draw shadow) v0-0) v0-0))
|
|
(else (set! (-> self draw shadow) #f) (the-as shadow-geo #f)))))
|
|
(('shadow-min-max)
|
|
(let ((v1-5 (-> self draw shadow-ctrl)))
|
|
(let ((a0-5 v1-5)) (set! (-> a0-5 settings bot-plane w) (- (the-as float (-> block param 0)))))
|
|
0
|
|
(set! (-> v1-5 settings top-plane w) (- (the-as float (-> block param 1)))))
|
|
(the-as shadow-geo 0))
|
|
(('end-mode)
|
|
(the-as shadow-geo
|
|
(if (should-display? self) (the-as shadow-geo (go-virtual idle)) (the-as shadow-geo (go-virtual hidden))))))))
|
|
:enter
|
|
(behavior ((source-handle handle))
|
|
(logior! (-> self skel status) (janim-status blerc))
|
|
(logclear! (-> self mask) (process-mask actor-pause))
|
|
(set-vector! (-> self draw bounds) 0.0 (-> self draw-bounds-y-offset) 0.0 (-> self draw bounds w)))
|
|
:exit
|
|
(behavior ()
|
|
(logclear! (-> self skel status) (janim-status blerc spool))
|
|
(logior! (-> self mask) (process-mask actor-pause))
|
|
(let ((entity-transform (-> self entity extra trans)))
|
|
(if entity-transform (vector-copy! (-> self root trans) entity-transform)))
|
|
(ja-channel-set! 0))
|
|
:trans
|
|
(behavior ()
|
|
(draw-npc-shadow self)
|
|
((-> self cur-trans-hook)))
|
|
:code
|
|
(behavior ((source-handle handle))
|
|
(clone-anim source-handle (-> self center-joint-index) #t "")
|
|
(format #t "ERROR<GMJ>: handle invalid while ~S is cloning~%" (-> self name))
|
|
(go-virtual hidden)))
|
|
|
|
(defmethod target-above-threshold? ((this process-taskable))
|
|
"Return whether the target is above this character's interaction threshold."
|
|
#t)
|
|
|
|
(defstate idle (process-taskable)
|
|
:virtual #t
|
|
:event
|
|
(behavior ((proc process) (argc int) (message symbol) (block event-message-block))
|
|
(the-as symbol
|
|
(case message
|
|
(('attack)
|
|
(the-as symbol
|
|
(if (-> self bounce-away)
|
|
(the-as symbol (send-event proc 'shove #f (static-attack-info ((shove-back (meters 3)) (shove-up (meters 1)))))))))
|
|
(('touch)
|
|
(the-as symbol
|
|
(send-shove-back (-> self root) proc (the-as touching-shapes-entry (-> block param 0)) 0.7 6144.0 16384.0)))
|
|
(('clone) (the-as symbol (go-virtual be-clone (the-as handle (-> block param 0)))))
|
|
(('play-anim)
|
|
(logclear! (-> self mask) (process-mask actor-pause))
|
|
(let ((v0-0 #t)) (set! (-> self been-kicked) v0-0) v0-0))
|
|
(('hidden-other) (the-as symbol (go-virtual hidden-other))))))
|
|
:enter
|
|
(behavior ()
|
|
(set-time! (-> self state-time))
|
|
(process-taskable-clean-up-after-talking))
|
|
:exit
|
|
(behavior ()
|
|
(cond
|
|
((or (= (-> self next-state name) 'dead-state) (= (-> self next-state name) 'idle))
|
|
(process-entity-status! self (entity-perm-status no-kill) #f))
|
|
(else
|
|
(kill-current-level-hint '() '() 'exit)
|
|
(logior! (-> self skel status) (janim-status inited))
|
|
(logclear! (-> self mask) (process-mask actor-pause))
|
|
(process-entity-status! self (entity-perm-status no-kill) #t)
|
|
(set-setting! 'border-mode #f 0.0 0)
|
|
(set-setting! 'talking (process->ppointer self) 0.0 0)
|
|
(apply-settings *setting-control*))))
|
|
:trans
|
|
(behavior ()
|
|
(when (time-elapsed? (-> self state-time) (seconds 0.2))
|
|
(logior! (-> self mask) (process-mask actor-pause))
|
|
(process-entity-status! self (entity-perm-status no-kill) #f))
|
|
(cond
|
|
((not *target*))
|
|
((not (-> self will-talk))
|
|
(if (>= (- (-> *display* game-frame-counter) (-> self last-talk)) (seconds 10)) (set! (-> self will-talk) #t)))
|
|
((begin
|
|
(update-music-and-flava! self)
|
|
(and (not (and (logtest? (-> *target* control mod-surface flags) (surface-flags jump))
|
|
(not (logtest? (-> *target* control status) (collide-status on-surface)))))
|
|
(< (-> (target-pos 0) y) (+ 8192.0 (-> self root root-prim prim-core world-sphere y)))
|
|
;; og:preserve-this
|
|
(less-than-hack (vector-vector-distance (target-pos 0) (the-as vector (-> self root root-prim prim-core))) 32768.0)
|
|
(= (-> *level* loading-level) (-> *level* level-default))
|
|
(not (movie?))
|
|
(not (level-hint-displayed?))
|
|
(none-reserved? *art-control*)
|
|
(not *progress-process*)
|
|
(and (not (handle->process (-> *game-info* other-camera-handle))) (close-anim-file! self))))
|
|
(first-any (-> self tasks) #t)
|
|
(when (target-above-threshold? self)
|
|
(case (current-status (-> self tasks))
|
|
(((task-status need-hint)
|
|
(task-status need-introduction)
|
|
(task-status need-reminder)
|
|
(task-status need-reminder-a)
|
|
(task-status need-reward-speech))
|
|
(kill-current-level-hint '() '(sidekick voicebox ambient) 'exit)
|
|
(level-hint-surpress!)
|
|
(hide-hud)
|
|
(when (and (hud-hidden?) (can-grab-display? self))
|
|
(let ((gp-1 (new 'stack 'font-context *font-default-matrix* 32 140 0.0 (font-color default) (font-flags shadow kerning))))
|
|
(set-width! gp-1 440)
|
|
(set-height! gp-1 60)
|
|
(set-scale! gp-1 0.9)
|
|
(set-flags! gp-1 (font-flags shadow kerning middle-vert large))
|
|
(print-game-text (lookup-text! *common-text* (-> self talk-message) #f) gp-1 #f 128 22))
|
|
(when (and (cpad-pressed? 0 circle) (process-grab? *target*))
|
|
(logclear! (-> *cpad-list* cpads 0 button0-abs 0) (pad-buttons circle))
|
|
(logclear! (-> *cpad-list* cpads 0 button0-rel 0) (pad-buttons circle))
|
|
(send-event *target* 'trans 'save (-> self old-target-pos))
|
|
(go-virtual play-anim))))))))
|
|
(if (= (-> *level* loading-level) (-> *level* level-default)) (prefetch-play-anim! self))
|
|
(draw-npc-shadow self)
|
|
(when (and (-> self been-kicked)
|
|
(and (not *progress-process*) (process-grab? *target*) (not (handle->process (-> *game-info* other-camera-handle)))))
|
|
(set! (-> self been-kicked) #f)
|
|
(send-event *target* 'trans 'save (-> self old-target-pos))
|
|
(go-virtual play-anim))
|
|
((-> self cur-trans-hook)))
|
|
:code process-taskable-anim-loop
|
|
:post
|
|
(behavior ()
|
|
(when *target*
|
|
(when (!= (-> self neck-joint-index) -1)
|
|
(let ((neck-position (new 'stack-no-clear 'vector)))
|
|
(vector<-cspace! neck-position (-> self node-list data (-> self neck-joint-index)))
|
|
(if *target* (look-at-enemy! (-> *target* neck) neck-position 'nothing self)))))
|
|
(transform-post)))
|
|
|
|
(defmethod initialize-collision ((this process-taskable) (center-joint int) (local-sphere vector))
|
|
"Build this character's solid, indestructible enemy collision sphere at center-joint. Set its
|
|
navigation radius to three quarters of the sphere radius, save its collision mask, and install it
|
|
as the drawable root."
|
|
(let ((collision (new 'process 'collide-shape this (collide-list-enum hit-by-player))))
|
|
(let ((collision-sphere (new 'process 'collide-shape-prim-sphere collision (the-as uint 0))))
|
|
(set! (-> collision-sphere prim-core collide-as) (collide-kind enemy))
|
|
(set! (-> collision-sphere collide-with) (collide-kind target))
|
|
(set! (-> collision-sphere prim-core action) (collide-action solid))
|
|
(set! (-> collision-sphere prim-core offense) (collide-offense indestructible))
|
|
(set! (-> collision-sphere transform-index) center-joint)
|
|
(set-vector! (-> collision-sphere local-sphere)
|
|
(-> local-sphere x)
|
|
(-> local-sphere y)
|
|
(-> local-sphere z)
|
|
(-> local-sphere w))
|
|
(set-root-prim! collision collision-sphere))
|
|
(set! (-> collision nav-radius) (* 0.75 (-> collision root-prim local-sphere w)))
|
|
(backup-collide-with-as collision)
|
|
(set! (-> this root) collision))
|
|
0
|
|
(none))
|
|
|
|
(defmethod init-as-taskable! ((this process-taskable) (actor object) (skel-group skeleton-group) (center-joint int) (cam-joint int) (local-sphere vector) (neck-joint int))
|
|
"Initialize collision, drawable and skeleton state, joint indices, interaction defaults,
|
|
ambient state, and shadow control for a taskable character."
|
|
(stack-size-set! (-> this main-thread) 512)
|
|
(initialize-collision this center-joint local-sphere)
|
|
(process-drawable-from-entity! this (the-as entity-actor actor))
|
|
(initialize-skeleton this skel-group '())
|
|
(set! (-> this shadow-backup) (-> this draw shadow))
|
|
(logior! (-> this skel status) (janim-status eye))
|
|
;; og:preserve-this
|
|
(#when PC_PORT
|
|
(set! (-> this skel postbind-function) process-drawable-joint-callback-pc))
|
|
(set! (-> this root pause-adjust-distance) -122880.0)
|
|
(set! (-> this fuel-cell-anim) (fuel-cell-pick-anim this))
|
|
(set! (-> this draw origin-joint-index) (the-as uint center-joint))
|
|
(set! (-> this draw shadow-joint-index) (the-as uint center-joint))
|
|
(set! (-> this center-joint-index) center-joint)
|
|
(set! (-> this draw-bounds-y-offset) (-> this draw bounds y))
|
|
(set! (-> this have-flava) #f)
|
|
(set! (-> this music) #f)
|
|
(set! (-> this have-music) #f)
|
|
(set! (-> this cam-joint-index) cam-joint)
|
|
(set! (-> this cell-x) (the-as handle #f))
|
|
(set! (-> this cell-for-task) (game-task none))
|
|
(set! (-> this camera) (the-as handle #f))
|
|
(set! (-> this will-talk) #t)
|
|
(set! (-> this talk-message) (text-id press-to-talk))
|
|
(set! (-> this last-talk) 0)
|
|
(set! (-> this bounce-away) #t)
|
|
(set! (-> this been-kicked) #f)
|
|
(set! (-> this neck-joint-index) neck-joint)
|
|
(set! (-> this cur-trans-hook) nothing)
|
|
(ambient-control-method-9 (-> this ambient))
|
|
(set! (-> this event-hook) (-> (method-of-object this idle) event))
|
|
(set! (-> this draw shadow-ctrl) (new 'process 'shadow-control 0.0 0.0 614400.0 (the-as float 60) 245760.0))
|
|
(setup-shadow-settings! this)
|
|
0
|
|
(none))
|
|
|
|
(defmethod goto-initial-state! ((this process-taskable))
|
|
"Enter hidden when the character should not display, give-cell when its current stage needs
|
|
resolution, and idle otherwise."
|
|
(cond
|
|
((not (should-display? this)) (go (method-of-object this hidden)))
|
|
((= (current-status (-> this tasks)) (task-status need-resolution)) (go (method-of-object this give-cell)))
|
|
(else (go (method-of-object this idle))))
|
|
(none))
|
|
|
|
(defmethod try-play-ambient-chatter ((this process-taskable))
|
|
"Try to play character-specific ambient speech. The base implementation does nothing."
|
|
(the-as symbol 0))
|
|
|
|
(defmethod ambient-control-method-9 ((this ambient-control))
|
|
"Restart the ambient-chatter cooldown at the current gameplay frame."
|
|
(set! (-> this last-ambient-time) (-> *display* game-frame-counter))
|
|
0
|
|
(none))
|
|
|
|
(defmethod ambient-control-method-10 ((this ambient-control) (out-vector vector) (cooldown time-frame) (max-distance float) (speaker process-drawable))
|
|
"Fill out-vector with the displacement from the listener to speaker and return it only when
|
|
cooldown ticks have elapsed and the speaker is within max-distance. Return #f otherwise."
|
|
(when (< (- (-> *display* game-frame-counter) (-> this last-ambient-time)) cooldown)
|
|
(set! out-vector (the-as vector #f))
|
|
(goto cfg-6))
|
|
(vector-for-ambient speaker out-vector)
|
|
(when (< max-distance (vector-length out-vector))
|
|
(set! out-vector (the-as vector #f))
|
|
(goto cfg-6))
|
|
(label cfg-6)
|
|
out-vector)
|
|
|
|
(defmethod play-ambient ((this ambient-control) (name string) (force? symbol) (position vector))
|
|
"Play name as positional ambient speech when it differs from the previous line, hint
|
|
conditions permit it, and the normal level is active. force bypasses the hint-availability test."
|
|
(when (and (not (string= name (-> this last-ambient)))
|
|
(or force? (can-hint-be-played? (text-id one) (the-as entity #f) (the-as string #f)))
|
|
(= (-> *level* loading-level) (-> *level* level-default))
|
|
(ambient-hint-spawn name position *entity-pool* 'ambient))
|
|
(set! (-> this last-ambient-time) (-> *display* game-frame-counter))
|
|
(set! (-> this last-ambient) name)
|
|
(return #t))
|
|
#f)
|
|
|
|
(defun vector-for-ambient ((speaker process-drawable) (out-vector vector))
|
|
"Write the displacement from the target, or from the camera when no target exists, to speaker
|
|
into out-vector and return it."
|
|
(if *target*
|
|
(vector-! out-vector (target-pos 0) (-> speaker root trans))
|
|
(vector-! out-vector (camera-pos) (-> speaker root trans)))
|
|
out-vector)
|
|
|
|
(defun othercam-calc ((joint-scale float))
|
|
"Set the other camera's field of view from the authored camera joint's uniform scale using
|
|
2 * atan(14.941477 / (20.3 * joint-scale)). Larger joint scales therefore narrow the view."
|
|
(set! (-> *camera-other-fov* data) (* 2.0 (atan (/ 14.941477 (* 20.3 joint-scale)) 1.0)))
|
|
(none))
|
|
|
|
(defstate othercam-running (othercam)
|
|
:event
|
|
(behavior ((proc process) (argc int) (message symbol) (block event-message-block))
|
|
(local-vars (v0-0 object))
|
|
(case message
|
|
(('die) (set! v0-0 #t) (set! (-> self die?) (the-as symbol v0-0)) v0-0)
|
|
(('joint)
|
|
(let ((t9-0 type-type?)
|
|
(joint-selector (-> block param 0)))
|
|
(cond
|
|
((t9-0 (rtype-of joint-selector) string)
|
|
(let ((joint-art (lookup-art (-> (the-as process-taskable (-> self hand process 0)) draw jgeo)
|
|
(the-as string (-> block param 0))
|
|
(the-as type #f))))
|
|
(when joint-art
|
|
(set! v0-0 (+ (-> joint-art number) 1))
|
|
(set! (-> self cam-joint-index) (the-as int v0-0))
|
|
v0-0)))
|
|
((not (logtest? (-> block param 0) 7))
|
|
(set! v0-0 (-> block param 0))
|
|
(set! (-> self cam-joint-index) (the-as int v0-0))
|
|
v0-0))))
|
|
(('mask) (set! v0-0 (-> block param 0)) (set! (-> self mask-to-clear) (the-as process-mask v0-0)) v0-0)))
|
|
:enter
|
|
(behavior ()
|
|
(hide-hud-quick)
|
|
(case (-> self spooling?)
|
|
(('logo))
|
|
(else
|
|
(add-setting! 'process-mask 'set 0.0 (-> self mask-to-clear))
|
|
(add-setting! 'movie (process->ppointer self) 0.0 0)
|
|
(if (not (-> self border-value)) (add-setting! 'border-mode (-> self border-value) 0.0 0))))
|
|
(set! (-> self had-valid-frame) #f)
|
|
(let ((parent (-> self hand process 0)))
|
|
(vector<-cspace! (-> self old-pos) (-> (the-as process-taskable parent) node-list data (-> self cam-joint-index)))
|
|
(let ((joint-transform (-> (the-as process-taskable parent) node-list data (-> self cam-joint-index) bone transform)))
|
|
(vector-normalize-copy! (-> self old-mat-z) (-> joint-transform vector 2) -1.0)))
|
|
(apply-settings *setting-control*))
|
|
:exit
|
|
(behavior ()
|
|
(remove-setting! 'process-mask)
|
|
(apply-settings *setting-control*))
|
|
:code
|
|
(behavior ()
|
|
(loop
|
|
(let ((parent (-> self hand process 0)))
|
|
(when (not parent)
|
|
(format #t "ERROR<GMJ>: othercam parent invalid~%")
|
|
(deactivate self))
|
|
(vector-copy! *camera-other-root* (-> (the-as process-taskable parent) root trans))
|
|
(let ((joint-transform (-> (the-as process-taskable parent) node-list data (-> self cam-joint-index) bone transform))
|
|
(joint-scale (-> (the-as process-taskable parent) node-list data (-> self cam-joint-index) bone scale))
|
|
(camera-forward (new 'stack-no-clear 'vector))
|
|
(camera-position (new 'stack-no-clear 'vector))
|
|
(frame-ready? (or (!= (-> self spooling?) #t) (logtest? (-> (the-as process-taskable parent) skel status) (janim-status spool)))))
|
|
(vector<-cspace! camera-position (-> (the-as process-taskable parent) node-list data (-> self cam-joint-index)))
|
|
(vector-normalize-copy! camera-forward (-> joint-transform vector 2) -1.0)
|
|
(when frame-ready?
|
|
(when (not (-> self had-valid-frame))
|
|
(set! (-> self had-valid-frame) #t)
|
|
(vector-copy! (-> self old-pos) camera-position)
|
|
(vector-copy! (-> self old-mat-z) camera-forward))
|
|
(when #t
|
|
(vector-copy! *camera-other-trans* camera-position)
|
|
(vector-normalize-copy! (-> *camera-other-matrix* vector 0) (-> joint-transform vector 0) -1.0)
|
|
(set! (-> *camera-other-matrix* vector 0 w) 0.0)
|
|
(vector-normalize-copy! (-> *camera-other-matrix* vector 1) (-> joint-transform vector 1) 1.0)
|
|
(set! (-> *camera-other-matrix* vector 1 w) 0.0)
|
|
(vector-normalize-copy! (-> *camera-other-matrix* vector 2) (-> joint-transform vector 2) -1.0)
|
|
(set! (-> *camera-other-matrix* vector 2 w) 0.0)
|
|
(vector-reset! (-> *camera-other-matrix* vector 3))
|
|
(othercam-calc (-> joint-scale x)))
|
|
(set! *camera-look-through-other* 2)
|
|
(vector-copy! (-> self old-pos) camera-position)
|
|
(vector-copy! (-> self old-mat-z) camera-forward))))
|
|
(suspend)
|
|
(let ((parent (-> self hand process 0)))
|
|
(when (or (-> self die?) (and (not (-> self survive-anim-end?)) (ja-anim-done? parent)))
|
|
(let ((wait-start (current-time)))
|
|
(while (and (not (time-elapsed? wait-start (seconds 60)))
|
|
(or (and (-> self entity) (not (is-object-visible? (-> self entity extra level) (-> self entity extra vis-id))))
|
|
(< 81920.0 (vector-vector-distance (camera-pos) (-> *math-camera* trans)))))
|
|
(suspend)))
|
|
(deactivate self))))))
|
|
|
|
(defbehavior othercam-init-by-other othercam ((owner process-taskable) (cam-joint-index symbol) (survive-anim-end? symbol) (spooling-mode symbol))
|
|
"Attach this camera process to cam-joint-index on owner. Configure movie masking, whether the
|
|
camera survives the animation ending, and normal, spooling, or logo behavior before entering
|
|
othercam-running."
|
|
(set! (-> self spooling?) spooling-mode)
|
|
(case (-> self spooling?)
|
|
(('logo))
|
|
(else (set! (-> *game-info* other-camera-handle) (process->handle self))))
|
|
(set! (-> self hand) (process->handle owner))
|
|
(set! (-> self cam-joint-index) (the-as int cam-joint-index))
|
|
(logclear! (-> self mask) (process-mask pause menu actor-pause))
|
|
(set! (-> self border-value) #f)
|
|
(set! (-> self die?) #f)
|
|
(set! (-> self survive-anim-end?) survive-anim-end?)
|
|
(set! (-> self mask-to-clear) (process-mask movie enemy platform projectile))
|
|
(set! (-> self event-hook) (-> othercam-running event))
|
|
(go othercam-running)
|
|
0
|
|
(none))
|
|
|
|
(defmethod draw-npc-shadow ((this process-taskable))
|
|
"Update this character's shadow planes and sun direction when its highest-detail geometry was
|
|
drawn this frame; otherwise disable the shadow."
|
|
(let ((shadow-ctrl (-> this draw shadow-ctrl)))
|
|
(cond
|
|
((and (-> this draw shadow) (zero? (-> this draw cur-lod)) (logtest? (-> this draw status) (draw-status was-drawn)))
|
|
(collide-to-find-planes shadow-ctrl (-> this draw origin) -4096.0 4096.0 32768.0)
|
|
(update-direction-from-time-of-day shadow-ctrl))
|
|
(else
|
|
(let ((shadow-ctrl-alias shadow-ctrl)) (logior! (-> shadow-ctrl-alias settings flags) (shadow-flags disable-draw)))
|
|
0)))
|
|
(none))
|