mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 21:27:52 -04:00
c9fc4f0bf9
* first draft eye renderer * working * working
2200 lines
74 KiB
Common Lisp
2200 lines
74 KiB
Common Lisp
;;-*-Lisp-*-
|
|
(in-package goal)
|
|
|
|
;; name: level.gc
|
|
;; name in dgo: level
|
|
;; dgos: GAME, ENGINE
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;
|
|
;; level info/names
|
|
;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(defun lookup-level-info ((name symbol))
|
|
"Get the level-load-info of a level using its name. name can be the level name, the visname or the nickname. First match is returned."
|
|
|
|
(let* ((rest *level-load-list*)
|
|
(current-sym (the symbol (car rest)))
|
|
)
|
|
(while (not (null? rest))
|
|
(let ((info (the level-load-info (-> current-sym value))))
|
|
(if (or (= name (-> info name))
|
|
(= name (-> info visname))
|
|
(= name (-> info nickname))
|
|
)
|
|
(return info)
|
|
)
|
|
)
|
|
(set! rest (cdr rest))
|
|
(set! current-sym (the symbol (car rest)))
|
|
)
|
|
)
|
|
default-level
|
|
)
|
|
|
|
|
|
(defmethod load-command-get-index level-group ((obj level-group) (name symbol) (cmd-idx int))
|
|
"Get the n-th load command for the given level."
|
|
(let ((cmd-lst (-> (lookup-level-info name) alt-load-commands)))
|
|
(while (nonzero? cmd-idx)
|
|
(+! cmd-idx -1)
|
|
(set! cmd-lst (cdr cmd-lst))
|
|
(nop!)
|
|
(nop!)
|
|
(nop!)
|
|
)
|
|
(the-as pair (car cmd-lst))
|
|
)
|
|
)
|
|
|
|
(defun remap-level-name ((level-info level-load-info))
|
|
"Get the canonical name for a level using its level-load-info"
|
|
|
|
(if (-> *level* vis?)
|
|
(-> level-info visname)
|
|
(-> level-info name)
|
|
)
|
|
)
|
|
|
|
(defmethod art-group-get-by-name level ((obj level) (arg0 string))
|
|
"Get the art group in the given level with the given name.
|
|
If it doesn't exist, #f."
|
|
(countdown (i (-> obj art-group art-group-array length))
|
|
(if (name= (-> obj art-group art-group-array i name) arg0)
|
|
(return (-> obj art-group art-group-array i))
|
|
)
|
|
)
|
|
(the-as art-group #f)
|
|
)
|
|
|
|
(defmethod bsp-name level ((obj level))
|
|
"Get the name of the bsp tree of the level"
|
|
|
|
(if (and (!= (-> obj status) 'inactive)
|
|
(-> obj bsp)
|
|
(nonzero? (-> obj bsp name))
|
|
)
|
|
(-> obj bsp name)
|
|
(-> obj name)
|
|
)
|
|
)
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; BSP
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; The "bsp" is the big data structure that contains the level geometry.
|
|
|
|
;; the background draw engine will use this function to draw an entire level's background.
|
|
;; The actual drawing is executed with (execute-connections *background-draw-engine* ...)
|
|
;; in drawable.gc
|
|
|
|
(defun add-bsp-drawable ((arg0 bsp-header) (arg1 level) (arg2 symbol) (arg3 display-frame))
|
|
"Draw a level!"
|
|
;; do the draw
|
|
(draw arg0 arg0 arg3)
|
|
|
|
(if (nonzero? *display-strip-lines*)
|
|
(debug-draw arg0 arg0 arg3)
|
|
)
|
|
(none)
|
|
)
|
|
|
|
|
|
(defmethod print level ((obj level))
|
|
"print a level."
|
|
|
|
(format #t "#<~A ~A ~S @ #x~X>"
|
|
(-> obj type)
|
|
(-> obj status)
|
|
(-> obj name)
|
|
obj
|
|
)
|
|
obj
|
|
)
|
|
|
|
(defmethod relocate bsp-header ((obj bsp-header) (dest-heap kheap) (name (pointer uint8)))
|
|
"Handle a bsp file load."
|
|
|
|
;; we expect that we'll have a loading-level set when we link/login a bsp-header
|
|
(let ((s5-0 (-> *level* loading-level)))
|
|
(if s5-0
|
|
(cond
|
|
(obj
|
|
(cond
|
|
((not (type-type? (-> obj type) bsp-header))
|
|
(format 0 "ERROR: level ~A is not a bsp-header.~%" (-> s5-0 name))
|
|
(the-as bsp-header #f)
|
|
)
|
|
((not (file-info-correct-version? (-> obj info) (file-kind level-bt) 0))
|
|
(the-as bsp-header #f)
|
|
)
|
|
((< 2048 (-> obj visible-list-length))
|
|
(format 0 "ERROR: level ~A visible-list-length ~d is greater than 2048 (16384 drawables).~%"
|
|
(-> s5-0 name)
|
|
(-> obj visible-list-length)
|
|
)
|
|
(the-as bsp-header #f)
|
|
)
|
|
(else
|
|
(load-dbg "bsp relocate: ~A~%" obj)
|
|
;; everything is okay, link the bsp and level.
|
|
(set! (-> s5-0 bsp) obj)
|
|
(set! (-> obj level) s5-0)
|
|
obj
|
|
)
|
|
)
|
|
)
|
|
(else
|
|
(format 0 "ERROR: level ~A is not a valid file.~%"
|
|
(-> s5-0 name)
|
|
)
|
|
(the-as bsp-header #f)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(none)
|
|
)
|
|
|
|
(defmethod load-required-packages level ((obj level))
|
|
"Load required packages for the level. This is mostly useless, but might load common.
|
|
This will have no effect most of the time - common is often loaded at boot as part of
|
|
game.cgo."
|
|
(when (not (or (not (-> obj bsp)) (= *kernel-boot-mode* 'debug-boot)))
|
|
(if (not (null? (-> obj info packages)))
|
|
(load-package "common" global)
|
|
)
|
|
)
|
|
obj
|
|
)
|
|
|
|
;;;;;;;;;;;;;;
|
|
;; vis
|
|
;;;;;;;;;;;;;;
|
|
|
|
(defmethod vis-clear level ((obj level))
|
|
"Clear the visibility info for when the level is loading."
|
|
|
|
;; clear vis-infos, so we can't try to look up a vis string.
|
|
(countdown (v1-0 8)
|
|
(nop!) ;; the usual.
|
|
(set! (-> obj vis-info v1-0) #f)
|
|
)
|
|
;; set the vis string to all 0s.
|
|
(dotimes (v1-3 128)
|
|
(set! (deref int128 (-> obj vis-bits) v1-3) (the-as int128 0))
|
|
)
|
|
;; this flag indicates we don't have vis data because loading is in progress
|
|
(set! (-> obj all-visible?) 'loading)
|
|
0
|
|
)
|
|
|
|
|
|
(defmethod vis-load level ((obj level))
|
|
"Start the initial load of a VIS file to the IOP VIS buffer. After this is done, we can use
|
|
ramdisk-load to load chunks."
|
|
|
|
;; check to see if we have a buffer for loaded vis data.
|
|
(when (zero? (-> obj vis-info (-> obj vis-self-index) ramdisk))
|
|
;; nope, we have no vis data buffer, we need to set it up.
|
|
|
|
;; first, we should see if the other level has loaded vis. if so, kill it.
|
|
(let ((vis (-> obj other vis-info (-> obj other vis-self-index))))
|
|
(when (and vis (nonzero? (-> vis ramdisk)))
|
|
(set! (-> vis flags) (logand #xffffffffbfffffff (-> vis flags))) ;; clear waiting-for-load
|
|
(set! (-> vis ramdisk) 0)
|
|
0
|
|
)
|
|
)
|
|
|
|
;; set up a ramdisk rpc (fill command, actually load the file from DVD to IOP buffer)
|
|
(let ((visname (make-file-name (file-kind vis) (the-as string (-> obj nickname)) 0 #f))
|
|
(cmd (the-as ramdisk-rpc-fill (add-element *ramdisk-rpc*)))
|
|
(s5-0 (+ *current-ramdisk-id* 1))
|
|
)
|
|
(set! *current-ramdisk-id* s5-0)
|
|
(set! (-> cmd filename) (string->sound-name visname))
|
|
(set! (-> cmd ee-id) s5-0)
|
|
(load-dbg "doing ramdisk vis load: ~A~%" visname)
|
|
(call *ramdisk-rpc* RAMDISK_RPC_FILL_FNO (the-as pointer 0) (the-as uint 0))
|
|
;; remember which ramdisk id we are assigned
|
|
(set! (-> obj vis-info (-> obj vis-self-index) ramdisk) s5-0)
|
|
)
|
|
)
|
|
|
|
;; return the ramdisk ID.
|
|
(-> obj vis-info (-> obj vis-self-index) ramdisk)
|
|
)
|
|
|
|
(defun load-vis-info ((vis-name symbol) (old-vis-name symbol))
|
|
"Load a new VIS file and dump the old one. The corresponding level must be active!"
|
|
|
|
(dotimes (i (-> *level* length))
|
|
(let ((lev (-> *level* level i)))
|
|
(when (= (-> lev status) 'active)
|
|
(when (= vis-name (-> lev nickname))
|
|
(format 0 "Swapping in ~A VIS [dumping ~A]~%" vis-name old-vis-name)
|
|
(vis-load lev)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
0
|
|
)
|
|
|
|
(defmethod init-vis level ((obj level))
|
|
"Set up the vis info in a level from the vis info in the BSP."
|
|
|
|
(when (not (or (= (-> obj status) 'inactive) (not (-> obj bsp))))
|
|
;; no vis loaded at first, mark as loading/invalid.
|
|
(set! (-> obj all-visible?) 'loading)
|
|
;; vis info 0 is always self.
|
|
(let ((s5-0 (-> obj bsp vis-info 0)))
|
|
;; check that our vis info is valid.
|
|
(cond
|
|
((and s5-0 (nonzero? s5-0) (valid? s5-0 level-vis-info #f #f 0))
|
|
;; add to the level
|
|
(set! (-> obj vis-info 0) s5-0)
|
|
;; don't have a string loaded yet
|
|
(set! (-> s5-0 current-vis-string) (the-as uint -1))
|
|
;; link to bsp
|
|
(set! (-> s5-0 from-bsp) (-> obj bsp))
|
|
;; the current vis string (uncompressed). The level allocates/manages this.
|
|
(set! (-> s5-0 vis-bits) (-> obj vis-bits))
|
|
;; clear waiting-for-load, thirty-one
|
|
(set! (-> s5-0 flags) (logand (the-as uint #xffffffff3fffffff) (-> s5-0 flags)))
|
|
;; set twenty-nine
|
|
(set! (-> s5-0 flags) (logior #x20000000 (-> s5-0 flags)))
|
|
(set! (-> s5-0 ramdisk) (the-as uint 0))
|
|
(set! (-> s5-0 string-block) (the-as uint #f))
|
|
;; remember that we use the vis system. This will enable warnings in the kernel
|
|
;; if we run out of actor memory. Without vis, I guess this happens a lot.
|
|
(set! *vis-boot* #t)
|
|
)
|
|
(else
|
|
;; we don't have vis (but it's okay)
|
|
(set! (-> obj vis-info 0) #f)
|
|
)
|
|
)
|
|
)
|
|
|
|
;; check for up to 6 neighbor level vis info. The last one is always left as null.
|
|
(dotimes (s5-1 6)
|
|
(let* ((s3-0 (+ s5-1 1))
|
|
(s4-0 (-> obj bsp vis-info s3-0))
|
|
)
|
|
(cond
|
|
((and s4-0 (nonzero? s4-0) (valid? s4-0 level-vis-info #f #f 0))
|
|
(set! (-> obj vis-info s3-0) s4-0)
|
|
(set! (-> s4-0 current-vis-string) (the-as uint -1))
|
|
(set! (-> s4-0 from-bsp) #f)
|
|
(set! (-> s4-0 vis-bits) (-> obj vis-bits))
|
|
;; clear 29, 30, 31
|
|
(set! (-> s4-0 flags) (logand (the-as uint #xffffffff1fffffff) (-> s4-0 flags)))
|
|
(set! *vis-boot* #t)
|
|
)
|
|
(else
|
|
(set! (-> obj vis-info s3-0) #f)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
0
|
|
)
|
|
|
|
(defmethod level-get-for-use level-group ((obj level-group) (name symbol) (want-status symbol))
|
|
"Get a level in a playable form, loading it if necessary."
|
|
|
|
(local-vars (s5-1 level))
|
|
;; debug allocate levels if necessary
|
|
(alloc-levels! obj #f)
|
|
|
|
(let* ((level-info (lookup-level-info name))
|
|
(level-name (remap-level-name level-info))
|
|
)
|
|
(swhen (level-get obj level-name)
|
|
(level-status-set! bc want-status)
|
|
(return bc)
|
|
)
|
|
(let ((a0-7 (level-get-most-disposable obj)))
|
|
(set! s5-1 (if a0-7 (level-status-set! a0-7 'inactive)
|
|
a0-7
|
|
))
|
|
)
|
|
;; THIS WAS BUGGED IN THE ORIGINAL GAME!! Probably due to a fault in the original GOAL compiler and because they had
|
|
;; a local variable called "level", this branch here checks for the *TYPE* object called level instead of the
|
|
;; variable. Since the type will never be equal to #f when this code runs, this failsafe never runs, and the game will
|
|
;; proceed to corrupt the symbol table since it thinks #f is a level, which most definitely crashes the game
|
|
;; very quickly.
|
|
;; We are fixing it.
|
|
(when (not s5-1) ;;level)
|
|
(format 0 "ERROR: could not find a slot to load ~A into.~%" name)
|
|
(return (the-as level #f))
|
|
)
|
|
(set! (-> s5-1 info) level-info)
|
|
(set! (-> s5-1 name) name)
|
|
(set! (-> s5-1 load-name) level-name)
|
|
)
|
|
(set! (-> s5-1 mood) (the mood-context (-> s5-1 info mood value)))
|
|
(set! (-> s5-1 mood-func) (the (function mood-context float int none) (-> s5-1 info mood-func value)))
|
|
(set! (-> s5-1 display?) #f)
|
|
(set! (-> s5-1 force-all-visible?) #f)
|
|
(set! (-> s5-1 force-inside?) #f)
|
|
(level-status-set! s5-1 'loading)
|
|
(level-status-set! s5-1 want-status)
|
|
s5-1
|
|
)
|
|
|
|
;; level status:
|
|
;; - inactive: nothing loaded or loading.
|
|
;; - loading: level is reserved and in the process of loading. There can only be 1 loading level at a time.
|
|
;; when loading, the loading-level heap is set to the appropriate level heap.
|
|
;; also, (-> *level* loading-level) points to the level.
|
|
;; - loading-bt: loading the "buffer top". This is the big BSP object file, it loads differently.
|
|
;; - loading-done: loading is done, but no login/init has started
|
|
;; - login: login is in progress
|
|
;; - loaded: login is done
|
|
;; - alive: level is birthed, etc
|
|
;; - active: level is being drawn
|
|
|
|
(defmethod level-status level-group ((obj level-group) (level-name symbol))
|
|
"Get the status of an existing level."
|
|
|
|
(let ((lev (level-get *level* level-name)))
|
|
(if lev
|
|
(-> lev status)
|
|
)
|
|
)
|
|
)
|
|
|
|
(defmethod level-status-set! level ((obj level) (want-status symbol))
|
|
"Change the status of a level, performing any cleanup and prep work as necessary.
|
|
Only change loading statuses in order!
|
|
Returns the level."
|
|
|
|
(case want-status
|
|
(('inactive)
|
|
(case (-> obj status)
|
|
)
|
|
(unload! obj)
|
|
)
|
|
(('loading)
|
|
(case (-> obj status)
|
|
(('inactive)
|
|
(load-begin obj)
|
|
)
|
|
)
|
|
)
|
|
(('loading-bt)
|
|
(case (-> obj status)
|
|
(('loading)
|
|
(set! (-> obj status) want-status)
|
|
(load-continue obj)
|
|
)
|
|
)
|
|
)
|
|
(('loading-done)
|
|
(case (-> obj status)
|
|
(('loading-bt)
|
|
(set! (-> obj status) want-status)
|
|
)
|
|
)
|
|
)
|
|
(('loaded)
|
|
(case (-> obj status)
|
|
(('loading-done)
|
|
;; will actually put us in login for a bit.
|
|
(login-begin obj)
|
|
)
|
|
(('alive 'active)
|
|
(deactivate obj)
|
|
)
|
|
)
|
|
)
|
|
(('alive 'active)
|
|
(when *dproc*
|
|
(case (-> obj status)
|
|
(('loaded)
|
|
(birth obj)
|
|
;; try again. we will be in alive.
|
|
;; this will do nothing if we want alive, but will activate if we want activate
|
|
(level-status-set! obj want-status)
|
|
)
|
|
(('alive)
|
|
(when (and *dproc* (= want-status 'active))
|
|
;; only if we want to do alive -> active
|
|
|
|
;; will set the level to be drawn.
|
|
(remove-by-param1 *background-draw-engine* (-> obj bsp))
|
|
(add-connection *background-draw-engine* *dproc* (the (function object object object object object) add-bsp-drawable) (-> obj bsp) obj #f)
|
|
(dotimes (v1-40 9)
|
|
(set! (-> obj closest-object v1-40) 0.0)
|
|
(set! (-> obj texture-mask v1-40) (the-as uint 0))
|
|
)
|
|
(set! (-> obj level-distance) 0.0)
|
|
(set! (-> obj status) 'active)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
obj
|
|
)
|
|
|
|
(define *login-state* (new 'global 'login-state))
|
|
(define *print-login* #t)
|
|
|
|
(defmethod load-continue level ((obj level))
|
|
"Continue loading a level from where we left off last time."
|
|
|
|
;; see if we are still linking some file
|
|
(when (-> obj linking)
|
|
;; do some more linking
|
|
(when (nonzero? (link-resume))
|
|
;; done linking and object file!
|
|
(set! (-> obj linking) #f)
|
|
(case (-> obj status)
|
|
(('loading)
|
|
;; load another object if we don't wanna copy anything
|
|
(if (not (-> *texture-relocate-later* memcpy))
|
|
(dgo-load-continue (the pointer (align64 (-> obj heap current))))
|
|
)
|
|
)
|
|
(('loading-bt)
|
|
;; finished loading the last object!
|
|
(level-status-set! obj 'loading-done)
|
|
(level-status-set! obj 'loaded)
|
|
)
|
|
)
|
|
)
|
|
(return obj)
|
|
)
|
|
;; otherwise, copy stuff that needs copying
|
|
(when (-> *texture-relocate-later* memcpy)
|
|
(relocate-later)
|
|
(dgo-load-continue (the pointer (align64 (-> obj heap current))))
|
|
(return obj)
|
|
)
|
|
;; otherwise, check status
|
|
(case (-> obj status)
|
|
(('loading)
|
|
;; we are still loading
|
|
(let* ((last-obj #f)
|
|
(a0-15 (dgo-load-get-next (& last-obj))))
|
|
(when a0-15
|
|
;; something has finished loading!
|
|
(cond
|
|
((not last-obj)
|
|
;; not the last object. start linking
|
|
(cond
|
|
((dgo-load-link (the-as dgo-header a0-15) (-> obj heap) *print-login* #f)
|
|
;; linking finished (that was fast)
|
|
(if (not (-> *texture-relocate-later* memcpy))
|
|
(dgo-load-continue (the pointer (align64 (-> obj heap current))))
|
|
)
|
|
)
|
|
(else
|
|
;; linking is not done, resume later.
|
|
(set! (-> obj linking) #t)
|
|
)
|
|
)
|
|
)
|
|
(else
|
|
;; we're loading the last object now, which has different rules
|
|
(set! (-> obj heap top) (-> obj heap top-base))
|
|
(level-status-set! obj 'loading-bt)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(('login)
|
|
;; run level login
|
|
(level-update-after-load obj *login-state*)
|
|
)
|
|
(('loading-bt)
|
|
;; link the last object
|
|
(let ((a0-26 (the pointer (align64 (-> obj heap current)))))
|
|
(cond
|
|
((dgo-load-link (the-as dgo-header a0-26) (-> obj heap) *print-login* #t)
|
|
(level-status-set! obj 'loading-done)
|
|
;; will start login.
|
|
(level-status-set! obj 'loaded)
|
|
)
|
|
(else
|
|
(set! (-> obj linking) #t)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
obj
|
|
)
|
|
|
|
(defmethod load-begin level ((obj level))
|
|
"Start loading the level. Uses 2 megabyte heaps for loading each object."
|
|
|
|
;; set the level heap. level code logins called from linker may allocate here
|
|
(set! loading-level (-> obj heap))
|
|
|
|
;; relocate method of the bsp will look for this
|
|
(set! (-> *level* loading-level) obj)
|
|
|
|
;; clear out old stuff
|
|
(set! (-> *level* log-in-level-bsp) #f)
|
|
(set! (-> obj nickname) #f)
|
|
(set! (-> obj bsp) #f)
|
|
(set! (-> obj entity) #f)
|
|
(set! (-> obj ambient) #f)
|
|
(set! (-> obj linking) #f)
|
|
(vis-clear obj)
|
|
|
|
(set! (-> obj status) 'loading)
|
|
|
|
;; incoming textures should use the level allocator
|
|
(set! (-> *texture-pool* allocate-func) texture-page-level-allocate)
|
|
|
|
;; build name
|
|
(if (= (-> obj load-name) (-> obj info visname))
|
|
(format (clear *temp-string*) "~S" (-> obj info nickname))
|
|
(format (clear *temp-string*) "~S" (-> obj name))
|
|
)
|
|
(set! (-> *temp-string* data 8) (the-as uint 0))
|
|
(format *temp-string* ".DGO")
|
|
|
|
;; reset temporary allocations on level heap
|
|
(set! (-> obj heap top) (-> obj heap top-base))
|
|
|
|
;; allocate DGO loading buffers
|
|
(let ((s4-0 (kmalloc (-> obj heap) (* 2 1024 1024) (kmalloc-flags align-64 top) "dgo-level-buf-2"))
|
|
(s5-2 (kmalloc (-> obj heap) (* 2 1024 1024) (kmalloc-flags align-64 top) "dgo-level-buf-2"))
|
|
)
|
|
(load-dbg " DGO buffers at #x~X #x~X~%" s4-0 s5-2)
|
|
|
|
;; we expect to load code first, remember where the heap is now.
|
|
(set! (-> obj code-memory-start) (-> obj heap current))
|
|
|
|
(format 0 "-----------> begin load ~A [~S]~%" (-> obj load-name) *temp-string*)
|
|
;; kick off the load!
|
|
(dgo-load-begin *temp-string* s5-2 s4-0 (the pointer (align64 (-> obj heap current))))
|
|
)
|
|
obj
|
|
)
|
|
|
|
(defmethod login-begin level ((obj level))
|
|
"Start the login. This is spread over multiple frames."
|
|
|
|
;; done with load, reset the texture page allocator
|
|
(set! (-> *texture-pool* allocate-func) texture-page-default-allocate)
|
|
|
|
(cond
|
|
((-> obj bsp)
|
|
(set! (-> *level* log-in-level-bsp) (-> obj bsp))
|
|
;; login textures
|
|
(login-level-textures *texture-pool* obj (-> obj bsp texture-page-count) (-> obj bsp texture-ids))
|
|
;; login shaders
|
|
(let ((bsp (-> obj bsp)))
|
|
(when (nonzero? (-> bsp adgifs))
|
|
(let ((adgifs (-> bsp adgifs)))
|
|
(dotimes (i (-> adgifs length))
|
|
(adgif-shader-login-no-remap (-> adgifs data i))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;; set the login state machine at the beginning.
|
|
(set! (-> *login-state* state) -1)
|
|
(set! (-> *login-state* pos) (the-as uint 0))
|
|
(set! (-> *login-state* elts) (the-as uint 0))
|
|
(set! (-> obj status) 'login)
|
|
)
|
|
(else
|
|
;; something went wrong, kill the level.
|
|
(level-status-set! obj 'inactive)
|
|
(set! loading-level global)
|
|
(set! (-> *level* loading-level) (-> *level* level-default))
|
|
)
|
|
)
|
|
obj
|
|
)
|
|
|
|
(defun level-update-after-load ((loaded-level level) (level-login-state login-state))
|
|
"Run some small amount of logins.
|
|
This will time itself and stop after some time.
|
|
When it's done, it will set the status to loaded."
|
|
(local-vars
|
|
(current-timer int)
|
|
(v1-154 int)
|
|
(initial-timer int)
|
|
(sv-16 prototype-bucket-tie)
|
|
(sv-32 int)
|
|
)
|
|
|
|
;; there is some logic for not doing the whole login all at once...
|
|
;; for now, we will somewhat ignore that.
|
|
|
|
|
|
(let ((level-drawable-trees (-> loaded-level bsp drawable-trees)))
|
|
;;(.mfc0 initial-timer Count)
|
|
(label cfg-1)
|
|
;;(.mfc0 current-timer Count)
|
|
|
|
;; this would quit the login function after some amount of time elapsed.
|
|
#|
|
|
(let ((elapsed-timer (- current-timer initial-timer)))
|
|
(when (< #x186a0 elapsed-timer)
|
|
(set! loaded-level loaded-level)
|
|
(goto cfg-78)
|
|
)
|
|
)
|
|
|#
|
|
|
|
(let ((current-login-pos (the-as int (-> level-login-state pos))))
|
|
|
|
;; Login state -1.
|
|
;; in this state, we log in drawables/art-groups that are in referenced in the bsp directly
|
|
;; the current-login-pos in the index of the drawable/art to login.
|
|
|
|
(when (= (-> level-login-state state) -1)
|
|
;;(load-dbg "login state -1~%")
|
|
|
|
;; login some drawables.
|
|
(when (< current-login-pos (-> level-drawable-trees length))
|
|
(let ((current-drawable (-> level-drawable-trees trees (the-as uint current-login-pos))))
|
|
;;(load-dbg "login draw: ~A~%" current-drawable)
|
|
(cond
|
|
((= (-> current-drawable type) drawable-tree-tfrag)
|
|
;; tfrag!
|
|
(dotimes (idx-in-drawable (-> current-drawable length))
|
|
(cond
|
|
((= (-> current-drawable data idx-in-drawable type) drawable-inline-array-tfrag)
|
|
;; we got an array of drawables. instead of iterating/recursing, just add it to the back of the login list.
|
|
;;(load-dbg " tfrag array case~%")
|
|
(set! (-> level-login-state elt (-> level-login-state elts)) (-> current-drawable data idx-in-drawable))
|
|
(+! (-> level-login-state elts) 1)
|
|
)
|
|
(else
|
|
;;(load-dbg " tfrag actual login case~%")
|
|
(login (-> current-drawable data idx-in-drawable))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
((= (-> current-drawable type) drawable-tree-instance-tie)
|
|
;; tie! add the tree to the list.
|
|
;;(load-dbg " tie tree case~%")
|
|
(set! (-> level-login-state elt (-> level-login-state elts)) current-drawable)
|
|
(+! (-> level-login-state elts) 1)
|
|
)
|
|
(else
|
|
;;(load-dbg " other actual login: ~A~%" (method-of-object current-drawable login))
|
|
(login current-drawable)
|
|
)
|
|
)
|
|
)
|
|
(+! (-> level-login-state pos) 1)
|
|
(goto cfg-1)
|
|
)
|
|
|
|
;; this makes the art groups go at the end.
|
|
(let ((v1-39 (- (the-as uint current-login-pos) (the-as uint (-> level-drawable-trees length)))))
|
|
(when (< (the-as int v1-39) (-> loaded-level art-group art-group-array length))
|
|
(let ((s2-2 (-> loaded-level art-group art-group-array v1-39)))
|
|
(login s2-2)
|
|
(if (needs-link? s2-2)
|
|
(link-art! s2-2)
|
|
)
|
|
)
|
|
(+! (-> level-login-state pos) 1)
|
|
(goto cfg-1)
|
|
)
|
|
)
|
|
|
|
;; if we got here, we're done with state -1!
|
|
(set! (-> level-login-state pos) (the-as uint 0))
|
|
(set! (-> level-login-state state) 0)
|
|
(goto cfg-1)
|
|
)
|
|
|
|
|
|
;; login state 0.
|
|
;; we log in children of the drawables from state -1.
|
|
(when (< (-> level-login-state state) (the-as int (-> level-login-state elts)))
|
|
;; (load-dbg " login state 0~%")
|
|
(let ((s1-1 (-> level-login-state elt (-> level-login-state state))))
|
|
(cond
|
|
((= (-> s1-1 type) drawable-inline-array-tfrag)
|
|
;; (load-dbg " login drawable-inline-array-tfrag: ~A~%" s1-1)
|
|
(cond
|
|
((< current-login-pos (-> (the-as drawable-inline-array-tfrag s1-1) length))
|
|
(dotimes (s0-0 200)
|
|
(when (< current-login-pos (-> (the-as drawable-inline-array-tfrag s1-1) length))
|
|
;; (load-dbg " login from drawable-inline-array-tfrag: ~A~%" (-> (the-as drawable-inline-array-tfrag s1-1) data (the-as uint current-login-pos)))
|
|
(login (-> (the-as drawable-inline-array-tfrag s1-1) data (the-as uint current-login-pos)))
|
|
(set! current-login-pos (the-as int (+ (the-as uint current-login-pos) 1)))
|
|
)
|
|
)
|
|
(set! (-> level-login-state pos) (the-as uint current-login-pos))
|
|
)
|
|
(else
|
|
(set! (-> level-login-state pos) (the-as uint 0))
|
|
(set! current-login-pos (+ (-> level-login-state state) 1))
|
|
(set! (-> level-login-state state) current-login-pos)
|
|
)
|
|
)
|
|
)
|
|
((= (-> s1-1 type) drawable-tree-instance-tie)
|
|
;;(load-dbg " login drawable-tree-instance-tie: ~A~%" s1-1)
|
|
(let ((s1-2 (-> (the-as drawable-tree-instance-tie s1-1) prototypes prototype-array-tie)))
|
|
(when (< current-login-pos (-> s1-2 length))
|
|
(dotimes (s0-1 10)
|
|
(when (< current-login-pos (-> s1-2 length))
|
|
(set! sv-16 (-> s1-2 array-data (the-as uint current-login-pos)))
|
|
(set! sv-32 0)
|
|
(while (< sv-32 4)
|
|
(let ((a0-28 (-> sv-16 geometry sv-32)))
|
|
;;(load-dbg " login geom: ~A~%" a0-28)
|
|
(if (nonzero? a0-28)
|
|
(login a0-28)
|
|
)
|
|
)
|
|
(set! sv-32 (+ sv-32 1))
|
|
)
|
|
(set! current-login-pos (the-as int (+ (the-as uint current-login-pos) 1)))
|
|
)
|
|
)
|
|
(set! (-> level-login-state pos) (the-as uint current-login-pos))
|
|
)
|
|
(when (= (the-as uint current-login-pos) (-> s1-2 length))
|
|
(dotimes (s2-3 (-> s1-2 length))
|
|
(let ((s0-2 (-> s1-2 array-data s2-3 envmap-shader)))
|
|
(when (nonzero? s0-2)
|
|
;;(load-dbg " login adgif shader for envmap~%")
|
|
(adgif-shader-login-no-remap s0-2)
|
|
(set! (-> s0-2 tex1) (new 'static 'gs-tex1 :mmag #x1 :mmin #x1))
|
|
(set!
|
|
(-> s0-2 clamp)
|
|
(new 'static 'gs-clamp
|
|
:wms (gs-tex-wrap-mode clamp)
|
|
:wmt (gs-tex-wrap-mode clamp)
|
|
)
|
|
)
|
|
(set! (-> s0-2 alpha) (new 'static 'gs-alpha :b #x2 :c #x1 :d #x1))
|
|
(set! (-> s0-2 prims 1) (gs-reg64 tex0-1))
|
|
(set! (-> s0-2 prims 3) (gs-reg64 tex1-1))
|
|
(set! (-> s0-2 prims 5) (gs-reg64 miptbp1-1))
|
|
(set! (-> s0-2 clamp-reg) (gs-reg64 clamp-1))
|
|
(set! (-> s0-2 prims 9) (gs-reg64 alpha-1))
|
|
)
|
|
)
|
|
)
|
|
(set! (-> level-login-state pos) (the-as uint 0))
|
|
(+! (-> level-login-state state) 1)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(goto cfg-1)
|
|
)
|
|
|
|
|
|
(when (= (-> level-login-state state) (-> level-login-state elts))
|
|
(let ((v1-115 (-> loaded-level bsp)))
|
|
(cond
|
|
((or (zero? (-> v1-115 actors)) (= (the-as uint current-login-pos) (-> v1-115 actors length)))
|
|
(set! (-> level-login-state pos) (the-as uint 0))
|
|
(+! (-> level-login-state state) 1)
|
|
)
|
|
(else
|
|
(let ((a0-36 (-> v1-115 actors data (the-as uint current-login-pos) actor)))
|
|
;; (load-dbg "entity nav login: ~A~%" a0-36)
|
|
(entity-nav-login a0-36)
|
|
)
|
|
(+! (-> level-login-state pos) 1)
|
|
)
|
|
)
|
|
)
|
|
(goto cfg-1)
|
|
)
|
|
(when (zero? (the-as uint current-login-pos))
|
|
(set! (-> level-login-state pos) (the-as uint 1))
|
|
(set! loaded-level loaded-level)
|
|
(goto cfg-78)
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
;; done!
|
|
(set! (-> loaded-level nickname) (-> loaded-level bsp nickname))
|
|
(if (nonzero? (-> loaded-level bsp nodes))
|
|
(set! *time-of-day-effects* #t)
|
|
(set! *time-of-day-effects* #f)
|
|
)
|
|
(let ((f0-0 (-> loaded-level bsp unk-data-4))
|
|
(f1-0 (-> loaded-level bsp unk-data-5))
|
|
)
|
|
(when (and (= f0-0 0.0) (= f1-0 0.0))
|
|
(set! f0-0 122880.0)
|
|
(set! f1-0 286720.0)
|
|
)
|
|
(set! (-> *subdivide-settings* close (-> loaded-level index)) f0-0)
|
|
(set! (-> *subdivide-settings* far (-> loaded-level index)) f1-0)
|
|
(set! (-> *subdivide-settings* close 3) f0-0)
|
|
(set! (-> *subdivide-settings* far 3) f1-0)
|
|
)
|
|
|
|
(load-dbg "init-vis~%")
|
|
(init-vis loaded-level)
|
|
(load-dbg "package load~%")
|
|
(load-required-packages loaded-level)
|
|
(set! (-> loaded-level status) 'loaded)
|
|
(set! loading-level global)
|
|
(set! (-> *level* loading-level) (-> *level* level-default))
|
|
(set! (-> *level* log-in-level-bsp) #f)
|
|
; 0
|
|
; (.mfc0 v1-154 Count)
|
|
; (- v1-154 initial-timer)
|
|
(label cfg-78)
|
|
loaded-level
|
|
)
|
|
|
|
(defmethod birth level ((obj level))
|
|
"Birth a level to make it alive! It must be loaded."
|
|
|
|
(case (-> obj status)
|
|
(('loaded)
|
|
(protect (loading-level
|
|
(-> *level* loading-level)
|
|
(-> *level* log-in-level-bsp)
|
|
)
|
|
(set! loading-level (-> obj heap))
|
|
(set! (-> *level* log-in-level-bsp) (-> obj bsp))
|
|
(set! (-> *level* loading-level) obj)
|
|
(birth (-> obj bsp))
|
|
(set! (-> obj status) 'alive)
|
|
;;(load-dbg "copy perms~%")
|
|
(copy-perms-to-level! *game-info* obj)
|
|
;;(load-dbg "send activate~%")
|
|
;; note: this isn't a great name - the level isn't actually activated, just alive.
|
|
(send-event *camera* 'level-activate (-> obj name))
|
|
(send-event *target* 'level-activate (-> obj name))
|
|
)
|
|
)
|
|
)
|
|
obj
|
|
)
|
|
|
|
(defmethod deactivate level ((obj level))
|
|
"Kill the level. This won't remove it from memory."
|
|
|
|
(case (-> obj status)
|
|
(('active 'alive)
|
|
(format 0 "----------- kill ~A (status ~A)~%" obj (-> obj status))
|
|
|
|
;; copy data from the level to the game-info storage. This will remember permanent level stuff, like
|
|
;; what you collected/completed.
|
|
(copy-perms-from-level! *game-info* obj)
|
|
(send-event *camera* 'level-deactivate (-> obj name))
|
|
(send-event *target* 'level-deactivate (-> obj name))
|
|
|
|
;; remove this BSP from the engine. This will stop us from being drawn.
|
|
(remove-by-param1 *background-draw-engine* (-> obj bsp))
|
|
|
|
;; track down all the entities and kill them
|
|
(deactivate-entities (-> obj bsp))
|
|
|
|
;; kill any remaining particles not associated with a part-tracker
|
|
(kill-all-particles-in-level obj)
|
|
|
|
;; clean up our level
|
|
(set! (-> obj inside-sphere?) #f)
|
|
(set! (-> obj inside-boxes?) #f)
|
|
(set! (-> obj meta-inside?) #f)
|
|
(set! (-> obj force-inside?) #f)
|
|
|
|
;; we're still loaded.
|
|
(set! (-> obj status) 'loaded)
|
|
|
|
(set! (-> obj all-visible?) 'loading)
|
|
;; clear vis buffers
|
|
(dotimes (v1-19 128)
|
|
(set! (deref int128 (-> obj vis-bits) v1-19) (the-as int128 0))
|
|
)
|
|
(let ((v1-22 8))
|
|
(while (nonzero? v1-22)
|
|
(+! v1-22 -1)
|
|
(let ((a0-14 (-> obj vis-info v1-22)))
|
|
(if a0-14
|
|
(set! (-> a0-14 current-vis-string) (the-as uint -1))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(if (= (-> *level* log-in-level-bsp) (-> obj bsp))
|
|
(set! (-> *level* log-in-level-bsp) #f)
|
|
)
|
|
obj
|
|
)
|
|
|
|
(defmethod unload! level ((obj level))
|
|
"Unloads the level. This does not free the heap. The level will be made inactive and ready to be loaded some other time."
|
|
|
|
(deactivate obj)
|
|
(when (!= (-> obj status) 'inactive)
|
|
|
|
;; if we linked art group, unlink it.
|
|
(when (or (= (-> obj status) 'loaded)
|
|
(= (-> obj status) 'alive)
|
|
(= (-> obj status) 'active)
|
|
(= (-> obj status) 'login)
|
|
)
|
|
(dotimes (s5-0 (-> obj art-group art-group-array length))
|
|
(let ((s4-0 (-> obj art-group art-group-array s5-0)))
|
|
(if (needs-link? s4-0)
|
|
(unlink-art! s4-0)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;; turn some things off
|
|
(set! (-> obj bsp) #f)
|
|
(set! (-> obj entity) #f)
|
|
(set! (-> obj ambient) #f)
|
|
(set! (-> obj status) 'inactive)
|
|
(set! (-> obj art-group string-array length) 0)
|
|
(set! (-> obj art-group art-group-array length) 0)
|
|
|
|
;; unload texture pages
|
|
(countdown (s5-1 (-> obj loaded-texture-page-count))
|
|
(dotimes (v1-27 32)
|
|
(when (= (-> obj loaded-texture-page s5-1) (-> *texture-pool* common-page v1-27))
|
|
(set! (-> *texture-pool* common-page v1-27) (the-as texture-page 0))
|
|
)
|
|
)
|
|
(unload! *texture-pool* (-> obj loaded-texture-page s5-1))
|
|
)
|
|
(set! (-> obj loaded-texture-page-count) 0)
|
|
(unlink-textures-in-heap! *texture-page-dir* (-> obj heap))
|
|
|
|
;; unload particle groups that were defined in the level data
|
|
(unlink-part-group-by-heap (-> obj heap))
|
|
|
|
;; if there are any in-progress art loads for this level, kill them.
|
|
(dotimes (s5-2 2)
|
|
(let ((v1-41 (-> *art-control* buffer s5-2 pending-load-file)))
|
|
(if (and (>= (the-as int v1-41) (the-as int (-> obj heap base)))
|
|
(< (the-as int v1-41) (the-as int (-> obj heap top-base)))
|
|
)
|
|
(set-pending-file
|
|
(-> *art-control* buffer s5-2)
|
|
(the-as string #f)
|
|
-1
|
|
(the-as handle #f)
|
|
100000000.0
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;; unload packages (doesn't really do anything.)
|
|
(let* ((s5-3 (-> obj info packages))
|
|
(a0-29 (car s5-3))
|
|
)
|
|
(while (not (null? s5-3))
|
|
(case (rtype-of a0-29)
|
|
((symbol)
|
|
(unload (symbol->string (the-as symbol a0-29)))
|
|
)
|
|
((string)
|
|
(unload (the-as string a0-29))
|
|
)
|
|
)
|
|
(set! s5-3 (cdr s5-3))
|
|
(set! a0-29 (car s5-3))
|
|
)
|
|
)
|
|
|
|
(vis-clear obj)
|
|
|
|
;; reset the level heap!
|
|
(let ((v1-64 (-> obj heap)))
|
|
(set! (-> v1-64 current) (-> v1-64 base))
|
|
)
|
|
(set! (-> obj code-memory-start) (the-as pointer 0))
|
|
(set! (-> obj code-memory-end) (the-as pointer 0))
|
|
(when (= (-> *level* loading-level) obj)
|
|
(set! loading-level global)
|
|
(set! (-> *level* loading-level) (-> *level* level-default))
|
|
(set! (-> *level* log-in-level-bsp) #f)
|
|
)
|
|
)
|
|
obj
|
|
)
|
|
|
|
;; method 27 level
|
|
|
|
;; method 10 level
|
|
(defmethod is-object-visible? level ((obj level) (arg0 int))
|
|
"Is arg0 visible? Note that this will return #f if the visibility data is not loaded."
|
|
|
|
;; note : pc port added option to show every actor regardless
|
|
(#when PC_PORT
|
|
(cond
|
|
((actor-force-visible? *pc-settings*) #t)
|
|
(else
|
|
|
|
;; check the vis bits!
|
|
(let* (;; lwu v1, 388(a0)
|
|
(vis-data (-> obj vis-bits))
|
|
;; sra a0, a1, 3
|
|
(byte-idx (sar arg0 3))
|
|
;; daddu v1, a0, v1
|
|
;; lb v1, 0(v1)
|
|
(vis-byte (-> (the (pointer int8) vis-data) byte-idx))
|
|
;; andi a0, a1, 7
|
|
(bit-idx (logand arg0 #b111))
|
|
;; addiu a0, a0, 56
|
|
(shift-amount (+ bit-idx 56)) ;; 56 + 8 = 64, to set the sign bit
|
|
;; dsllv v1, v1, a0
|
|
(check-sign-word (the int (shl vis-byte shift-amount))) ;; signed
|
|
)
|
|
;; slt v1, v1, r0 v1 = (csw < 0)
|
|
;; daddiu v0, s7, 8
|
|
;; movz v0, s7, v1 if (csw >= 0) result = false
|
|
;;(format 0 "vis check ~D ~X ~X ~A~%" arg0 vis-byte check-sign-word (>= check-sign-word 0))
|
|
(< check-sign-word 0)
|
|
)
|
|
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
(defmethod point-in-boxes? level ((obj level) (arg0 vector))
|
|
"Is this point in the list of level boxes?"
|
|
(cond
|
|
((or (not (-> obj bsp)) (zero? (-> obj bsp boxes)))
|
|
;; no boxes or no bsp
|
|
#f
|
|
)
|
|
((-> obj force-inside?)
|
|
#t
|
|
)
|
|
(else
|
|
(let* ((a0-1 (-> obj bsp boxes))
|
|
(v1-5 (-> a0-1 data))
|
|
)
|
|
(countdown (a0-2 (-> a0-1 length))
|
|
(if (and (>= (-> arg0 x) (-> v1-5 0 min x))
|
|
(>= (-> arg0 y) (-> v1-5 0 min y))
|
|
(>= (-> arg0 z) (-> v1-5 0 min z))
|
|
(< (-> arg0 x) (-> v1-5 0 max x))
|
|
(< (-> arg0 y) (-> v1-5 0 max y))
|
|
(< (-> arg0 z) (-> v1-5 0 max z))
|
|
)
|
|
(return #t)
|
|
)
|
|
(set! v1-5 (the (inline-array box8s) (-> v1-5 1)))
|
|
)
|
|
)
|
|
#f
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
(defmethod debug-print-splitbox level ((obj level) (arg0 vector) (arg1 string))
|
|
"Print the current splitbox, if we're in one."
|
|
(cond
|
|
((or (not (-> obj bsp)) (zero? (-> obj bsp boxes)) (zero? (-> obj bsp split-box-indices)))
|
|
;; do nothing!
|
|
)
|
|
(else
|
|
(let* ((s3-0 (-> obj bsp boxes))
|
|
(s2-0 (-> s3-0 data))
|
|
)
|
|
(dotimes (s1-0 (-> s3-0 length))
|
|
(if
|
|
(and
|
|
(>= (-> arg0 x) (-> s2-0 0 min x))
|
|
(>= (-> arg0 y) (-> s2-0 0 min y))
|
|
(>= (-> arg0 z) (-> s2-0 0 min z))
|
|
(< (-> arg0 x) (-> s2-0 0 max x))
|
|
(< (-> arg0 y) (-> s2-0 0 max y))
|
|
(< (-> arg0 z) (-> s2-0 0 max z))
|
|
)
|
|
(format arg1 " splitbox-~D~%" (-> obj bsp split-box-indices s1-0))
|
|
)
|
|
(set! s2-0 (the (inline-array box8s) (-> s2-0 1)))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
0
|
|
(none)
|
|
)
|
|
|
|
|
|
(defmethod mem-usage level ((obj level) (arg0 memory-usage-block) (arg1 int))
|
|
"Get the memory usage for a level."
|
|
|
|
(when (= (-> obj status) 'active)
|
|
(set! (-> arg0 length) (max 65 (-> arg0 length)))
|
|
(set! (-> arg0 data 64 name) "entity-links")
|
|
(set!
|
|
(-> arg0 data 64 count)
|
|
(+ (-> arg0 data 64 count) (-> obj entity length))
|
|
)
|
|
(let ((v1-8 (asize-of (-> obj entity))))
|
|
(set! (-> arg0 data 64 used) (+ (-> arg0 data 64 used) v1-8))
|
|
(set!
|
|
(-> arg0 data 64 total)
|
|
(+ (-> arg0 data 64 total) (logand -16 (+ v1-8 15)))
|
|
)
|
|
)
|
|
(set! (-> arg0 length) (max 65 (-> arg0 length)))
|
|
(set! (-> arg0 data 64 name) "ambient-links")
|
|
(set!
|
|
(-> arg0 data 64 count)
|
|
(+ (-> arg0 data 64 count) (-> obj ambient length))
|
|
)
|
|
(let ((v1-18 (asize-of (-> obj ambient))))
|
|
(set! (-> arg0 data 64 used) (+ (-> arg0 data 64 used) v1-18))
|
|
(set!
|
|
(-> arg0 data 64 total)
|
|
(+ (-> arg0 data 64 total) (logand -16 (+ v1-18 15)))
|
|
)
|
|
)
|
|
(mem-usage (-> obj art-group) arg0 arg1)
|
|
(set! (-> arg0 length) (max 64 (-> arg0 length)))
|
|
(set! (-> arg0 data 63 name) "level-code")
|
|
(set! (-> arg0 data 63 count) (+ (-> arg0 data 63 count) 1))
|
|
(let
|
|
((v1-30
|
|
(&- (-> obj code-memory-end) (the-as uint (-> obj code-memory-start)))
|
|
)
|
|
)
|
|
(set! (-> arg0 data 63 used) (+ (-> arg0 data 63 used) v1-30))
|
|
(set!
|
|
(-> arg0 data 63 total)
|
|
(+ (-> arg0 data 63 total) (logand -16 (+ v1-30 15)))
|
|
)
|
|
)
|
|
(countdown (s3-0 (-> obj loaded-texture-page-count))
|
|
(mem-usage (-> obj loaded-texture-page s3-0) arg0 arg1)
|
|
)
|
|
(countdown (s3-1 8)
|
|
(let ((s2-0 (-> obj vis-info s3-1)))
|
|
(when s2-0
|
|
(cond
|
|
((zero? s3-1)
|
|
(set! (-> arg0 length) (max 60 (-> arg0 length)))
|
|
(set! (-> arg0 data 59 name) "bsp-leaf-vis-self")
|
|
(set! (-> arg0 data 59 count) (+ (-> arg0 data 59 count) 1))
|
|
(let ((v1-50 (asize-of s2-0)))
|
|
(set! (-> arg0 data 59 used) (+ (-> arg0 data 59 used) v1-50))
|
|
(set!
|
|
(-> arg0 data 59 total)
|
|
(+ (-> arg0 data 59 total) (logand -16 (+ v1-50 15)))
|
|
)
|
|
)
|
|
)
|
|
(else
|
|
(set! (-> arg0 length) (max 61 (-> arg0 length)))
|
|
(set! (-> arg0 data 60 name) "bsp-leaf-vis-adj")
|
|
(set! (-> arg0 data 60 count) (+ (-> arg0 data 60 count) 1))
|
|
(let
|
|
((v1-61 (+ (asize-of s2-0) (the-as int (-> s2-0 allocated-length)))))
|
|
(set! (-> arg0 data 60 used) (+ (-> arg0 data 60 used) v1-61))
|
|
(set!
|
|
(-> arg0 data 60 total)
|
|
(+ (-> arg0 data 60 total) (logand -16 (+ v1-61 15)))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(mem-usage (-> obj bsp) arg0 arg1)
|
|
)
|
|
obj
|
|
)
|
|
|
|
(#cond
|
|
(PC_PORT
|
|
(defconstant LEVEL_HEAP_SIZE (* 10416 1024)) ;; 10.416K
|
|
(defconstant LEVEL_HEAP_SIZE_DEBUG (* 11000 1024))
|
|
)
|
|
(#t
|
|
(defconstant LEVEL_HEAP_SIZE (* 10416 1024)) ;; 10.416K
|
|
(defconstant LEVEL_HEAP_SIZE_DEBUG (* 25600 1024)) ;; 25.600K
|
|
)
|
|
)
|
|
|
|
(defmethod alloc-levels! level-group ((obj level-group) (compact-level-heaps symbol))
|
|
"Allocate the level heaps and load the common packages for levels."
|
|
|
|
;; only do stuff if levels are not allocated
|
|
(when (zero? (-> *level* level0 heap base))
|
|
;; GAME.CGO is made up of ART.CGO and COMMON.CGO
|
|
(when (nmember "game" *kernel-packages*)
|
|
(set! *kernel-packages* (cons "art" *kernel-packages*))
|
|
(set! *kernel-packages* (cons "common" *kernel-packages*))
|
|
)
|
|
(load-package "art" global) ;; load ART
|
|
(if compact-level-heaps
|
|
(load-package "common" global) ;; load COMMON unless we're debugging levels
|
|
)
|
|
;; allocate level heaps. turn on compact-level-heaps for use in 32MB systems
|
|
(let ((level-heap-size (if compact-level-heaps LEVEL_HEAP_SIZE
|
|
LEVEL_HEAP_SIZE_DEBUG))
|
|
)
|
|
(dotimes (lev LEVEL_COUNT)
|
|
(let ((level-heap (-> obj level lev heap)))
|
|
(set! (-> level-heap base) (malloc 'global level-heap-size))
|
|
(set! (-> level-heap current) (-> level-heap base))
|
|
(set! (-> level-heap top-base) (&+ (-> level-heap base) level-heap-size))
|
|
(set! (-> level-heap top) (-> level-heap top-base))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
0
|
|
)
|
|
|
|
|
|
(defmethod level-get-with-status level-group ((obj level-group) (status symbol))
|
|
(dotimes (i (-> obj length))
|
|
(if (= (-> obj level i status) status)
|
|
(return (-> obj level i))
|
|
)
|
|
)
|
|
(the-as level #f)
|
|
)
|
|
|
|
(defmethod level-get-most-disposable level-group ((obj level-group))
|
|
"Get a level that's least likely to be in use right now. #f = all levels in use."
|
|
|
|
;; check inactive levels first
|
|
(dotimes (v1-0 (-> obj length))
|
|
(case (-> obj level v1-0 status)
|
|
(('inactive)
|
|
(return (-> obj level v1-0))
|
|
)
|
|
)
|
|
)
|
|
|
|
;; check for any loading levels
|
|
(dotimes (v1-6 (-> obj length))
|
|
(case (-> obj level v1-6 status)
|
|
(('loading 'loading-bt)
|
|
(return (-> obj level v1-6))
|
|
)
|
|
)
|
|
)
|
|
|
|
;; check for loaded, but not active, levels.
|
|
(dotimes (v1-12 (-> obj length))
|
|
(let ((a1-18 (-> obj level v1-12 status)))
|
|
(if (= a1-18 'loaded)
|
|
(return (-> obj level v1-12))
|
|
)
|
|
)
|
|
)
|
|
|
|
;; check active levels. pick one we're not in bounds of.
|
|
(let ((v0-0 (the-as level #f)))
|
|
(dotimes (v1-18 (-> obj length))
|
|
(case (-> obj level v1-18 status)
|
|
(('active)
|
|
(if (and (not (-> obj level v1-18 inside-boxes?))
|
|
(or (not v0-0)
|
|
(< (-> obj level v1-18 info priority) (-> v0-0 info priority))
|
|
)
|
|
)
|
|
(set! v0-0 (-> obj level v1-18))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
v0-0
|
|
)
|
|
)
|
|
|
|
(defmethod level-get level-group ((obj level-group) (name symbol))
|
|
"Return the level data using its name, if it is available. Returns #f if none are found."
|
|
|
|
(dotimes (lev (-> obj length))
|
|
(if (and (!= (-> obj level lev status) 'inactive)
|
|
(or (= (-> obj level lev name) name)
|
|
(= (-> obj level lev load-name) name)
|
|
)
|
|
)
|
|
(return (-> obj level lev))
|
|
)
|
|
)
|
|
(the level #f)
|
|
)
|
|
|
|
(defmethod art-group-get-by-name level-group ((obj level-group) (arg0 string))
|
|
(countdown (i 3)
|
|
(let ((lev (-> obj level i)))
|
|
(countdown (ii (-> lev art-group art-group-array length))
|
|
(if (name= (-> lev art-group art-group-array ii name) arg0)
|
|
(return (-> lev art-group art-group-array ii))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(the-as art-group #f)
|
|
)
|
|
|
|
|
|
(defmethod activate-levels! level-group ((obj level-group))
|
|
"Try to activate all levels."
|
|
|
|
(dotimes (i (-> obj length))
|
|
(level-status-set! (-> obj level i) 'active)
|
|
)
|
|
0
|
|
)
|
|
|
|
(defmethod level-get-target-inside level-group ((obj level-group))
|
|
"Get the level target is in, or one it is close to.
|
|
The distance checks do not work."
|
|
|
|
(let ((target-trans (target-pos 0)))
|
|
(let ((current-level (-> *game-info* current-continue level)))
|
|
(dotimes (i (-> obj length))
|
|
(let ((ilev (-> obj level i)))
|
|
(when (= (-> ilev status) 'active)
|
|
(if (= (-> ilev name) current-level)
|
|
(return ilev)
|
|
)))))
|
|
(let ((level-ret (the-as level #f)))
|
|
(let ((min-distance-to-level 0.0)) ;; uh-huh
|
|
(dotimes (i (-> obj length))
|
|
(let ((ilev (-> obj level i)))
|
|
(when (= (-> ilev status) 'active)
|
|
(let ((distance-to-level (vector-vector-distance (-> ilev bsp bsphere) target-trans)))
|
|
(if (and (-> ilev inside-boxes?) (or (not level-ret) (< distance-to-level min-distance-to-level)))
|
|
(set! level-ret ilev)
|
|
))))))
|
|
(if level-ret
|
|
(return level-ret)
|
|
)
|
|
)
|
|
)
|
|
(dotimes (i (-> obj length))
|
|
(let ((ilev (-> obj level i)))
|
|
(when (= (-> ilev status) 'active)
|
|
(if (-> ilev meta-inside?)
|
|
(return ilev)
|
|
))))
|
|
(let ((level-ret (the-as level #f)))
|
|
(let ((min-distance-to-level 0.0)) ;; why?
|
|
(dotimes (i (-> obj length))
|
|
(let ((ilev (-> obj level i)))
|
|
(when (= (-> ilev status) 'active)
|
|
(if (or (not level-ret) (< (-> ilev level-distance) min-distance-to-level))
|
|
(set! level-ret ilev)
|
|
)))))
|
|
level-ret
|
|
)
|
|
)
|
|
|
|
(defmethod load-commands-set! level-group ((obj level-group) (load-commands pair))
|
|
(set! (-> obj load-commands) load-commands)
|
|
load-commands
|
|
)
|
|
|
|
(defmethod mem-usage level-group ((obj level-group) (arg0 memory-usage-block) (arg1 int))
|
|
"Get the memory usage data for a level-group"
|
|
|
|
;; get memory usage of each level
|
|
(dotimes (i (-> obj length))
|
|
(mem-usage (-> obj level i) arg0 arg1)
|
|
)
|
|
obj
|
|
)
|
|
|
|
(defun bg ((level-name symbol))
|
|
(set! *cheat-mode* (if *debug-segment*
|
|
'debug
|
|
#f
|
|
)
|
|
)
|
|
(let ((v1-2 (lookup-level-info level-name)))
|
|
(cond
|
|
((= (-> v1-2 visname) level-name)
|
|
(set! (-> *level* vis?) #t)
|
|
(set! level-name (-> v1-2 name))
|
|
)
|
|
(else
|
|
(set! (-> *level* vis?) #f)
|
|
(set! (-> *kernel-context* low-memory-message) #f)
|
|
)
|
|
)
|
|
(let* ((s5-0 (-> v1-2 run-packages))
|
|
(a0-8 (car s5-0))
|
|
)
|
|
(while (not (null? s5-0))
|
|
(let ((v1-4 (rtype-of a0-8)))
|
|
(cond
|
|
((= v1-4 symbol)
|
|
(load-package (symbol->string (the-as symbol a0-8)) global)
|
|
)
|
|
((= v1-4 string)
|
|
(load-package (the-as string a0-8) global)
|
|
)
|
|
)
|
|
)
|
|
(set! s5-0 (cdr s5-0))
|
|
(set! a0-8 (car s5-0))
|
|
)
|
|
)
|
|
)
|
|
(let ((gp-1 (level-get-for-use *level* level-name 'active)))
|
|
(while (and gp-1 (or (= (-> gp-1 status) 'loading)
|
|
(= (-> gp-1 status) 'loading-bt)
|
|
(= (-> gp-1 status) 'login)
|
|
)
|
|
(not *dproc*)
|
|
)
|
|
(load-continue gp-1)
|
|
)
|
|
(vis-load gp-1)
|
|
(set! (-> *load-state* vis-nick) (if (-> *level* vis?)
|
|
(-> gp-1 nickname)
|
|
#f
|
|
))
|
|
(set! (-> *load-state* want 0 name) (-> gp-1 name))
|
|
(set! (-> *load-state* want 0 display?) 'display)
|
|
(set! (-> *load-state* want 0 force-vis?) #f)
|
|
(set! (-> *load-state* want 0 force-inside?) #f)
|
|
(set! (-> *load-state* want 1 name) #f)
|
|
(set! (-> *load-state* want 1 display?) #f)
|
|
(set! (-> *load-state* want 1 force-inside?) #f)
|
|
(if (-> gp-1 info continues)
|
|
(set-continue! *game-info* (the-as continue-point (car (-> gp-1 info continues))))
|
|
)
|
|
)
|
|
(activate-levels! *level*)
|
|
(set! *print-login* #f)
|
|
0
|
|
)
|
|
|
|
(defun play ((use-vis symbol) (init-game symbol))
|
|
"The entry point to the actual game! This allocates the level heaps, loads some data, sets some default parameters and sets the startup level."
|
|
|
|
;; temp
|
|
(format #t "(play :use-vis ~A :init-game ~A) has been called!~%" use-vis init-game)
|
|
(format 0 "(play :use-vis ~A :init-game ~A) has been called!~%" use-vis init-game)
|
|
;;(kernel-shutdown)
|
|
|
|
(let ((startup-level (case *kernel-boot-message*
|
|
(('play)
|
|
(if *debug-segment*
|
|
(#if (user? dass) 'citadel 'village1)
|
|
'title
|
|
)
|
|
)
|
|
(else
|
|
'demo
|
|
)
|
|
)
|
|
))
|
|
(stop 'play)
|
|
(set! (-> *level* vis?) use-vis)
|
|
(set! (-> *level* want-level) #f)
|
|
(set! (-> *level* border?) #t)
|
|
(set! (-> *setting-control* default border-mode) #t)
|
|
(set! (-> *level* play?) #t)
|
|
(alloc-levels! *level* #f);;#t)
|
|
(set! *display-profile* #f)
|
|
(set! *cheat-mode* (if *debug-segment*
|
|
'debug
|
|
#f
|
|
))
|
|
(set! *time-of-day-fast* #f)
|
|
(load-commands-set! *level* '())
|
|
(when *time-of-day-proc*
|
|
(set! (-> *time-of-day-proc* 0 time-ratio) (fsec 1.0))
|
|
(set! (-> *time-of-day-proc* 0 hour) 7) ;; 7AM waking up in the morning
|
|
)
|
|
(set-blackout-frames 6)
|
|
(unless *dproc*
|
|
(reset! *load-state*)
|
|
(let ((s4-1 (level-get-for-use *level* startup-level 'active)))
|
|
(load-state-want-levels startup-level #f)
|
|
(load-state-want-display-level startup-level 'display)
|
|
(load-state-want-vis (-> (lookup-level-info startup-level) nickname))
|
|
(while (and s4-1 (or (= (-> s4-1 status) 'loading)
|
|
(= (-> s4-1 status) 'loading-bt)
|
|
(= (-> s4-1 status) 'login)))
|
|
(set-blackout-frames 6)
|
|
(load-continue s4-1)
|
|
)
|
|
)
|
|
)
|
|
(set! *print-login* #f)
|
|
(level-status-set! (level-get *level* startup-level) 'active)
|
|
)
|
|
|
|
(load-dbg "Load complete. Level: ~A. Now starting display!~%" (-> *level* level0))
|
|
(on #t)
|
|
(load-dbg "Display started: ~A~%" *dproc*)
|
|
(when init-game
|
|
(initialize! *game-info* 'game (the-as game-save #f) (the-as string #f))
|
|
)
|
|
0
|
|
)
|
|
|
|
(defun update-sound-banks ()
|
|
(if (nonzero? (rpc-busy? RPC-SOUND-LOADER))
|
|
(return 0)
|
|
)
|
|
(let ((gp-0 #f)
|
|
(s5-0 #f)
|
|
)
|
|
(dotimes (s4-0 (-> *level* length))
|
|
(let ((v1-5 (-> *level* level s4-0)))
|
|
(when (= (-> v1-5 status) 'active)
|
|
(let* ((s3-0 (-> v1-5 info sound-banks))
|
|
(t0-0 (the-as symbol (car s3-0)))
|
|
)
|
|
(while (not (null? s3-0))
|
|
(cond
|
|
((or (= gp-0 t0-0) (= s5-0 t0-0) (-> *setting-control* current movie))
|
|
)
|
|
((not gp-0)
|
|
(set! gp-0 t0-0)
|
|
)
|
|
((not s5-0)
|
|
(set! s5-0 t0-0)
|
|
)
|
|
(else
|
|
(format
|
|
0
|
|
"ERROR: Soundbanks ~A, ~A and ~A all required~%"
|
|
gp-0
|
|
s5-0
|
|
t0-0
|
|
)
|
|
)
|
|
)
|
|
(set! s3-0 (cdr s3-0))
|
|
(set! t0-0 (the-as symbol (car s3-0)))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(when (and gp-0 (!= gp-0 *sound-bank-1*) (!= gp-0 *sound-bank-2*))
|
|
(when (not *sound-bank-1*)
|
|
(format 0 "Load soundbank ~A~%" gp-0)
|
|
(sound-bank-load (string->sound-name (symbol->string gp-0)))
|
|
(set! *sound-bank-1* gp-0)
|
|
(return 0)
|
|
)
|
|
(when (not *sound-bank-2*)
|
|
(format 0 "Load soundbank ~A~%" gp-0)
|
|
(sound-bank-load (string->sound-name (symbol->string gp-0)))
|
|
(set! *sound-bank-2* gp-0)
|
|
(return 0)
|
|
)
|
|
(when (!= *sound-bank-1* s5-0)
|
|
(format 0 "Unload soundbank ~A~%" *sound-bank-1*)
|
|
(sound-bank-unload (string->sound-name (symbol->string *sound-bank-1*)))
|
|
(set! *sound-bank-1* #f)
|
|
(return 0)
|
|
)
|
|
(when (!= *sound-bank-2* s5-0)
|
|
(format 0 "Unload soundbank ~A~%" *sound-bank-2*)
|
|
(sound-bank-unload (string->sound-name (symbol->string *sound-bank-2*)))
|
|
(set! *sound-bank-2* #f)
|
|
(return 0)
|
|
)
|
|
)
|
|
(when (and s5-0 (!= s5-0 *sound-bank-1*) (!= s5-0 *sound-bank-2*))
|
|
(when (not *sound-bank-1*)
|
|
(format 0 "Load soundbank ~A~%" s5-0)
|
|
(sound-bank-load (string->sound-name (symbol->string s5-0)))
|
|
(set! *sound-bank-1* s5-0)
|
|
(return 0)
|
|
)
|
|
(when (not *sound-bank-2*)
|
|
(format 0 "Load soundbank ~A~%" s5-0)
|
|
(sound-bank-load (string->sound-name (symbol->string s5-0)))
|
|
(set! *sound-bank-2* s5-0)
|
|
(return 0)
|
|
)
|
|
(when (!= *sound-bank-1* gp-0)
|
|
(format 0 "Unload soundbank ~A~%" *sound-bank-1*)
|
|
(sound-bank-unload (string->sound-name (symbol->string *sound-bank-1*)))
|
|
(set! *sound-bank-1* #f)
|
|
(return 0)
|
|
)
|
|
(when (!= *sound-bank-2* gp-0)
|
|
(format 0 "Unload soundbank ~A~%" *sound-bank-2*)
|
|
(sound-bank-unload (string->sound-name (symbol->string *sound-bank-2*)))
|
|
(set! *sound-bank-2* #f)
|
|
(return 0)
|
|
)
|
|
)
|
|
)
|
|
0
|
|
)
|
|
|
|
(defmethod update! load-state ((obj load-state))
|
|
"Updates load requests."
|
|
|
|
(update-sound-banks)
|
|
|
|
(let ((v1-0 #f))
|
|
(dotimes (s5-0 2)
|
|
(let ((s4-0 (-> *level* level s5-0)))
|
|
(when (!= (-> s4-0 status) 'inactive)
|
|
(let ((a0-6 #f))
|
|
(dotimes (a1-2 2)
|
|
(if (= (-> s4-0 name) (-> obj want a1-2 name))
|
|
(set! a0-6 #t)
|
|
)
|
|
)
|
|
(when (not a0-6)
|
|
(format 0 "Discarding level ~A~%" (-> s4-0 name))
|
|
(level-status-set! s4-0 'inactive)
|
|
(set! v1-0 #t)
|
|
(#when PC_PORT
|
|
(when *debug-segment*
|
|
(define-extern *entity* entity)
|
|
(set! *entity* (the entity #f))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(let ((s5-1 #f))
|
|
(if (and (= (-> *level* level0 status) 'inactive)
|
|
(= (-> *level* level1 status) 'inactive)
|
|
)
|
|
(set! s5-1 #t)
|
|
)
|
|
(if v1-0
|
|
(return 0)
|
|
)
|
|
(let ((a0-20 #f)
|
|
(v1-5 #f)
|
|
)
|
|
(when (-> obj want 0 name)
|
|
(set! a0-20 #t)
|
|
(dotimes (a1-12 3)
|
|
(let ((a2-9 (-> *level* level a1-12)))
|
|
(if (and (!= (-> a2-9 status) 'inactive)
|
|
(= (-> a2-9 name) (-> obj want 0 name))
|
|
)
|
|
(set! a0-20 #f)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(when (-> obj want 1 name)
|
|
(set! v1-5 #t)
|
|
(dotimes (a1-17 3)
|
|
(let ((a2-17 (-> *level* level a1-17)))
|
|
(if (and (!= (-> a2-17 status) 'inactive)
|
|
(= (-> a2-17 name) (-> obj want 1 name))
|
|
)
|
|
(set! v1-5 #f)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(let ((s4-1 -1))
|
|
(cond
|
|
((and a0-20 v1-5)
|
|
(set! s4-1 0)
|
|
(if (and (-> obj want 1 display?)
|
|
(not (-> obj want 0 display?))
|
|
)
|
|
(set! s4-1 1)
|
|
)
|
|
)
|
|
(a0-20
|
|
(set! s4-1 0)
|
|
)
|
|
(v1-5
|
|
(set! s4-1 1)
|
|
)
|
|
)
|
|
(when (!= s4-1 -1)
|
|
(when (or s5-1 (not (check-busy *load-dgo-rpc*)))
|
|
(format 0 "Adding level ~A~%" (-> obj want s4-1 name))
|
|
(let ((s3-0 (level-get-for-use *level* (the-as symbol (-> obj want s4-1 name)) 'loaded)))
|
|
(when (and s5-1 (-> obj want s4-1 display?))
|
|
(format 0 "Waiting for level to load~%")
|
|
(while (or (= (-> s3-0 status) 'loading)
|
|
(= (-> s3-0 status) 'loading-bt)
|
|
(= (-> s3-0 status) 'login)
|
|
)
|
|
(load-continue s3-0)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(dotimes (s5-2 2)
|
|
(when (-> obj want s5-2 name)
|
|
(dotimes (s4-2 3)
|
|
(let ((s3-1 (-> *level* level s4-2)))
|
|
(when (!= (-> s3-1 status) 'inactive)
|
|
(when (= (-> s3-1 name) (-> obj want s5-2 name))
|
|
(when (!= (-> s3-1 display?) (-> obj want s5-2 display?))
|
|
(cond
|
|
((not (-> s3-1 display?))
|
|
(cond
|
|
((or (= (-> s3-1 status) 'loaded) (= (-> s3-1 status) 'active))
|
|
(format 0 "Displaying level ~A [~A]~%" (-> obj want s5-2 name) (-> obj want s5-2 display?))
|
|
(level-get-for-use *level* (-> s3-1 info name) 'active)
|
|
(set! (-> s3-1 display?) (-> obj want s5-2 display?))
|
|
)
|
|
(else
|
|
(when (and (-> s3-1 info wait-for-load)
|
|
(!= (-> obj want s5-2 display?) 'display-no-wait)
|
|
)
|
|
(send-event *target* 'loading)
|
|
)
|
|
(if (= *cheat-mode* 'debug)
|
|
(format *stdcon* "display on for ~A but level is loading~%" (-> obj want s5-2 name))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(else
|
|
(cond
|
|
((not (-> obj want s5-2 display?))
|
|
(set! (-> s3-1 display?) #f)
|
|
(format 0 "Turning level ~A off~%" (-> s3-1 name))
|
|
(deactivate s3-1)
|
|
)
|
|
(else
|
|
(format 0 "Setting level ~A display command to ~A~%" (-> obj want s5-2 name) (-> obj want s5-2 display?))
|
|
(set! (-> s3-1 display?) (-> obj want s5-2 display?))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
(when (!= (-> s3-1 force-all-visible?) (-> obj want s5-2 force-vis?))
|
|
(set! (-> s3-1 force-all-visible?) (-> obj want s5-2 force-vis?))
|
|
(format 0 "Setting force-all-visible?[~A] to ~A~%" (-> obj want s5-2 name) (-> obj want s5-2 force-vis?))
|
|
)
|
|
(when (!= (-> s3-1 force-inside?) (-> obj want s5-2 force-inside?))
|
|
(set! (-> s3-1 force-inside?) (-> obj want s5-2 force-inside?))
|
|
(format 0 "Setting force-inside?[~A] to ~A~%" (-> obj want s5-2 name) (-> obj want s5-2 force-inside?))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;; load vis info.
|
|
;; The load-state's vis-nick is the level we want vis data for.
|
|
;; Note that we won't load vis until we are inside the level's boxes.
|
|
|
|
;; this will be the level that is currently being used.
|
|
(let ((s5-3 #f))
|
|
(dotimes (v1-121 (-> *level* length))
|
|
(let ((a0-55 (-> *level* level v1-121)))
|
|
(when (= (-> a0-55 status) 'active) ;; level is active
|
|
(if (nonzero? (-> a0-55 vis-info (-> a0-55 vis-self-index) ramdisk)) ;; and vis is set up.
|
|
(set! s5-3 (-> a0-55 nickname))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;; if we have the wrong vis
|
|
(when (and (!= s5-3 (-> obj vis-nick)) (-> *level* vis?))
|
|
;; and we want a vis
|
|
(when (-> obj vis-nick)
|
|
;; find matching level and load vis
|
|
(dotimes (s4-3 (-> *level* length))
|
|
(let ((v1-133 (-> *level* level s4-3)))
|
|
(when (= (-> v1-133 status) 'active)
|
|
(if (and (= (-> v1-133 nickname) (-> obj vis-nick))
|
|
(-> v1-133 inside-boxes?) ;; note: only start if we are inside boxes.
|
|
)
|
|
(load-vis-info (-> obj vis-nick) s5-3)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
0
|
|
)
|
|
|
|
;; method 16 level-group (debug text stuff)
|
|
|
|
(defmethod level-update level-group ((obj level-group))
|
|
|
|
;; this does nothing...
|
|
(camera-pos)
|
|
(new 'static 'boxed-array :type symbol :length 0 :allocated-length 2)
|
|
|
|
;; compute the settings for this frame
|
|
(update-per-frame-settings! *setting-control*)
|
|
|
|
;; run the art loading system
|
|
(update *art-control* #t)
|
|
(clear-rec *art-control*)
|
|
|
|
;; run level loading!
|
|
(dotimes (s5-0 2)
|
|
(load-continue (-> obj level s5-0))
|
|
)
|
|
|
|
;; compute inside for each level
|
|
(dotimes (s5-1 (-> obj length))
|
|
(let ((s4-0 (-> obj level s5-1)))
|
|
(when (= (-> s4-0 status) 'active)
|
|
(set! (-> s4-0 inside-boxes?) (point-in-boxes? s4-0 (-> *math-camera* trans)))
|
|
(set! (-> s4-0 inside-sphere?) (>= (-> s4-0 bsp bsphere w) (-> s4-0 level-distance)))
|
|
;; being inside sets your meta-inside to #t. If you are outside, remember your old inside.
|
|
(if (-> s4-0 inside-boxes?)
|
|
(set! (-> s4-0 meta-inside?) #t)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;; update load state machine (the level-border one)
|
|
(update! *load-state*)
|
|
|
|
;; checkpoint assignment
|
|
(dotimes (s5-2 (-> obj length))
|
|
(let ((s4-1 (-> obj level s5-2)))
|
|
(when (= (-> s4-1 status) 'active)
|
|
;; if you're outside here, and inside somewhere else, kick out of meta inside.
|
|
(if (and (-> s4-1 inside-boxes?) (not (-> s4-1 other inside-boxes?)))
|
|
(set! (-> s4-1 other meta-inside?) #f)
|
|
)
|
|
(when (and (null? (-> obj load-commands))
|
|
(= (-> s4-1 nickname) (-> *load-state* vis-nick))
|
|
(!= (-> s4-1 name) (-> *game-info* current-continue level))
|
|
(-> *level* border?)
|
|
)
|
|
(let ((s3-0 (the-as continue-point (car (-> s4-1 info continues)))))
|
|
(let* ((s2-0 (target-pos 0))
|
|
(s4-2 (-> s4-1 info continues))
|
|
(s1-0 (the-as continue-point (car s4-2)))
|
|
)
|
|
(while (not (null? s4-2))
|
|
(if (and (< (vector-vector-distance s2-0 (-> s1-0 trans)) (vector-vector-distance s2-0 (-> s3-0 trans)))
|
|
(zero? (-> s1-0 flags))
|
|
)
|
|
(set! s3-0 s1-0)
|
|
)
|
|
(set! s4-2 (cdr s4-2))
|
|
(set! s1-0 (the-as continue-point (car s4-2)))
|
|
)
|
|
)
|
|
(set-continue! *game-info* s3-0)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;; determine vis info idx for each level
|
|
(dotimes (v1-67 (-> obj length))
|
|
(let ((a0-26 (-> obj level v1-67)))
|
|
(when (= (-> a0-26 status) 'active)
|
|
;; self is always 0
|
|
(set! (-> a0-26 vis-self-index) 0)
|
|
;; neighbor level defaults to 7 (null placeholder)...
|
|
(set! (-> a0-26 vis-adj-index) 7)
|
|
;; but if there's a second level that's active, search for a vis info for that level...
|
|
(when (= (-> a0-26 other status) 'active)
|
|
(dotimes (a1-10 8)
|
|
(if (and (-> a0-26 vis-info a1-10)
|
|
(= (-> a0-26 vis-info a1-10 from-level) (-> a0-26 other load-name))
|
|
)
|
|
;; and store it in the adj index.
|
|
(set! (-> a0-26 vis-adj-index) a1-10)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;; display level vis info
|
|
(when *display-level-border*
|
|
(dotimes (s5-3 (-> obj length))
|
|
(let ((s4-3 (-> obj level s5-3)))
|
|
(when (= (-> s4-3 status) 'active)
|
|
(let ((s3-1 (-> s4-3 bsp current-bsp-back-flags)))
|
|
(dotimes (s2-1 6)
|
|
(when (and (logtest? s3-1 3) (-> s4-3 vis-info (+ s2-1 1)))
|
|
(let
|
|
((v1-88 (lookup-level-info (-> s4-3 vis-info (+ s2-1 1) from-level))))
|
|
(format
|
|
*stdcon*
|
|
" ~A -> ~A: load: ~A display: ~A~%"
|
|
(-> s4-3 name)
|
|
(-> v1-88 name)
|
|
(logtest? s3-1 1)
|
|
(logtest? s3-1 2)
|
|
)
|
|
)
|
|
)
|
|
(set! s3-1 (shr s3-1 2))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;; if we have vis for level A, but we aren't "in" it, display an error and
|
|
;; force us out of the other level. Ideally the boxes and the load boundary system
|
|
;; will be consistent and there is no way to set a vis to a level that we aren't in.
|
|
;; (you can be "in" multiple levels at the same time, when crossing levels, it is expected
|
|
;; that you are in both.)
|
|
(dotimes (s5-4 (-> obj length))
|
|
(let ((s4-4 (-> obj level s5-4)))
|
|
(when (= (-> s4-4 status) 'active)
|
|
(when (and (= (-> s4-4 nickname) (-> *load-state* vis-nick)) ;; vis for A
|
|
(not (-> s4-4 inside-boxes?)) ;; but not in A
|
|
)
|
|
(if (and (= *cheat-mode* 'debug) (-> s4-4 other inside-boxes?))
|
|
(format
|
|
*stdcon*
|
|
"~3LForcing outside of ~A [bad split boxes]~%~0L"
|
|
(-> s4-4 other name)
|
|
)
|
|
)
|
|
(set! (-> s4-4 other inside-boxes?) #f)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;; if we are outside of the boxes, we consider ourselves "outside of bsp"
|
|
;; if we are outside of both levels boxes, then we don't really know what to do
|
|
;; for vis, and we can display the classic "outside of bsp" error.
|
|
(cond
|
|
((not (or (-> obj level0 inside-boxes?) (-> obj level1 inside-boxes?)))
|
|
(when (or (-> obj level0 vis-info 0) (-> obj level1 vis-info 0))
|
|
(if (= *cheat-mode* 'debug)
|
|
(format *stdcon* "~3Loutside of bsp~%~0L")
|
|
)
|
|
)
|
|
)
|
|
(else
|
|
;; we are in at least one bsp.
|
|
;; now we need to link vis info to bsps.
|
|
(dotimes (v1-125 (-> obj length))
|
|
(let ((a0-44 (-> obj level v1-125)))
|
|
(when (= (-> a0-44 status) 'active)
|
|
;; loop over vis infos
|
|
(dotimes (a1-17 8)
|
|
(let ((a2-18 (-> a0-44 vis-info a1-17)))
|
|
(when a2-18
|
|
;; clear bit 31
|
|
(set! (-> a2-18 flags) (logand (the-as uint #xffffffff7fffffff) (-> a2-18 flags)))
|
|
;; link info to bsp
|
|
(cond
|
|
((= a1-17 (-> a0-44 vis-self-index))
|
|
(set! (-> a2-18 from-bsp) (-> a0-44 bsp))
|
|
)
|
|
((= a1-17 (-> a0-44 vis-adj-index))
|
|
(set! (-> a2-18 from-bsp) (-> a0-44 other bsp))
|
|
)
|
|
(else
|
|
(set! (-> a2-18 from-bsp) #f)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
;; now, handle setting bit 31 (maybe single vis mode?)
|
|
(cond
|
|
;; special display self mode.
|
|
((= (-> a0-44 display?) 'display-self)
|
|
(let ((a0-46 (-> a0-44 vis-info (-> a0-44 vis-self-index))))
|
|
(if a0-46
|
|
(set! (-> a0-46 flags) (the-as uint (logior (shl #x8000 16) (-> a0-46 flags))))
|
|
)
|
|
)
|
|
)
|
|
;; in this level, but not the other, only use vis for this.
|
|
((and (-> a0-44 inside-boxes?) (not (-> a0-44 other inside-boxes?)))
|
|
(let ((a0-48 (-> a0-44 vis-info (-> a0-44 vis-self-index))))
|
|
(if a0-48
|
|
(set! (-> a0-48 flags) (the-as uint (logior (shl #x8000 16) (-> a0-48 flags))))
|
|
)
|
|
)
|
|
)
|
|
;; only in other level, only use vis for other.
|
|
((-> a0-44 other inside-boxes?)
|
|
(let ((a0-50 (-> a0-44 vis-info (-> a0-44 vis-adj-index))))
|
|
(if a0-50
|
|
(set! (-> a0-50 flags) (the-as uint (logior (shl #x8000 16) (-> a0-50 flags))))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
(when (or *display-level-border* *display-texture-download* *display-split-box-info*)
|
|
(when *display-level-border*
|
|
(format *stdcon* " want: ~A ~A/~A ~A ~A/~A~%"
|
|
(-> *load-state* want 0 name)
|
|
(-> *load-state* want 0 display?)
|
|
(-> *load-state* want 0 force-vis?)
|
|
(-> *load-state* want 1 name)
|
|
(-> *load-state* want 1 display?)
|
|
(-> *load-state* want 1 force-vis?)
|
|
)
|
|
(format *stdcon* " nick ~A cur ~S cont ~A~%~%"
|
|
(-> *load-state* vis-nick)
|
|
(let ((lev-name (and *target* (-> *target* current-level name))))
|
|
(if lev-name
|
|
(symbol->string lev-name)
|
|
)
|
|
)
|
|
(-> *game-info* current-continue name)
|
|
)
|
|
; (let ((t9-16 format)
|
|
; (a0-53 *stdcon*)
|
|
; (a1-49 " nick ~A cur ~S cont ~A~%~%")
|
|
; (a2-24 (-> *load-state* vis-nick))
|
|
; (v1-142 (and *target* (-> *target* current-level name)))
|
|
; )
|
|
; (t9-16 a0-53 a1-49 a2-24 (if v1-142
|
|
; (->
|
|
; (the-as
|
|
; (pointer uint32)
|
|
; (+ #xff38 (the-as int v1-142))
|
|
; )
|
|
; )
|
|
; )
|
|
; (-> *game-info* current-continue name)
|
|
; )
|
|
; )
|
|
)
|
|
(dotimes (s5-5 (-> obj length))
|
|
(let ((s4-5 (-> obj level s5-5)))
|
|
(when (= (-> s4-5 status) 'active)
|
|
(format *stdcon* "~A: ~S ~A~%"
|
|
(-> s4-5 name)
|
|
(if (point-in-boxes? s4-5 (-> *math-camera* trans))
|
|
"inside"
|
|
)
|
|
(-> s4-5 display?)
|
|
)
|
|
(when *display-texture-download*
|
|
(format *stdcon* " tfrag: ~8,,0m " (-> s4-5 closest-object 0))
|
|
(format *stdcon* " shrub: ~8,,0m " (-> s4-5 closest-object 2))
|
|
(format *stdcon* " alpha: ~8,,0m #x~8X~%"(-> s4-5 closest-object 3) (-> s4-5 texture-mask 8))
|
|
(format *stdcon* " tie: ~8,,0m " (-> s4-5 closest-object 5))
|
|
(format *stdcon* " fg-tf: ~8,,0m " (-> s4-5 closest-object 6))
|
|
(format *stdcon* " fg-pr: ~8,,0m #x~8X~%"(-> s4-5 closest-object 7) (-> s4-5 texture-mask 7))
|
|
(format *stdcon* " tf: ~8D pr: ~8D sh: ~8D al: ~8D wa: ~8D~%~1K"
|
|
(-> s4-5 upload-size 0)
|
|
(-> s4-5 upload-size 1)
|
|
(-> s4-5 upload-size 2)
|
|
(-> s4-5 upload-size 3)
|
|
(-> s4-5 upload-size 4)
|
|
)
|
|
)
|
|
(if *display-split-box-info*
|
|
(debug-print-splitbox s4-5 (-> *math-camera* trans) *stdcon*)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
0
|
|
)
|
|
|
|
(defun-debug show-level ((level-name symbol))
|
|
(set! (-> *setting-control* default border-mode) #t)
|
|
(load-state-want-levels (-> (level-get-target-inside *level*) name) level-name)
|
|
(load-state-want-display-level level-name 'display)
|
|
0
|
|
)
|
|
|
|
;; init art buffers and engines
|
|
(when (zero? (-> *level* level0 art-group))
|
|
(let ((lev-group *level*))
|
|
(set! (-> lev-group vis?) #f)
|
|
(set! (-> lev-group loading-level) (-> lev-group level-default))
|
|
(set! (-> lev-group level0 art-group) (new 'global 'load-dir-art-group 50 (-> lev-group level0)))
|
|
(set! (-> lev-group level0 foreground-draw-engine 0) (new 'global 'engine 'draw 280))
|
|
(set! (-> lev-group level0 foreground-draw-engine 1) (new 'global 'engine 'draw 280))
|
|
(set! (-> lev-group level0 foreground-draw-engine 2) (new 'global 'engine 'draw 16))
|
|
(set! (-> lev-group level1 art-group) (new 'global 'load-dir-art-group 50 (-> lev-group level1)))
|
|
(set! (-> lev-group level1 foreground-draw-engine 0) (new 'global 'engine 'draw 280))
|
|
(set! (-> lev-group level1 foreground-draw-engine 1) (new 'global 'engine 'draw 280))
|
|
(set! (-> lev-group level1 foreground-draw-engine 2) (new 'global 'engine 'draw 16))
|
|
(set! (-> lev-group level-default art-group) (new 'global 'load-dir-art-group 50 (-> lev-group level1)))
|
|
(set! (-> lev-group level-default foreground-draw-engine 0) (new 'global 'engine 'draw 280))
|
|
(set! (-> lev-group level-default foreground-draw-engine 1) (new 'global 'engine 'draw 10))
|
|
(set! (-> lev-group level0 other) (-> lev-group level1))
|
|
(set! (-> lev-group level1 other) (-> lev-group level0))
|
|
(set! (-> lev-group level-default other) #f)
|
|
(dotimes (i 2)
|
|
(let ((lev (-> lev-group level i)))
|
|
(set! (-> lev vis-bits) (malloc 'global 2048))
|
|
(vis-clear lev)
|
|
)
|
|
)
|
|
(dotimes (i 3)
|
|
(let ((lev (-> lev-group level i)))
|
|
(set! (-> lev linking) #f)
|
|
(dotimes (ii 3)
|
|
(set! (-> lev foreground-sink-group ii level) lev)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
(defmacro test-play ()
|
|
`(begin
|
|
;; before calling play, the C Kernel would set this.
|
|
(define *kernel-boot-message* 'play)
|
|
(load-package "game" global)
|
|
(play #t #t)
|
|
)
|
|
)
|