jak-project/goal_src/jak2/engine/level/level.gc
water111 2fc943977f
[jak2] GOAL side texture animation stuff (#2766)
It turns out we didn't decompile any of this stuff yet.
2023-06-24 10:11:47 -04:00

3027 lines
111 KiB
Common Lisp

;;-*-Lisp-*-
(in-package goal)
;; name: level.gc
;; name in dgo: level
;; dgos: ENGINE, GAME
#|@file
the level heap is a giant block of memory which is seperated into "pages" so that it can easily
be split into different sizes for the different kinds of level sizes.
it is split into 6 sections, 24-24-25-25-24-24 pages large.
this means the "center" portion of the main level heap is actually "larger"
which is why there is a special small-center level memory mode for two-section
levels that want to be placed in the middle of the heap for that slight size boost.
some code checks for 7 bits in the memory mask, indicating the heap was originally split
into 7 sections, which might explain the weird sizes in the center.
|#
;; DECOMP BEGINS
(define-extern level-update-after-load (function level login-state level))
(define-extern *level-type-list* type)
(defglobalconstant NUM_LEVEL_PAGES 146)
(defglobalconstant LEVEL_PAGE_SIZE_KB 126) ;; original value
(defglobalconstant LEVEL_PAGE_SIZE (* LEVEL_PAGE_SIZE_KB 1024)) ;; original value
(defglobalconstant LEVEL_HEAP_SIZE (* NUM_LEVEL_PAGES LEVEL_PAGE_SIZE))
;(defglobalconstant DEBUG_LEVEL_HEAP_MULT 1.5) ;; level heap in debug mode is 1.5x larger
(defglobalconstant DEBUG_LEVEL_HEAP_MULT 1.1) ;; we're gonna use debug mode-style heaps but we don't actually need them at 1.5x size right now
(defglobalconstant DEBUG_LEVEL_PAGE_SIZE (* 1024 (* DEBUG_LEVEL_HEAP_MULT LEVEL_PAGE_SIZE_KB)))
(defglobalconstant DEBUG_LEVEL_HEAP_SIZE (* NUM_LEVEL_PAGES DEBUG_LEVEL_PAGE_SIZE))
;; multiplier for borrow heap size. It is a bit of a hack required to load the slightly larger PC port levels.
;; in the original game, borrow levels never got extra room, even with big level heaps
;; Setting this means that borrow won't work with normal-size level heaps, but this is probably okay
;; because normal-size level heaps don't work at all.
(defglobalconstant BORROW_MULT DEBUG_LEVEL_HEAP_MULT)
(defun give-all-stuff ()
(send-event *target* 'get-pickup 18 #x447a0000)
(send-event *target* 'get-pickup 17 #x447a0000)
(send-event *target* 'get-pickup 13 #x447a0000)
(send-event *target* 'get-pickup 14 #x447a0000)
(send-event *target* 'get-pickup 15 #x447a0000)
(send-event *target* 'get-pickup 16 #x447a0000)
(send-event *target* 'get-pickup 7 #x42c80000)
(logior! (-> *game-info* features) (game-feature gun gun-yellow gun-red gun-blue gun-dark board darkjak))
(let ((v0-7
(logior (-> *game-info* debug-features) (game-feature gun gun-yellow gun-red gun-blue gun-dark board darkjak))
)
)
(set! (-> *game-info* debug-features) v0-7)
v0-7
)
)
(defmacro test-play ()
"Temporary start macro"
`(begin
(start-debug "test-play~%")
(define *kernel-boot-message* 'play)
(start-debug "loading GAME.DGO~%")
(load-package "game" global)
(play-boot)
;; wait 10 frames and then turn on profile bars.
;; they get shut off as part of startup, so we can't do it here.
(process-spawn-function
process
(lambda ()
(dotimes (i 10)
(suspend)
)
(set! *display-profile* #t)
(give-all-stuff)
;;(set! *stats-profile-bars* #t)
)
)
)
)
(defun lookup-level-info ((arg0 symbol))
"Get level-load-info for the specified level.
The level-load-info for all levels is always available to the engine and is used
to figure out how to load levels."
(let* ((v1-0 *level-load-list*)
(a1-0 (car v1-0))
)
(while (not (null? v1-0))
(let ((a1-1 (the-as level-load-info (-> (the-as symbol a1-0) value))))
(if (or (= arg0 (-> a1-1 name)) (= arg0 (-> a1-1 visname)) (= arg0 (-> a1-1 nickname)))
(return a1-1)
)
)
(set! v1-0 (cdr v1-0))
(set! a1-0 (car v1-0))
)
)
default-level
)
(defmethod alt-load-command-get-index level-group ((obj level-group) (arg0 symbol) (arg1 int))
"Get the n-th alt-load-command for the given level.
This is likely unused in jak 2 because no levels have alt-load-commands."
(let ((v1-1 (-> (lookup-level-info arg0) alt-load-commands)))
(while (nonzero? arg1)
(+! arg1 -1)
(set! v1-1 (cdr v1-1))
(nop!)
(nop!)
(nop!)
)
(the-as pair (car v1-1))
)
)
(defmethod load-in-progress? level-group ((obj level-group))
"Is a level being loaded right now?"
(!= (-> *level* loading-level) (-> *level* default-level))
)
(defmethod get-level-by-heap-ptr-and-status level-group ((obj level-group) (arg0 pointer) (arg1 symbol))
"Get a level by a heap pointer and status.
If no matching level is found, return #f.
The purpose of the status check is possibly to prevent bugs with getting stuff
from a level that's just been replaced with another."
(case arg1
(('active)
(dotimes (v1-1 (-> obj length))
(let ((a2-6 (-> obj level v1-1)))
(when (= (-> a2-6 status) 'active)
(if (and (>= (the-as int arg0) (the-as int (-> a2-6 heap base)))
(< (the-as int arg0) (the-as int (-> a2-6 heap top-base)))
)
(return a2-6)
)
)
)
)
)
(('loading)
(dotimes (v1-5 (-> obj length))
(let ((a2-12 (-> obj level v1-5)))
(when (!= (-> a2-12 status) 'inactive)
(if (and (>= (the-as int arg0) (the-as int (-> a2-12 heap base)))
(< (the-as int arg0) (the-as int (-> a2-12 heap top-base)))
)
(return a2-12)
)
)
)
)
)
)
(the-as level #f)
)
(defun remap-level-name ((arg0 level-load-info))
"Get the name of a level to use. Picks the visname if the vis? setting is on."
(if (-> *level* vis?)
(-> arg0 visname)
(-> arg0 name)
)
)
(defmethod get-art-group-by-name level ((obj level) (arg0 string))
"As the name implies, look through the art-groups of this level and get the one
with the given name. Return #f if not found."
(countdown (s4-0 (-> obj art-group art-group-array length))
(if (name= (-> obj art-group art-group-array s4-0 name) arg0)
(return (-> obj art-group art-group-array s4-0))
)
)
(the-as art-group #f)
)
(defmethod bsp-name level ((obj level))
"Get the name of the bsp. If this can't be done, get the name of the level."
(if (and (!= (-> obj status) 'inactive) (-> obj bsp) (nonzero? (-> obj bsp name)))
(-> obj bsp name)
(-> obj name)
)
)
(defun add-bsp-drawable ((arg0 bsp-header) (arg1 level) (arg2 symbol) (arg3 display-frame))
"Draw this bsp!
Calling draw on a bsp mostly just adds stuff to background-work, so maybe that's why
it's called 'add'. This also will do a debug-draw on the entire bsp if the
display-strip-lines option is set."
(draw arg0 arg0 arg3)
(if (nonzero? *display-strip-lines*)
(debug-draw arg0 arg0 arg3)
)
(none)
)
(defmethod print level ((obj level))
(format #t "#<~A ~A ~S @ #x~X>" (-> obj type) (-> obj status) (-> obj name) obj)
obj
)
(defmethod relocate bsp-header ((obj bsp-header) (arg0 int))
"Handle the load of a new bsp-header. The linker calls this function
when the bsp-header is linked.
Do some sanity checks and link the bsp-header and level to each other."
(let ((s5-0 (-> *level* loading-level)))
(when s5-0
(cond
(obj
(cond
((not (type? obj 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
(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)
)
)
)
)
)
(defmethod load-required-packages level ((obj level))
"Load packages for a level.
This just loads common, and this feature is not really useful.
Packages were only used during development, and seem only partially used in Jak 2
(the only package is common)."
(when (not (or (not (-> obj bsp)) (= *kernel-boot-mode* 'debug-boot)))
(if (not (null? (-> obj info packages)))
(load-package "common" global)
)
)
obj
)
(defmethod vis-clear level ((obj level))
"Completely invalide all visibility data, vis-info, and set all-visible? to loading."
(countdown (v1-0 8)
(nop!)
(set! (-> obj vis-info v1-0) #f)
)
(dotimes (v1-3 128)
(set! (-> (the-as (pointer int128) (&+ (-> obj vis-bits) (* v1-3 16)))) (the int128 0))
)
(set! (-> obj all-visible?) 'loading)
0
(none)
)
(defmethod init-vis-from-bsp level ((obj level))
"Set up a level's vis-infos from a bsp."
(when (not (or (= (-> obj status) 'inactive) (not (-> obj bsp))))
;; mark our visibility as 'loading.
(set! (-> obj all-visible?) 'loading)
;; check vis-info's from the loaded bsp:
(dotimes (s5-0 8)
(let ((s4-0 (-> obj bsp vis-info s5-0)))
(cond
((and s4-0 (nonzero? s4-0) (valid? s4-0 level-vis-info (the-as string #f) #f 0))
;; looks good
;; level -> vis info
(set! (-> obj vis-info s5-0) s4-0)
(set! (-> s4-0 current-vis-string) (the-as uint -1))
;; vis info -> bsp
(if (= (-> s4-0 from-level) (-> obj load-name))
(set! (-> s4-0 from-bsp) (-> obj bsp))
(set! (-> s4-0 from-bsp) #f)
)
;; vis info -> level's vis-bits
(set! (-> s4-0 vis-bits) (the-as uint (-> obj vis-bits)))
(set! (-> s4-0 flags)
(the-as vis-info-flag (logclear (-> s4-0 flags) (vis-info-flag in-iop loading vis-valid)))
)
(set! *vis-boot* #t)
)
(else
(set! (-> obj vis-info s5-0) #f)
)
)
)
)
)
0
(none)
)
(defmethod level-get-for-use level-group ((obj level-group) (arg0 symbol) (arg1 symbol))
"Request a level by name in the given state.
Will return quickly (non-blocking) and might not be able to get a level in the desired state,
though it will ofborrow do some small amount of work to make progress on loading.
This is the most general/powerful function like this: if there is no level with this name
it will kick out levels as needed to make a free slot, and set up a new level, and start
the load. This should only be used when you might want to start a load.
"
(local-vars (s5-1 level))
(start-debug "level-get-for-use: ~A ~A~%" arg0 arg1)
;; make sure we have level heaps
(alloc-levels-if-needed obj #f)
;; look up the requested level
(let* ((s2-0 (lookup-level-info arg0))
(s1-0 (remap-level-name s2-0))
)
(start-debug "level info: ~A, remapped name: ~A~%" s2-0 s1-0)
;; if we already have it, try updating status, then return it
(let ((s5-0 (level-get obj s1-0)))
(when s5-0
(level-status-update! s5-0 arg1)
(set! s5-1 s5-0)
(goto cfg-13)
)
)
(start-debug "level isn't loaded already, need to find a level~%")
;; find slot to load into
(let ((a0-7 (level-get-most-disposable obj)))
(start-debug "found slot: ~A~%" a0-7)
;; mark it as inactive, we're kicking it out.
(set! s5-1 (if a0-7
(level-status-update! a0-7 'inactive)
a0-7
)
)
)
;; oops: same bug as jak 1 here...
(when (not level)
(format 0 "ERROR: could not find a slot to load ~A into.~%" arg0)
(set! s5-1 (the-as level #f))
(goto cfg-13)
)
;; remember where we were loaded
(let ((v1-13 (+ (-> obj load-order) 1)))
(set! (-> obj load-order) v1-13)
(set! (-> s5-1 load-order) (the-as int v1-13))
)
;; set up the level info
(set! (-> s5-1 info) s2-0)
(set! (-> s5-1 name) arg0)
(set! (-> s5-1 load-name) s1-0)
)
;; other setup from level-info
(set! (-> s5-1 mood-func) (the-as (function mood-context float int none) (-> s5-1 info mood-func value)))
(set! (-> s5-1 mood-init) (the-as (function mood-context none) (-> s5-1 info mood-init value)))
;; clear old stuff in level
(dotimes (v1-20 10)
(set! (-> s5-1 texture-anim-array v1-20) #f)
)
(set! (-> s5-1 display?) #f)
(set! (-> s5-1 force-all-visible?) #f)
(set! (-> s5-1 force-inside?) #f)
;; kick off the load!
(start-debug "about to start loading~%")
(level-status-update! s5-1 'loading)
(start-debug "done with load in level-get-for-use, now updating to ~A~%" arg1)
(level-status-update! s5-1 arg1)
(label cfg-13)
s5-1
)
(defmethod level-status level-group ((obj level-group) (arg0 symbol))
"Get the status of a level by name, return #f if no level is found."
(let ((v1-1 (level-get *level* arg0)))
(if v1-1
(-> v1-1 status)
)
)
)
(defmethod level-status-update! level ((obj level) (arg0 symbol))
"Try to update the level to the given status, calling whatever is needed
to make it happen.
This can do both loading, linking, login, and activation.
This is somewhat similar to level-get-for-use, but requires that you already have
the level object.
This function is the way to transition from loaded to alive/active."
(start-debug "level-status-update trying to do ~A to ~A for ~A~%" (-> obj status) arg0 (-> obj name))
(case arg0
(('inactive)
;; any request to go inactive should unload.
(-> obj status)
(unload! obj)
)
(('loading)
(case (-> obj status)
(('inactive)
;; inactive -> loading transition, start the loader
(load-begin obj)
)
)
)
(('loading-bt)
(case (-> obj status)
(('loading)
;; loading -> loading-bt, transition immediately and do one load-continue
(set! (-> obj status) arg0)
(load-continue obj)
)
)
)
(('loading-done)
(case (-> obj status)
(('loading-bt)
;; loading-bt -> loading-done, the only allowed transition to loading-done
(set! (-> obj status) arg0)
)
)
)
(('loaded)
(case (-> obj status)
(('loading-done)
;; loading-done->loaded, need to log in first
(login-begin obj)
)
(('alive 'active)
;; deactivating
(deactivate obj)
)
)
)
(('alive 'active)
(when *dproc*
;; we do this twice, once to alive, then once to active.
;; alive means that entities are alive, active means alive and
;; added to draw engine.
(case (-> obj status)
(('loaded)
;; loaded (so logged in too), do birth (will set to alive), then try again
(birth obj)
(level-status-update! obj arg0)
)
(('alive)
;; on the second run, gets here:
(when (and *dproc* (= arg0 'active))
;; remember when
(when (zero? (-> obj display-start-time))
(set! (-> obj display-start-time) (-> *display* real-clock frame-counter))
0
)
;; add us to the background draw engine! this will cause us to be drawn.
(remove-by-param1 *background-draw-engine* (the-as int (-> obj bsp)))
(add-connection *background-draw-engine* *dproc* add-bsp-drawable (-> obj bsp) obj #f)
;; not sure why this becomes 0...
(dotimes (v1-46 18)
(set! (-> obj closest-object-array v1-46) 0.0)
(set! (-> obj texture-mask v1-46 mask quad) (the-as uint128 0))
)
(set! (-> obj status) 'active)
;; set up for drawing.
(assign-draw-indices *level*)
)
)
)
)
)
)
obj
)
(define *login-state* (new 'global 'login-state))
(define *print-login* #t)
;; load buffering:
;; the dgo loader and linker are double buffered and require two temp buffers
;; while the dgo loader is loading from the DVD to one buffer, the linker is using the other.
;; the linker will copy data from the temp buffer to the heap.
;; the final object loaded by the DGO loader will be loaded directly to the heap, not the temporary buffer.
;; this is the bt load (buffer top?). This can't be double buffered - the linker and login process may allocate memory.
;; the extra syncronization point is in RunDGOStateMachine in the Overlord (see DgoState::Read_Last_Obj)
;; this approach has 2 advantages:
;; - this final load can completely fill up the heap, without needing a separate temporary load buffer
;; - this final load can skip copying data from a temporary buffer (requires v4 format)
;; - the final load can be an object much larger than the temporary buffers.
(defun load-buffer-resize ((arg0 level) (arg1 dgo-header))
"Adjust the load buffers size and location.
The dgo-header passed in should be the load buffer we're about to use."
;; first, determine the size.
;; interestingly, if we are in the 'medium' mode, we use the size of the
;; previous object, plus 2048 bytes. Maybe the objects are sorted in decreasing size,
;; so this allows the big ones to load first, then shrink the temp buffer as the rest come in.
;; the "medium" case is hit because the relocate method for `art-group` changes the mode.
;; if it detects that it runs after textures.
(case (-> arg0 load-buffer-mode)
(((load-buffer-mode small-center))
(set! (-> arg0 load-buffer-size) (the-as uint (* 1100 1024))) ;; 1100 KB
)
(((load-buffer-mode medium))
(set! (-> arg0 load-buffer-size) (+ (-> arg1 length) (* 2 1024)))
)
)
;; adjust the load buffer location
;; the two load buffers are located at the top of the heap, like in jak 1.
(let ((v1-6 (logand -64 (+ (-> arg0 load-buffer-size) 63))))
(if (= arg1 (-> arg0 load-buffer 0))
;; loading to 0, just place this before load-buffer 1 (in use, can't modify)
(set! (-> arg0 load-buffer 0) (- (-> arg0 load-buffer 1) v1-6))
;; loading to 1, place relative to the top of the heap.
(set! (-> arg0 load-buffer 1)
(the-as uint (&- (logand -64 (&+ (-> arg0 heap top-base) 0)) (the-as uint v1-6)))
)
)
)
;; update heap top pointer.
(set! (-> arg0 heap top) (the-as pointer (-> arg0 load-buffer 0)))
0
(none)
)
;; borrowing system:
;; the "borrow" system allows a "borrower" level to use the heap of another level.
;; for an unknown reason, the borrow system doesn't use the double buffering of normal.
;; it's unclear exactly how the linking/loading works here, and it may be that we're missing
;; a case in the DGO loader here. If the objects come in totally corrupted, we're likely missing
;; some additional syncronization.
(defmethod load-continue level ((obj level))
"Run the loading/login state machine.
This will only make progress on loading, linking, and login for loads that have already started.
No 'scary' state transitions (like birth, alive, deactivate) are made here."
(local-vars (sv-16 symbol))
;; if any linking is in progress, do that first.
(when (-> obj linking)
(when (nonzero? (link-resume)) ;; run linker
;; linker return is nonzero, we're done!
(start-debug "link done!~%")
(set! (-> obj linking) #f)
(case (-> obj status)
(('loading) ;; we're loading to b0/b1, not the top buffer
;; if we are doing a texture relocate later, don't do anything now, come back later.
(when (not (-> *texture-relocate-later* memcpy))
(cond
((= (-> obj load-buffer-mode) (load-buffer-mode borrow))
;; in this "borrow" mode, load directly to the heap.
(start-debug "kick load borrow case~%")
(let ((a2-0 (logand -64 (&+ (-> obj heap current) 63))))
(dgo-load-continue a2-0 a2-0 a2-0)
)
)
(else
;; otherwise, continue with double buffered load to b0/b1 like normal
;; update load buffers, and make the dgo loader continue.
(load-buffer-resize obj (the-as dgo-header (-> obj load-buffer-last)))
(start-debug "kicking next load~%")
(dgo-load-continue
(the-as pointer (-> obj load-buffer 0))
(the-as pointer (-> obj load-buffer 1))
(logand -64 (&+ (-> obj heap current) 63))
)
)
)
)
)
(('loading-bt)
;; finished linking the final object! begin login.
(level-status-update! obj 'loading-done)
(level-status-update! obj 'loaded)
)
)
)
(set! obj obj)
(goto cfg-39)
)
;; if any pending texture-relocate, do that, then kick the dgo loader.
;; (note that this doens't handle mode "borrow")
(when (-> *texture-relocate-later* memcpy)
(relocate-later)
(load-buffer-resize obj (the-as dgo-header (-> obj load-buffer-last)))
(dgo-load-continue
(the-as pointer (-> obj load-buffer 0))
(the-as pointer (-> obj load-buffer 1))
(logand -64 (&+ (-> obj heap current) 63))
)
(set! obj obj)
(goto cfg-39)
)
;; not waiting on the linker, check other cases
(case (-> obj status)
(('loading)
;; if loading, we are waiting on the DGO loader. Check it again:
(set! sv-16 (the-as symbol #f))
(let ((s5-0 (dgo-load-get-next (& sv-16))))
(when s5-0
;; we got something! remember where and update stats
(set! (-> obj load-buffer-last) (the-as uint s5-0))
(+! (-> *level* load-size) (-> (the-as (pointer uint32) s5-0)))
(set! (-> *level* load-time)
(* 0.016666668 (the float (- (-> *display* real-clock integral-frame-counter) (the-as uint *dgo-time*))))
)
(set! (-> *level* load-login-time)
(* 0.016666668 (the float (- (-> *display* real-clock integral-frame-counter) (the-as uint *dgo-time*))))
)
(cond
((not sv-16)
;; not the last object
(cond
((= (-> obj load-buffer-mode) (load-buffer-mode borrow))
;; start the linker. in "borrow" mode, load directly to the heap again.
(cond
((dgo-load-link (the-as dgo-header s5-0) (-> obj heap) (the-as uint (-> obj heap top-base)) *print-login* #f)
;; linker finished immediately, kick off next load
(when (not (-> *texture-relocate-later* memcpy))
(let ((a2-8 (logand -64 (&+ (-> obj heap current) 63))))
(dgo-load-continue a2-8 a2-8 a2-8)
)
)
)
(else
;; linker still going, remember and come back later.
(set! (-> obj linking) #t)
)
)
)
;; not borrow mode, start linker
((dgo-load-link (the-as dgo-header s5-0) (-> obj heap) (-> obj load-buffer 1) *print-login* #f)
;; finished immediately, kick off next loa
(when (not (-> *texture-relocate-later* memcpy))
(load-buffer-resize obj (the-as dgo-header s5-0))
(dgo-load-continue
(the-as pointer (-> obj load-buffer 0))
(the-as pointer (-> obj load-buffer 1))
(logand -64 (&+ (-> obj heap current) 63))
)
)
)
(else
;; otherwise remember we're loading.
(set! (-> obj linking) #t)
)
)
)
(else
;; we are the last object. update heap top and go to bt load.
(set! (-> obj heap top) (-> obj heap top-base))
(level-status-update! obj 'loading-bt)
)
)
)
)
)
(('login)
;; logging in, load already finished. run the login state machine
(level-update-after-load obj *login-state*)
)
(('loading-bt)
;; last object was loaded, start linking it.
(let ((a0-36 (logand -64 (&+ (-> obj heap current) 63))))
(cond
((dgo-load-link (the-as dgo-header a0-36) (-> obj heap) (the-as uint (-> obj heap top-base)) *print-login* #t)
(level-status-update! obj 'loading-done)
(level-status-update! obj 'loaded)
)
(else
(set! (-> obj linking) #t)
)
)
)
)
)
(label cfg-39)
obj
)
(defmethod load-begin level ((obj level))
"Begin loading a level.
This assigns memory to a level and is somewhat confusing."
(local-vars (bits-to-use int) (borrow-from-lev level) (found-borrow symbol))
(when (!= (&- (-> *level* heap top) (the-as uint (-> *level* heap base))) DEBUG_LEVEL_HEAP_SIZE)
(format 0 "------------- load-begin called without large level heaps. This is not supported on PC~%")
(break!)
)
;; a "borrow" level will borrow the heap of an existing level
(dotimes (v1-0 2)
(set! (-> obj borrow-level v1-0) #f) ;; levels that borrow our heap
)
(set! (-> obj borrow-from-level) #f) ;; level that we borrow our heap for.
(set! (-> obj memory-mask) (the-as uint 0)) ;; bits representing which sections of the big level heap we use.
(let ((mem-mode (-> obj info memory-mode)))
(case mem-mode
(((load-buffer-mode borrow))
;; we need to find a level to borrow from.
;; borrowing is a two-way thing. the host level has to have our name.
(let ((slot-in-borrow-from-lev -1)) ;; the slot in the host
(dotimes (borrow-from-lev-idx LEVEL_MAX) ;; loop over all levels
(let ((maybe-borrow-from-lev (-> *level* level borrow-from-lev-idx)))
;; only can borrow from loaded level
(when (and (or (= (-> maybe-borrow-from-lev status) 'active) (= (-> maybe-borrow-from-lev status) 'loaded))
(begin
(dotimes (check-slot-idx 2) ;; check both borrow slots in the host
(when (and (= (-> maybe-borrow-from-lev info borrow-level check-slot-idx) (-> obj name)) ;; match name!
(nonzero? (-> maybe-borrow-from-lev info borrow-size check-slot-idx)) ;; has room!
)
(set! slot-in-borrow-from-lev check-slot-idx)
(set! found-borrow #t)
(goto cfg-20)
)
)
(set! found-borrow #f)
(label cfg-20)
(and found-borrow
(>= slot-in-borrow-from-lev 0)
(not (-> maybe-borrow-from-lev borrow-level slot-in-borrow-from-lev)) ;; nobody else using the slot (how?)
)
)
)
(set! borrow-from-lev maybe-borrow-from-lev) ;; success, found somebody to borrow from
(goto cfg-32)
)
)
)
(set! borrow-from-lev (the-as level #f))
(label cfg-32)
(cond
(borrow-from-lev
;; link to borrow level
(set! (-> obj borrow-from-level) borrow-from-lev)
(set! (-> borrow-from-lev borrow-level slot-in-borrow-from-lev) obj)
;; and copy the heap. seems kind of weird to copy the actual kheap object, but the host actually prepared
;; for this, so it should be fine.
(mem-copy!
(the-as pointer (-> obj heap))
(the-as pointer (-> borrow-from-lev borrow-heap slot-in-borrow-from-lev))
16
)
(start-debug "borrowing from ~A. heap:~%" borrow-from-lev)
(inspect (-> obj heap))
)
(else
;; couldn't find it, die.
(format 0 "ERROR: level ~A could not find free ~S bank in the level-group heap~%"
(-> obj name)
(enum->string load-buffer-mode mem-mode)
)
(break!)
0
)
)
)
)
(else
(start-debug "load-begin, no borrow~%")
(dotimes (i LEVEL_TOTAL)
(start-debug "lev ~8S bits #b~b~%"
(-> *level* level i name)
(-> *level* level i memory-mask))
)
;; not borrowing, we have to find our own memory.
;; there's a bit mask to indicate which sections of memory are used, with 6 bits.
;; large = 4 bits, medium = 3 bits, small = 2 bits.
;; note that the the "bits" are not exact sizes, so there is some code to fudge the boundaries a bit
;; depending on the layout - there are 6 bits, but the heap is divided into 146ths, and the actual
;; boundaries are set so the following combinations work:
;; the supported layouts are
;; large + small
;; small + large
;; medium + medium
;; small + medium
;; medium + small
;; small + small-center + small
;; note that small-center cannot exist at the same time as any medium/large.
;; helper function to check to see if a certain group of bits is unused.
(let* ((memory-unused? (lambda ((arg0 level-group) (arg1 int))
(dotimes (v1-0 LEVEL_TOTAL)
(if (logtest? (-> arg0 level v1-0 memory-mask) arg1)
(return #f)
)
)
#t
)
)
(offset-in-level-heap 0)
(heap-size (case mem-mode
(((load-buffer-mode large))
;; 96 pages. this uses up four of the six sections, meaning you can only have a small level alongside a large level.
;; because two of the sections are gonna be in the middle, there is actually space for 98 pages.
;; but it seems ndi did not notice that when writing this code.
(* LEVEL_PAGE_SIZE 96)
)
(((load-buffer-mode medium))
;; 73 pages. this uses up three of the six sections, one of them being a middle section
;; which is 1 page larger than non-middle sections. 24 + 24 + 25 = 73.
;; this means you can either have a medium or small level alongside this.
(* LEVEL_PAGE_SIZE 73)
)
(((load-buffer-mode small-center))
;; 50 pages. this uses up the two middle sections. 25 + 25 = 50.
;; this leaves two sections on each edge of the heap which are used by the small mode.
;; small-center + small + small is the only way to get 3 levels! (borrow levels excluded)
(* LEVEL_PAGE_SIZE 50)
)
(else
;; 48 pages. this uses up two sections that aren't in the middle. 24 + 24 = 48.
(* LEVEL_PAGE_SIZE 48)
)
)
)
)
(case mem-mode
(((load-buffer-mode large))
;; need 4 bits in the mask. first try lower 4
(when (memory-unused? *level* #b001111)
(set! bits-to-use #b1111)
(goto cfg-83)
)
;; nope, try upper 4.
(when (memory-unused? *level* #b111100)
(set! offset-in-level-heap (+ 24 24))
(set! bits-to-use #b111100)
(goto cfg-83)
)
)
(((load-buffer-mode medium))
;; need 3 bits in the mask.
;; like large, check both ends.
(when (memory-unused? *level* #b000111)
(set! bits-to-use #b000111)
(goto cfg-83)
)
(when (memory-unused? *level* #b111000)
(set! offset-in-level-heap (+ 24 24 25)) ;; weird sizing
(set! bits-to-use #b111000)
(goto cfg-83)
)
)
(((load-buffer-mode small-center))
;; only one place for us to go, in the center
(when (memory-unused? *level* #b001100)
(set! offset-in-level-heap (+ 24 24))
(set! bits-to-use #b001100)
(goto cfg-83)
)
)
(((load-buffer-mode small-edge))
;; check one side
(when (memory-unused? *level* #b000011)
(set! bits-to-use #b000011)
(goto cfg-83)
)
;; and the other
(when (memory-unused? *level* #b110000)
(set! offset-in-level-heap (+ 24 24 25 25))
(set! bits-to-use #b110000)
(goto cfg-83)
)
)
)
(set! bits-to-use 0)
(label cfg-83)
(cond
((zero? bits-to-use)
;; darn, couldn't find a spot.
(format 0 "ERROR: level ~A could not find free ~S bank in the level-group heap~%" (-> obj name) (enum->string load-buffer-mode mem-mode))
(dotimes (s5-1 LEVEL_TOTAL)
(if (!= (-> *level* level s5-1 status) 'inactive)
(format
0
"~Tlevel ~16S using bits #x~6,'0B~%"
(-> *level* level s5-1 name)
(-> *level* level s5-1 memory-mask)
)
)
)
#t
(break!)
0
)
(else
(start-debug "successfully found load: size #x~X, bits #x~X, offset ~D~%"
heap-size bits-to-use offset-in-level-heap)
;; found a spot, set mask.
(set! (-> obj memory-mask) (the-as uint bits-to-use))
(cond
;; are we using debug sized large level?
((= (&- (-> *level* heap top) (the-as uint (-> *level* heap base))) DEBUG_LEVEL_HEAP_SIZE)
;; if so, everything is bigger!
(let ((v1-44 (-> obj heap)))
(set! (-> v1-44 base) (&+ (-> *level* heap base) (* DEBUG_LEVEL_PAGE_SIZE offset-in-level-heap)))
(set! (-> v1-44 current) (-> v1-44 base))
;(set! (-> v1-44 top-base) (&+ (-> v1-44 base) (+ heap-size (/ heap-size 2))))
;; pc port note : modified the math here so we can just use a float to change the size
(set! (-> v1-44 top-base) (&+ (-> v1-44 base) (* DEBUG_LEVEL_PAGE_SIZE (/ heap-size LEVEL_PAGE_SIZE))))
(set! (-> v1-44 top) (-> v1-44 top-base))
)
)
(else
(let ((v1-45 (-> obj heap)))
;; no debug size heaps. set up our heap.
;; offset-in-level-heap is in 146ths (1 level heap page) of the total size.
(set! (-> v1-45 base) (&+ (-> *level* heap base) (* LEVEL_PAGE_SIZE offset-in-level-heap)))
(set! (-> v1-45 current) (-> v1-45 base))
(set! (-> v1-45 top-base) (&+ (-> v1-45 base) heap-size))
(set! (-> v1-45 top) (-> v1-45 top-base))
)
)
)
)
)
)
)
)
)
;; our heap is now set up, prepare for loading.
;; the global loading-level heap is used by many relocate/top-level code to allocate on the level heap
(set! loading-level (-> obj heap))
(set! (-> *level* loading-level) obj)
;; start linked list of types associated with this level
(set! (-> obj level-type) #f)
(set! *level-type-list* (the-as type (&-> obj level-type)))
;; clear stuff out
(set! (-> *level* log-in-level-bsp) #f)
(set! (-> obj nickname) #f)
(set! (-> obj bsp) #f)
(set! (-> obj entity) #f)
(set! (-> obj linking) #f)
(set! (-> obj task-mask) (-> *setting-control* user-current task-mask))
(vis-clear obj)
(set! (-> obj load-start-time) (-> *display* real-clock frame-counter))
(set! (-> obj load-stop-time) 0)
(set! (-> obj display-start-time) 0)
(set! (-> obj part-engine) #f)
(dotimes (v1-57 4)
(set! (-> obj user-object v1-57) #f)
)
;; go straight to loading
(set! (-> obj status) 'loading)
;; non-permanent allocator
(set! (-> *texture-pool* allocate-func) texture-page-level-allocate)
(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")
(set! (-> obj heap top) (-> obj heap top-base))
(set! (-> *level* load-level) (-> obj load-name))
(set! (-> *level* load-size) (the-as uint 0))
(set! (-> *level* load-time) 0.0)
(set! (-> *level* load-login-time) 0.0)
;; code comes first
(set! (-> obj code-memory-start) (-> obj heap current))
(cond
((= (-> obj info memory-mode) (load-buffer-mode borrow))
;; if we're borrowing, we should load directly to heap current.
;; this is somewhat strange, and has two drawbacks:
;; - we can't discard link data easily, like we would normally with the double buffer setup
;; - we can't allocate during login. Or if we allocate more than our link data, then bad things happen.
(set! (-> obj load-buffer-mode) (load-buffer-mode borrow))
(let ((a3-19 (logand -64 (&+ (-> obj heap current) 63))))
(start-debug "DGO-LOAD-BEGIN FOR BORROW: #x~x~%" a3-19)
;; start dgo loader!
(dgo-load-begin *temp-string* a3-19 a3-19 a3-19)
)
)
(else
;; normal loading into a new heap.
;; allocate the two dgo level load buffers on top, like normal
(let* ((s3-1 #x1b5800)
(s4-1 (kmalloc (-> obj heap) s3-1 (kmalloc-flags align-64 top) "dgo-level-buf-2"))
(s5-4 (kmalloc (-> obj heap) s3-1 (kmalloc-flags align-64 top) "dgo-level-buf-2"))
)
(format 0 "-----------> begin load ~A [~S]~%" (-> obj load-name) *temp-string*)
(set! (-> obj load-buffer 0) (the-as uint s5-4))
(set! (-> obj load-buffer 1) (the-as uint s4-1))
(set! (-> obj load-buffer-size) (the-as uint s3-1))
;; unclear why they do this, I guess it avoids the weird "medium" case in load-buffer-resize.
(set! (-> obj load-buffer-mode) (load-buffer-mode small-edge))
(start-debug "DGO-LOAD-BEGIN: #x~X #x~X #x~X~%" s5-4 s4-1 (logand -64 (&+ (-> obj heap current) 63)))
(dgo-load-begin *temp-string* s5-4 s4-1 (logand -64 (&+ (-> obj heap current) 63)))
)
)
)
obj
)
(defmethod login-begin level ((obj level))
"Begin login of a level after linking.
The login is spread over multiple frames."
;; link done, revert allocate-func back to "normal".
(set! (-> *texture-pool* allocate-func) texture-page-default-allocate)
(cond
((-> obj bsp)
(let ((s5-0 (-> obj bsp)))
(set! (-> s5-0 level tfrag-gs-test)
(if (logtest? (-> s5-0 texture-flags 0) (texture-page-flag alpha-enable))
(new 'static 'gs-test :ate #x1 :atst (gs-atest always) :zte #x1 :ztst (gs-ztest greater-equal))
(new 'static 'gs-test
:ate #x1
:atst (gs-atest greater-equal)
:aref #x26
:zte #x1
:ztst (gs-ztest greater-equal)
)
)
)
(set! (-> *level* log-in-level-bsp) (-> obj bsp))
(login-level-textures *texture-pool* obj (-> obj bsp texture-page-count) (-> obj bsp texture-ids))
(dotimes (v1-10 6)
(set! (-> obj sky-mask mask data v1-10) 0)
)
(dotimes (s4-0 10)
(let ((a0-8 (-> obj info texture-anim s4-0)))
(when a0-8
(set! (-> obj info texture-anim s4-0) #f)
(set! (-> obj texture-anim-array s4-0)
(init! (the-as texture-anim-array (-> a0-8 value)))
)
)
)
)
(build-masks s5-0)
)
(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
(level-status-update! obj 'inactive)
(set! loading-level global)
(set! (-> *level* loading-level) (-> *level* default-level))
(set! *level-type-list* (the-as type 0))
0
)
)
obj
)
(defun level-update-after-load ((lev level) (lstate login-state))
"Make progress on login.
Will set status to loaded when done."
(local-vars
(current-time int)
(end-time int)
(start-time int)
(sv-16 int)
(proto prototype-bucket-tie)
(geom-idx int)
)
;; in the pc port, lets just do all the login all at once for now.
(set! *level-index* (-> lev index))
0
(let ((drawable-trees (-> lev bsp drawable-trees)))
;; periodically, the code would jump back up here, see if it's been too long.
;; if so, it would return early.
;(.mfc0 start-time Count)
(label cfg-1)
;(.mfc0 current-time Count)
;(let ((v1-6 (- current-time start-time)))
; (when (< #x186a0 v1-6)
; (set! lev lev)
; (goto cfg-113)
; )
; )
(let ((login-state-pos (the-as int (-> lstate pos))))
;;;;;;;;;;;;;; STATE -1: first pass of tree login, art group login.
;; this pass adds drawable-inline-array-tfrag and drawable-tree-instance-tie's to
;; a list in lstate, logs in all other drawable-trees (fast), logs in all art groups,
;; and links all art.
(when (= (-> lstate state) -1)
;; STATE -1, part 1: drawable trees
(when (< login-state-pos (-> drawable-trees length))
(let ((current-tree (-> drawable-trees trees (the-as uint login-state-pos))))
(cond
((= (-> current-tree type) drawable-tree-tfrag)
;; for tfrags, iterate through all arrays
(dotimes (tree-array-idx (-> current-tree length))
(cond
;; for the actual tfrags, defer
((= (-> current-tree data tree-array-idx type) drawable-inline-array-tfrag)
(set! (-> lstate elt (-> lstate elts)) (-> current-tree data tree-array-idx))
(+! (-> lstate elts) 1)
)
(else
;; for the draw node arrays, just do them now (doesn't do anything, I think.)
(login (-> current-tree data tree-array-idx))
)
)
)
)
((= (-> current-tree type) drawable-tree-instance-tie)
;; instance-ties are deferred. This time, the whole thing is put off, including draw-node arrays
(set! (-> lstate elt (-> lstate elts)) current-tree)
(+! (-> lstate elts) 1)
)
(else
;; other trees are logged in hers.
(login current-tree)
)
)
)
;; on to the next tree. Check time
(+! (-> lstate pos) 1)
(goto cfg-1)
)
;; STATE -1, part 2: art gropus:
(let ((art-group-array-idx (- (the-as uint login-state-pos) (-> drawable-trees length))))
(when (< (the-as int art-group-array-idx) (-> lev art-group art-group-array length))
(let ((current-ag (-> lev art-group art-group-array art-group-array-idx)))
;; login and link. only janim's need linking.
(login current-ag)
(if (needs-link? current-ag)
(link-art! current-ag)
)
)
(+! (-> lstate pos) 1)
(goto cfg-1)
)
)
(set! (-> lstate pos) (the-as uint 0))
(set! (-> lstate state) 0)
(goto cfg-1)
)
;; next state is the arrays we put off from last state.
(when (< (-> lstate state) (the-as int (-> lstate elts)))
(let ((current-array (-> lstate elt (-> lstate state))))
(cond
((= (-> current-array type) drawable-inline-array-tfrag)
(set! *texture-masks-array* (-> lev bsp tfrag-masks))
(cond
((< login-state-pos (-> (the-as drawable-inline-array-tfrag current-array) length))
(dotimes (s2-2 200)
(when (< login-state-pos (-> (the-as drawable-inline-array-tfrag current-array) length))
(login (-> (the-as drawable-inline-array-tfrag current-array) data (the-as uint login-state-pos)))
(set! login-state-pos (the-as int (+ (the-as uint login-state-pos) 1)))
)
)
(set! (-> lstate pos) (the-as uint login-state-pos))
)
(else
(set! (-> lstate pos) (the-as uint 0))
(set! login-state-pos (+ (-> lstate state) 1))
(set! (-> lstate state) login-state-pos)
)
)
)
((= (-> current-array type) drawable-tree-instance-tie)
(let ((proto-array (-> (the-as drawable-tree-instance-tie current-array) prototypes prototype-array-tie)))
(let ((protos (-> (the-as drawable-tree-instance-tie current-array) prototypes)))
(when (< login-state-pos (-> proto-array length))
(set! sv-16 0)
(while (< sv-16 10)
(when (< login-state-pos (-> proto-array length))
(set! proto (-> proto-array array-data (the-as uint login-state-pos)))
(+! (-> protos prototype-max-qwc) 32)
(cond
((logtest? (-> proto flags) (prototype-flags tpage-alpha))
(set! *texture-masks* (-> *level* level *level-index* bsp alpha-masks data (-> proto texture-masks-index)))
)
((logtest? (-> proto flags) (prototype-flags tpage-water))
(set! *texture-masks* (-> *level* level *level-index* bsp water-masks data (-> proto texture-masks-index)))
)
(else
(set! *texture-masks* (-> *level* level *level-index* bsp tfrag-masks data (-> proto texture-masks-index)))
)
)
(when (and *debug-segment* (-> *screen-shot-work* highres-enable))
(dotimes (v1-105 4)
(set! (-> proto dists data v1-105) (+ 40960000.0 (-> proto dists data v1-105)))
(set! (-> proto rdists data v1-105) (/ 1.0 (-> proto dists data v1-105)))
)
)
(set! geom-idx 0)
(while (< geom-idx 4)
(let ((geom (-> proto tie-geom geom-idx)))
(when (nonzero? geom)
(+! (-> protos prototype-max-qwc) (* 7 (-> geom length)))
(login geom)
)
)
(set! geom-idx (+ geom-idx 1))
)
(set! login-state-pos (the-as int (+ (the-as uint login-state-pos) 1)))
)
(set! sv-16 (+ sv-16 1))
)
(set! (-> lstate pos) (the-as uint login-state-pos))
)
)
(when (= (the-as uint login-state-pos) (-> proto-array length))
(dotimes (proto2-idx (-> proto-array length))
(let ((proto2 (-> proto-array array-data proto2-idx)))
(cond
((logtest? (-> proto2 flags) (prototype-flags tpage-alpha))
(set! *texture-masks* (-> *level* level *level-index* bsp alpha-masks data (-> proto2 texture-masks-index)))
)
((logtest? (-> proto2 flags) (prototype-flags tpage-water))
(set! *texture-masks* (-> *level* level *level-index* bsp water-masks data (-> proto2 texture-masks-index)))
)
(else
(set! *texture-masks* (-> *level* level *level-index* bsp tfrag-masks data (-> proto2 texture-masks-index)))
)
)
(let ((envmap-shader (-> proto2 envmap-shader)))
(when (nonzero? envmap-shader)
(let ((envmap-tex (adgif-shader-login-no-remap envmap-shader)))
(when envmap-tex
(dotimes (v1-137 3)
(dotimes (a0-74 3)
(set! (-> (the-as (pointer int32) (+ (+ (* v1-137 16) (* a0-74 4)) (the-as int *texture-masks*))))
(logior (-> (the-as (pointer int32) (+ (* a0-74 4) (the-as int *texture-masks*) (* v1-137 16))) 0)
(-> (the-as (pointer int32) (+ (* a0-74 4) (the-as int envmap-tex) (* v1-137 16))) 15)
)
)
)
(set! (-> *texture-masks* data v1-137 mask w)
(the-as int (fmax (-> *texture-masks* data v1-137 dist) (-> envmap-tex masks data v1-137 dist)))
)
)
)
)
(set! (-> envmap-shader tex1) (new 'static 'gs-tex1 :mmag #x1 :mmin #x1))
(set! (-> envmap-shader clamp)
(new 'static 'gs-clamp :wms (gs-tex-wrap-mode clamp) :wmt (gs-tex-wrap-mode clamp))
)
(set! (-> envmap-shader alpha) (new 'static 'gs-alpha :b #x2 :c #x1 :d #x1))
(set! (-> envmap-shader prims 1) (gs-reg64 tex0-1))
(set! (-> envmap-shader prims 3) (gs-reg64 tex1-1))
(set! (-> envmap-shader prims 5) (gs-reg64 miptbp1-1))
(set! (-> envmap-shader clamp-reg) (gs-reg64 clamp-1))
(set! (-> envmap-shader prims 9) (gs-reg64 alpha-1))
)
)
)
)
(set! (-> lstate pos) (the-as uint 0))
(+! (-> lstate state) 1)
)
)
)
)
)
(goto cfg-1)
)
;; next is nav-meshes
(when (= (-> lstate state) (-> lstate elts))
(let ((lev-bsp (-> lev bsp)))
(cond
((or (zero? (-> lev-bsp nav-meshes)) (= (the-as uint login-state-pos) (-> lev-bsp nav-meshes length)))
(set! (-> lstate pos) (the-as uint 0))
(+! (-> lstate state) 1)
)
(else
(initialize-nav-mesh! (-> lev-bsp nav-meshes (the-as uint login-state-pos)))
(+! (-> lstate pos) 1)
)
)
)
(goto cfg-1)
)
(when (zero? (the-as uint login-state-pos))
(set! (-> lstate pos) (the-as uint 1))
(set! lev lev)
(goto cfg-113)
)
)
)
;; final!
;; name
(set! (-> lev nickname) (-> lev bsp nickname))
;; added: tombc has the wrong nickname in the bsp file...
(if (and (= (-> lev bsp name) 'tombc) (= (-> lev bsp nickname) 'toa))
(set! (-> lev nickname) 'toc)
)
;; subdivide distances
(let ((close-dist (-> lev bsp subdivide-close))
(far-dist (-> lev bsp subdivide-far))
)
(when (and (= close-dist 0.0) (= far-dist 0.0))
(set! close-dist 122880.0)
(set! far-dist 286720.0)
)
(set! (-> *subdivide-settings* close (-> lev index)) close-dist)
(set! (-> *subdivide-settings* far (-> lev index)) far-dist)
(set! (-> *subdivide-settings* close 7) close-dist)
(set! (-> *subdivide-settings* far 7) far-dist)
)
(when (and *debug-segment* (-> *screen-shot-work* highres-enable))
(set! (-> *subdivide-settings* close (-> lev index)) 40960000.0)
(set! (-> *subdivide-settings* far (-> lev index)) 41369600.0)
(set! (-> *subdivide-settings* close 7) 40960000.0)
(set! (-> *subdivide-settings* far 7) 41369600.0)
)
;; visibility info
(init-vis-from-bsp lev)
;; particle engines
(if (nonzero? (-> lev info part-engine-max))
(set! (-> lev part-engine)
(new 'loading-level 'engine 'sparticle-launcher (-> lev info part-engine-max) connection)
)
)
;; load other packages (used only for development, I think)
(load-required-packages lev)
;; mood setup
(clear-mood-context (-> lev mood-context))
(if (-> lev mood-init)
((-> lev mood-init) (-> lev mood-context))
)
;; if somebody will borrow from us, set aside some memory for them on the top of our heap
(dotimes (v1-211 2)
(set! (-> lev heap top-base)
;; MODIFIED
(the pointer (&- (-> lev heap top-base) (the uint (shl (the int (* BORROW_MULT (-> lev info borrow-size v1-211))) 10))))
)
(set! (-> lev heap top) (-> lev heap top-base))
(let ((borrower-heap (-> lev borrow-heap v1-211)))
(set! (-> borrower-heap base) (-> lev heap top))
(set! (-> borrower-heap current) (-> borrower-heap base))
;; MODIFIED
(set! (-> borrower-heap top-base) (&+ (-> borrower-heap base) (the int (shl (the int (* BORROW_MULT (-> lev info borrow-size v1-211))) 10))))
(set! (-> borrower-heap top) (-> borrower-heap top-base))
)
)
;; end the load
(set! (-> lev draw-priority) (-> lev info draw-priority))
(set! (-> lev status) 'loaded)
(mark-hud-warp-sprite-dirty *texture-pool*)
(set! loading-level global)
(set! (-> *level* loading-level) (-> *level* default-level))
(set! *level-type-list* (the-as type 0))
(set! (-> *level* log-in-level-bsp) #f)
(set! (-> lev load-stop-time) (-> *display* real-clock frame-counter))
0
(.mfc0 end-time Count)
(- end-time start-time)
(set! (-> *level* load-login-time)
(* 0.016666668 (the float (- (-> *display* real-clock integral-frame-counter) (the-as uint *dgo-time*))))
)
(label cfg-113)
lev
)
(defmethod birth level ((obj level))
"Start running code for a level that has been loaded."
(local-vars (sv-96 int))
(case (-> obj status)
(('loaded)
(let ((s5-0 loading-level)
(s4-0 (-> *level* loading-level))
(s3-0 (-> *level* log-in-level-bsp))
(s2-1 *level-type-list*)
)
(let ((s1-0 (not (-> obj entity))))
(set! loading-level (-> obj heap))
(set! (-> *level* log-in-level-bsp) (-> obj bsp))
(set! (-> *level* loading-level) obj)
(set! *level-type-list* (the-as type (&-> obj level-type)))
(cond
((valid? (-> obj bsp light-hash) light-hash (the-as string #f) #t 0)
(set! (-> obj light-hash) (-> obj bsp light-hash))
)
(else
(set! (-> obj light-hash) (the-as light-hash 0))
0
)
)
(birth (-> obj bsp))
(set! (-> obj status) 'alive)
(set! (-> obj render?) #t)
(copy-perms-to-level! *game-info* obj)
(send-event *camera* 'level-activate (-> obj name))
(send-event *target* 'level-activate (-> obj name))
(when (and (-> obj info login-func) s1-0)
(let ((s1-1 (-> obj info login-func value)))
(if (and s1-1 (nonzero? s1-1) (type? s1-1 function))
((the (function level none) s1-1) obj)
)
)
)
)
(let ((s1-2 (-> obj status)))
(set! (-> obj status) 'active)
(update-task-masks 'level)
(assign-draw-indices *level*)
(let ((s0-0 (-> obj bsp nav-meshes)))
(when (nonzero? s0-0)
(set! sv-96 0)
(while (< sv-96 (-> s0-0 length))
(birth! (-> s0-0 sv-96))
(set! sv-96 (+ sv-96 1))
)
)
)
(if (and (!= (-> obj bsp city-level-info) 0) *traffic-manager*)
(send-event *traffic-manager* 'level-loaded obj)
)
(when (-> obj info activate-func)
(let ((s0-1 (-> obj info activate-func value)))
(if (and s0-1 (nonzero? s0-1) (type? s0-1 function))
((the (function level symbol none) s0-1) obj 'display)
)
)
)
(set! (-> obj status) s1-2)
)
(set! loading-level s5-0)
(set! (-> *level* loading-level) s4-0)
(set! (-> *level* log-in-level-bsp) s3-0)
(set! *level-type-list* s2-1)
)
)
)
obj
)
(defmethod deactivate level ((obj level))
"Take a level out of active/alive"
(case (-> obj status)
(('active 'alive)
(format 0 "----------- kill ~A (status ~A)~%" obj (-> obj status))
;; send event to traffic manager.
(if (and (!= (-> obj bsp city-level-info) 0) *traffic-manager*)
(send-event *traffic-manager* 'level-killed obj)
)
;; run kill callbacks
(when (-> obj info kill-func)
(let ((s5-0 (-> obj info kill-func value)))
(if (and s5-0 (nonzero? s5-0) (type? s5-0 function))
((the (function level none) s5-0) obj)
)
)
)
;; copy data from entities to permanent storage
(copy-perms-from-level! *game-info* obj)
;; tell target
(send-event *target* 'level-deactivate (-> obj name))
;; remove from background draw system
(remove-by-param1 *background-draw-engine* (the-as int (-> obj bsp)))
;; kill entities, particles, anims
(deactivate-entities (-> obj bsp))
(kill-all-particles-in-level obj)
(unload-from-level *anim-manager* obj)
;; reset status
(set! (-> obj inside-boxes) #f)
(set! (-> obj meta-inside?) #f)
(set! (-> obj force-inside?) #f)
(set! (-> obj status) 'loaded)
(set! (-> obj light-hash) (the-as light-hash 0))
(set! (-> obj all-visible?) 'loading)
;; clear vis.
(dotimes (v1-34 128)
(set! (-> (the-as (pointer int128) (&+ (-> obj vis-bits) (* v1-34 16)))) (the int128 0))
)
(countdown (v1-37 8)
(let ((a0-20 (-> obj vis-info v1-37)))
(if a0-20
(set! (-> a0-20 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))
"Unload a level."
;; make sure it's not alive/active
(deactivate obj)
(when (!= (-> obj status) 'inactive)
;; first, unload anybody who borrows from us.
(dotimes (s5-0 2)
(when (-> obj borrow-level s5-0)
(unload! (-> obj borrow-level s5-0))
(set! (-> obj borrow-level s5-0) #f)
)
)
;; if we borrow from somebody, remove ourselves from them
(when (-> obj borrow-from-level)
(dotimes (v1-19 2)
(if (= obj (-> obj borrow-from-level borrow-level v1-19))
(set! (-> obj borrow-from-level borrow-level v1-19) #f)
)
)
(set! (-> obj borrow-from-level) #f)
)
(case (-> obj status)
(('loading 'loading-bt)
;; kill the linker if we're mid link.
(if (nonzero? link-reset)
(link-reset)
)
)
(('alive 'active 'loaded)
;; run deactivate func.
(when (-> obj info deactivate-func)
(let ((s5-1 (-> obj info deactivate-func value)))
(if (and s5-1 (nonzero? s5-1) (type? s5-1 function))
((the (function level none) s5-1) obj)
)
)
)
)
)
;; unlink art groups.
(when (or (= (-> obj status) 'loaded)
(= (-> obj status) 'alive)
(= (-> obj status) 'active)
(= (-> obj status) 'login)
)
(dotimes (s5-2 (-> obj art-group art-group-array length))
(let ((s4-0 (-> obj art-group art-group-array s5-2)))
(if (needs-link? s4-0)
(unlink-art! s4-0)
)
)
)
)
(set! (-> obj bsp) #f)
(set! (-> obj entity) #f)
(set! (-> obj status) 'inactive)
(set! (-> obj linking) #f)
(set! (-> obj art-group string-array length) 0)
(set! (-> obj art-group art-group-array length) 0)
(set! (-> obj mem-usage-block) (the-as memory-usage-block 0))
(set! (-> obj mem-usage) 0)
(set! (-> obj part-engine) #f)
(dotimes (v1-60 4)
(set! (-> obj user-object v1-60) #f)
)
;; kill texture anims
(let ((v1-63 (-> obj status)))
(when (or (= v1-63 'alive) (or (= v1-63 'active) (= v1-63 'loaded)))
(dotimes (s5-3 10)
(let ((a0-37 (-> obj info texture-anim s5-3)))
(if a0-37
(set! (-> obj texture-anim-array s5-3)
(clear! (the-as texture-anim-array (-> a0-37 value)))
)
)
)
)
)
)
(dotimes (v1-73 10)
(set! (-> obj texture-anim-array v1-73) #f)
)
(countdown (s5-4 (-> obj loaded-texture-page-count))
(dotimes (v1-76 32)
(when (= (-> obj loaded-texture-page s5-4) (-> *texture-pool* common-page v1-76))
(set! (-> *texture-pool* common-page v1-76) (the-as texture-page 0))
0
)
)
(unload-page *texture-pool* (-> obj loaded-texture-page s5-4))
)
(set! (-> obj loaded-texture-page-count) 0)
(unlink-shaders-in-heap *texture-page-dir* (-> obj heap))
(unlink-part-group-by-heap (-> obj heap))
(unlink-lightning-spec-by-heap (-> obj heap))
(particle-adgif-cache-flush)
(set! (-> obj loaded-text-info-count) 0)
(dotimes (s5-5 2)
(let ((v1-90 (-> *art-control* buffer s5-5 pending-load-file)))
(if (and (>= (the-as int v1-90) (the-as int (-> obj heap base)))
(< (the-as int v1-90) (the-as int (-> obj heap top-base)))
)
(set-pending-file (-> *art-control* buffer s5-5) (the-as string #f) -1 (the-as handle #f) 100000000.0)
)
)
)
(let ((v1-100 (-> *game-info* sub-task-list)))
(dotimes (a0-59 (-> v1-100 length))
(when (nonzero? a0-59)
(let ((a1-20 (-> v1-100 a0-59)))
(when (and (-> a1-20 info) (= (-> a1-20 info level) (-> obj name)))
(countdown (a2-6 7)
(set! (-> a1-20 info hooks a2-6) #f)
)
)
)
)
)
)
(let ((v1-103 0)
(a0-60 0)
(a1-23 (-> obj level-type))
)
(while a1-23
(+! a0-60 1)
(+! v1-103 (-> a1-23 psize))
;; PC port note : added this call to kill entities using level types that are being unloaded because of bad entity placement
(kill-by-type a1-23 *active-pool*)
(set! (-> a1-23 symbol value) (the-as object 0))
(set! a1-23 (the-as type (-> a1-23 method-table 8)))
)
)
(let* ((s5-6 (-> obj info packages))
(a0-61 (car s5-6))
)
(while (not (null? s5-6))
(case (rtype-of a0-61)
((symbol)
(unload (symbol->string (the-as symbol a0-61)))
)
((string)
(unload (the-as string a0-61))
)
)
(set! s5-6 (cdr s5-6))
(set! a0-61 (car s5-6))
)
)
(vis-clear obj)
(let ((v1-120 (-> obj heap)))
(set! (-> v1-120 current) (-> v1-120 base))
)
(set! (-> obj memory-mask) (the-as uint 0))
(set! (-> obj code-memory-start) (the-as pointer 0))
(set! (-> obj code-memory-end) (the-as pointer 0))
(set! (-> obj level-type) #f)
(when (= (-> *level* loading-level) obj)
(set! loading-level global)
(set! (-> *level* loading-level) (-> *level* default-level))
(set! (-> *level* log-in-level-bsp) #f)
(set! *level-type-list* (the-as type 0))
0
)
(assign-draw-indices *level*)
)
obj
)
(defmethod is-object-visible? level ((obj level) (arg0 int))
"Is drawable arg0 visible? Note that this will return #f if the visibility data is not loaded."
;; 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 inside-boxes-check level ((obj level) (arg0 vector))
"NOTE: this function used to check if we were in boxes - here it just checks
a flag. However, it is still used to set the inside-boxes field, so it keeps
the name we gave it in Jak 1.
The jak 2 behavior is that any loaded level (with a bsp) is considered 'in-boxes'
except for if the require-force-inside flag is set in the bsp-header, in which case
it requires the level to be marked as force-inside?"
(cond
((not (-> obj bsp))
#f
)
((-> obj force-inside?)
#t
)
(else
(zero? (-> obj bsp cam-outside-bsp))
)
)
)
(defmethod debug-print-region-splitbox level ((obj level) (arg0 vector) (arg1 object))
"Display debug info about the regions of a level."
(cond
((or (not (-> obj bsp)) (zero? (-> obj bsp region-tree)))
)
((nonzero? (-> obj bsp region-tree))
(debug-print (-> obj bsp region-tree) arg0 arg1)
)
)
0
(none)
)
(defmethod mem-usage level ((obj level) (arg0 memory-usage-block) (arg1 int))
"Compute the memory usage of a level."
(when (= (-> obj status) 'active)
(set! (-> arg0 length) (max 67 (-> arg0 length)))
(set! (-> arg0 data 66 name) "entity-links")
(+! (-> arg0 data 66 count) (-> obj entity length))
(let ((v1-8 (asize-of (-> obj entity))))
(+! (-> arg0 data 66 used) v1-8)
(+! (-> arg0 data 66 total) (logand -16 (+ v1-8 15)))
)
(mem-usage (-> obj art-group) arg0 arg1)
(set! (-> arg0 length) (max 66 (-> arg0 length)))
(set! (-> arg0 data 65 name) "level-code")
(+! (-> arg0 data 65 count) 1)
(let ((v1-20 (&- (-> obj code-memory-end) (the-as uint (-> obj code-memory-start)))))
(+! (-> arg0 data 65 used) v1-20)
(+! (-> arg0 data 65 total) (logand -16 (+ v1-20 15)))
)
(countdown (s3-0 (-> obj loaded-texture-page-count))
(mem-usage (-> obj loaded-texture-page s3-0) arg0 arg1)
)
(countdown (s3-1 (-> obj loaded-text-info-count))
(mem-usage (-> obj loaded-text-info s3-1) arg0 arg1)
)
(countdown (s3-2 8)
(let ((s2-0 (-> obj vis-info s3-2)))
(when s2-0
(cond
((zero? s3-2)
(set! (-> arg0 length) (max 62 (-> arg0 length)))
(set! (-> arg0 data 61 name) "bsp-leaf-vis-self")
(+! (-> arg0 data 61 count) 1)
(let ((v1-47 (+ (asize-of s2-0) (-> s2-0 allocated-length))))
(+! (-> arg0 data 61 used) v1-47)
(+! (-> arg0 data 61 total) (logand -16 (+ v1-47 15)))
)
)
(else
(set! (-> arg0 length) (max 63 (-> arg0 length)))
(set! (-> arg0 data 62 name) "bsp-leaf-vis-adj")
(+! (-> arg0 data 62 count) 1)
(let ((v1-58 (+ (asize-of s2-0) (-> s2-0 allocated-length))))
(+! (-> arg0 data 62 used) v1-58)
(+! (-> arg0 data 62 total) (logand -16 (+ v1-58 15)))
)
)
)
)
)
)
;; most of this is in the bsp:
(mem-usage (-> obj bsp) arg0 arg1)
)
obj
)
(defmethod alloc-levels-if-needed level-group ((obj level-group) (arg0 symbol))
"Setup for playing levels by loading the required base packages (art, common)
and allocating the level heap."
(when (zero? (-> *level* heap base))
(start-debug "level one-time setup~%")
(kmemopen global "level-heaps")
(when (nmember "game" *kernel-packages*)
(start-debug "game already loaded, provides art/common~%")
(set! *kernel-packages* (cons "art" *kernel-packages*))
(set! *kernel-packages* (cons "common" *kernel-packages*))
)
(load-package "art" global)
(if arg0
(load-package "common" global)
)
(let ((s5-1 (if (and arg0 (not *debug-segment*))
(#if PC_PORT DEBUG_LEVEL_HEAP_SIZE LEVEL_HEAP_SIZE)
DEBUG_LEVEL_HEAP_SIZE
)
)
(gp-1 (-> obj heap))
)
(start-debug "about to allocate level heap with size #x~X (~f MB)~%" s5-1 (/ (the float s5-1) 1024.))
(set! (-> gp-1 base) (kmalloc global s5-1 (kmalloc-flags) "heap"))
(set! (-> gp-1 current) (-> gp-1 base))
(set! (-> gp-1 top-base) (&+ (-> gp-1 base) s5-1))
(set! (-> gp-1 top) (-> gp-1 top-base))
)
(kmemclose)
)
0
(none)
)
(defmethod level-get-with-status level-group ((obj level-group) (arg0 symbol))
"Get a level with the given status."
(dotimes (v1-0 (-> obj length))
(if (= (-> obj level v1-0 status) arg0)
(return (-> obj level v1-0))
)
)
(the-as level #f)
)
(defmethod level-get-most-disposable level-group ((obj level-group))
"Get the level that's least useful."
(dotimes (v1-0 (-> obj length))
(case (-> obj level v1-0 status)
(('inactive)
(return (-> obj level v1-0))
)
)
)
(dotimes (v1-6 (-> obj length))
(case (-> obj level v1-6 status)
(('loading 'loading-bt)
(return (-> obj level v1-6))
)
)
)
(dotimes (v1-12 (-> obj length))
(case (-> obj level v1-12 status)
(('loaded)
(return (-> obj level v1-12))
)
)
)
(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) (arg0 symbol))
"Get a level by name or load-name"
(dotimes (v1-0 (-> obj length))
(if (and (!= (-> obj level v1-0 status) 'inactive)
(or (= (-> obj level v1-0 name) arg0) (= (-> obj level v1-0 load-name) arg0))
)
(return (-> obj level v1-0))
)
)
(the-as level #f)
)
(defmethod art-group-get-by-name level-group ((obj level-group) (arg0 string) (arg1 (pointer uint32)))
"Search all levels for an art-group. Return the art group, or #f. Optionally return the level index."
(countdown (s4-0 LEVEL_TOTAL)
(let ((s3-0 (-> *level* level s4-0)))
(when (or (= (-> s3-0 status) 'active) (= (-> s3-0 status) 'reserved))
(countdown (s2-0 (-> s3-0 art-group art-group-array length))
(when (name= (-> s3-0 art-group art-group-array s2-0 name) arg0)
(if arg1
(set! (-> arg1 0) (the-as uint s3-0))
)
(return (-> s3-0 art-group art-group-array s2-0))
)
)
)
)
)
(the-as art-group #f)
)
(defmethod activate-levels! level-group ((obj level-group))
"Set all levels to active."
(dotimes (s5-0 (-> obj length))
(level-status-update! (-> obj level s5-0) 'active)
)
0
)
(defmethod level-get-target-inside level-group ((obj level-group))
"Get the level that target is 'in'. With a bunch of tricks for what 'in' really means."
(let ((s5-0 (target-pos 0)))
;; first, try the level that we want for visibility data.
;; this is the most 'in' level.
(let ((v1-1 (-> *load-state* vis-nick)))
(when v1-1
(dotimes (a0-3 (-> obj length))
(let ((a1-3 (-> obj level a0-3)))
(when (= (-> a1-3 status) 'active)
(if (= (-> a1-3 name) v1-1)
(return a1-3)
)
)
)
)
)
)
;; next, try the level for the continue point.
(let ((v1-5 (-> *game-info* current-continue level)))
(dotimes (a0-5 (-> obj length))
(let ((a1-8 (-> obj level a0-5)))
(when (= (-> a1-8 status) 'active)
(if (= (-> a1-8 name) v1-5)
(return a1-8)
)
)
)
)
)
;; next, try using bounding spheres to find the closest.
;; (note that this is slightly broken, f30-0 is never updated)
(let ((s4-0 (the-as level #f)))
(let ((f30-0 0.0))
(dotimes (s3-0 (-> obj length))
(let ((s2-0 (-> obj level s3-0)))
(when (= (-> s2-0 status) 'active)
(let ((f0-0 (vector-vector-distance (-> s2-0 bsp bsphere) s5-0)))
(if (and (-> s2-0 inside-boxes) (or (not s4-0) (< f0-0 f30-0)))
(set! s4-0 s2-0)
)
)
)
)
)
)
(if s4-0
(return s4-0)
)
)
)
;; if all that failed, try any with the meta-inside? flag.
(dotimes (v1-23 (-> obj length))
(let ((a0-11 (-> obj level v1-23)))
(when (= (-> a0-11 status) 'active)
(if (-> a0-11 meta-inside?)
(return a0-11)
)
)
)
)
;; if that still didn't work, return any active level.
(let ((v0-1 (the-as level #f)))
0.0
(dotimes (v1-26 (-> obj length))
(let ((a0-16 (-> obj level v1-26)))
(when (= (-> a0-16 status) 'active)
(if (not v0-1)
(set! v0-1 a0-16)
)
)
)
)
v0-1
)
)
(defmethod load-commands-set! level-group ((obj level-group) (arg0 pair))
"Set the load-commands of a level."
(set! (-> obj load-commands) arg0)
(none)
)
(defmethod mem-usage level-group ((obj level-group) (arg0 memory-usage-block) (arg1 int))
"Compute mem-usage for an entire level-group."
(dotimes (s3-0 (-> obj length))
(mem-usage (-> obj level s3-0) arg0 arg1)
)
obj
)
(defun bg ((arg0 symbol))
"Begin playing a level. Works with or without dproc running (won't start it)."
;; enable cheat-mode if debugging
(set! *cheat-mode* (if *debug-segment*
'debug
#f
)
)
(let ((v1-2 (lookup-level-info arg0)))
(cond
((= (-> v1-2 visname) arg0) ;; we used a visname, enable vis!
(set! (-> *level* vis?) #t)
(set! arg0 (-> v1-2 name)) ;; and use the normal name for loading.
)
(else
;; otherwise disable vis, low memory warnings.
(set! (-> *level* vis?) #f)
(set! (-> *kernel-context* low-memory-message) #f)
)
)
;; disable borrow mode, as we might not have anybody to borrow from.
(case (-> v1-2 memory-mode)
(((load-buffer-mode borrow))
(set! (-> v1-2 memory-mode) (load-buffer-mode small-edge))
0
)
)
;; load all required packages
(let* ((s5-0 (-> v1-2 run-packages))
(a0-11 (car s5-0))
)
(while (not (null? s5-0))
(case (rtype-of a0-11)
((symbol)
(load-package (symbol->string (the-as symbol a0-11)) global)
)
((string)
(load-package (the-as string a0-11) global)
)
)
(set! s5-0 (cdr s5-0))
(set! a0-11 (car s5-0))
)
)
)
;; start the load!
(let ((gp-1 (level-get-for-use *level* arg0 'active)))
;; if dproc isn't running, run the load here...
(while (and gp-1
(or (= (-> gp-1 status) 'loading) (= (-> gp-1 status) 'loading-bt) (= (-> gp-1 status) 'login))
(not *dproc*)
)
(load-continue gp-1)
)
;; otherwise, set up the load-state. level-update will be called from dproc, which will read this and load it.
(reset! *load-state*)
(set! (-> *load-state* vis-nick) (-> gp-1 name))
(set! (-> *load-state* want 0 name) (-> gp-1 name))
(set! (-> *load-state* want 0 display?) 'display)
;; load the first continue point
(if (-> gp-1 info continues)
(set-continue! *game-info* (the-as basic (car (-> gp-1 info continues))) #f)
)
)
(dotimes (v1-37 3)
(set! (-> *load-state* want-sound v1-37) (-> *game-info* current-continue want-sound v1-37))
)
;; also try to load borrow level
(add-borrow-levels *load-state*)
;; if we loaded, activate now.
(activate-levels! *level*)
(set! *print-login* #f)
(set! (-> *time-of-day-context* mode) (time-of-day-palette-id unk3))
0
(none)
)
(defun play ((arg0 symbol) (arg1 symbol))
"Set up the game engine for playing."
(kmemopen global "level-boot")
(when *kernel-boot-level*
(start-debug "using *kernel-boot-level*: ~A~%" *kernel-boot-level*)
(bg *kernel-boot-level*)
(on #f)
(kmemclose)
(kmemclose)
(return 0)
)
(let* ((v1-3 *kernel-boot-message*)
(s5-0 (cond
((or (= v1-3 'demo) (= v1-3 'demo-shared))
'demo
)
(*debug-segment*
'prison
)
(else
'title
)
)
)
)
(start-debug "PLAY: kernel-boot-message is: ~A, startup level is ~A~%" v1-3 s5-0)
(stop 'play)
(set! (-> *level* vis?) arg0)
(set! (-> *level* want-level) #f)
(set! (-> *level* border?) #t)
(set! (-> *setting-control* user-default border-mode) #t)
(set! (-> *level* play?) #t)
(start-debug "PLAY: allocating levels~%")
(alloc-levels-if-needed *level* #t)
(start-debug "PLAY: global heap after level alloc:~%")
(inspect global)
(set! *display-profile* #f)
(set! *cheat-mode* (if *debug-segment*
'debug
#f
)
)
(set! *time-of-day-fast* #f)
(load-commands-set! *level* '())
(send-event (ppointer->process *time-of-day*) 'change 'ratio #x3f800000)
(send-event (ppointer->process *time-of-day*) 'change 'hour 7)
(send-event (ppointer->process *time-of-day*) 'change 'minutes 0)
(send-event (ppointer->process *time-of-day*) 'change 'seconds 0)
(send-event (ppointer->process *time-of-day*) 'change 'frames 0)
(set! (-> *time-of-day-context* mode) (time-of-day-palette-id unk3))
(set! (-> *mood-control* overide-weather-flag) #f)
(set-blackout-frames (seconds 0.02))
(when (not *dproc*)
(reset! *load-state*)
(let ((s4-1 (level-get-for-use *level* s5-0 'active)))
(let ((a1-11 (new 'stack-no-clear 'array 'symbol 10)))
(set! (-> a1-11 5) #f)
(set! (-> a1-11 4) #f)
(set! (-> a1-11 3) #f)
(set! (-> a1-11 2) #f)
(set! (-> a1-11 1) (if (= s5-0 'ctysluma)
'ctywide
)
)
(set! (-> a1-11 0) s5-0)
(start-debug "setting load-state want-levels~%")
(want-levels *load-state* a1-11)
)
(start-debug "setting load-state want-display-level~%")
(want-display-level *load-state* s5-0 'display)
(if (= s5-0 'ctysluma)
(want-display-level *load-state* 'ctywide 'display)
)
(start-debug "setting load-state want-vis-level~%")
(want-vis-level *load-state* s5-0)
(while (and s4-1 (or (= (-> s4-1 status) 'loading) (= (-> s4-1 status) 'loading-bt) (= (-> s4-1 status) 'login)))
(set-blackout-frames (seconds 0.02))
(load-continue s4-1)
)
)
)
(set! *print-login* #f)
(level-status-update! (level-get *level* s5-0) 'active)
)
(start-debug "PLAY: starting dproc~%")
(on #t)
(if arg1
(initialize! *game-info* 'game (the-as game-save #f) (the-as string #f))
)
(kmemclose)
(kmemclose)
0
)
(defun play-boot ()
"Entry point from C to initialize game for running.
This simply calls (play #t #t) in a GOAL thread."
(start-debug "play-boot about to switch stacks for calling play...~%")
(process-spawn-function
process
(lambda () (play #t #t) (none))
:from *4k-dead-pool*
:stack *kernel-dram-stack*
)
0
(none)
)
(defun update-sound-banks ()
"Load sound banks as needed."
(local-vars (v1-21 level-load-info) (v1-28 level-load-info) (a0-24 symbol))
(if (or (nonzero? (rpc-busy? 1))
(nonzero? (rpc-busy? 3))
(load-in-progress? *level*)
(not (-> *setting-control* user-current sound-bank-load))
)
(return 0)
)
(let ((gp-0 (new 'static 'boxed-array :type symbol :length 0 :allocated-length 3)))
(set! (-> gp-0 length) 3)
(dotimes (s5-0 3)
(let ((s4-0 (the-as object (-> *load-state* want-sound s5-0))))
(let ((v1-13 (and (not (null? (-> *setting-control* user-current extra-bank)))
(-> *setting-control* user-current extra-bank)
)
)
)
(when v1-13
(let ((a0-7 (car v1-13)))
(while (not (null? v1-13))
(cond
((and (= s5-0 2) (= (car a0-7) 'force2))
(set! s4-0 (car (cdr a0-7)))
)
((= (car a0-7) s4-0)
(set! s4-0 (car (cdr a0-7)))
)
)
(set! v1-13 (cdr v1-13))
(set! a0-7 (car (the-as pair v1-13)))
)
)
)
)
(let ((v1-19 (and (-> ctywide borrow-level 0)
(begin (set! v1-21 (lookup-level-info (-> ctywide borrow-level 0))) v1-21)
(-> v1-21 extra-sound-bank)
)
)
)
(when v1-19
(let ((a0-14 (car v1-19)))
(while (not (null? v1-19))
(if (= (car a0-14) s4-0)
(set! s4-0 (car (cdr a0-14)))
)
(set! v1-19 (cdr v1-19))
(set! a0-14 (car (the-as pair v1-19)))
)
)
)
)
(let ((v1-26 (and (-> ctywide borrow-level 1)
(begin (set! v1-28 (lookup-level-info (-> ctywide borrow-level 1))) v1-28)
(-> v1-28 extra-sound-bank)
)
)
)
(when v1-26
(let ((a0-19 (car v1-26)))
(while (not (null? v1-26))
(if (= (car a0-19) s4-0)
(set! s4-0 (car (cdr a0-19)))
)
(set! v1-26 (cdr v1-26))
(set! a0-19 (car (the-as pair v1-26)))
)
)
)
)
(set! (-> gp-0 s5-0) (the-as symbol s4-0))
)
)
(dotimes (v1-35 3)
(let ((s5-1 (-> gp-0 v1-35)))
(set! a0-24 (and s5-1 (begin
(dotimes (a0-25 3)
(when (= s5-1 (-> *level* sound-bank a0-25))
(set! a0-24 #f)
(goto cfg-63)
)
)
#t
)
)
)
(label cfg-63)
(when a0-24
(let ((s4-1 -1))
(dotimes (a0-28 3)
(when (not (-> *level* sound-bank a0-28))
(set! s4-1 a0-28)
(goto cfg-81)
)
)
(dotimes (s3-0 3)
(countdown (a0-32 3)
(if (= (-> gp-0 a0-32) (-> *level* sound-bank s3-0))
(goto cfg-78)
)
)
(format 0 "Unload soundbank ~A from slot ~D (want ~A)~%" (-> *level* sound-bank s3-0) s3-0 gp-0)
(sound-bank-unload (string->sound-name (symbol->string (-> *level* sound-bank s3-0))))
(set! (-> *level* sound-bank s3-0) #f)
(return 0)
(label cfg-78)
)
(label cfg-81)
(when (>= s4-1 0)
(format 0 "Load soundbank ~A in slot ~D (want ~A)~%" s5-1 s4-1 gp-0)
(sound-bank-load (string->sound-name (symbol->string s5-1)))
(set! (-> *level* sound-bank s4-1) (the-as basic s5-1))
(return 0)
)
)
)
)
)
)
0
)
(defmethod update! load-state ((obj load-state))
"Update level stuff based on load state.
This does scary transitions."
(local-vars (all-levels-inactive symbol))
(let ((discarded-level #f)) ;; set if we end up unloading anything.
;; First, discard levels. We'll discard levels that are no longer wanted, in reverse load order
(let ((most-recent-load-order 0))
-1
;; unload up to 6 levels, so try 6 times
(countdown (unload-attempt LEVEL_MAX)
(let ((unload-idx -1)) ;; which is best to unload
;; try all six, to find the best to unload
(countdown (unload-candidate-idx LEVEL_MAX)
(let ((unload-candidate-lev (-> *level* level unload-candidate-idx)))
(when (and (!= (-> unload-candidate-lev status) 'inactive) ;; in use
(>= (the-as uint (-> unload-candidate-lev load-order)) (the-as uint most-recent-load-order)) ;; newer than best
)
;; check if still wanted
(let ((still-wanted #f))
(dotimes (t0-2 LEVEL_MAX)
(if (= (-> unload-candidate-lev name) (-> obj want t0-2 name))
(set! still-wanted #t)
)
)
(when (not still-wanted)
;; not wanted, and best so far, remember.
(set! most-recent-load-order (-> unload-candidate-lev load-order))
(set! unload-idx unload-candidate-idx)
)
)
)
)
)
;; did we find one to unload?
;; PC NOTE : added an extra check for DGO time. If you start a load and discard it on the next frame,
;; you may attempt to start a new load right away before the ISO thread can properly stop the previous load
;; which will just crash the game. Sadly this means loads may sometimes be delayed by one frame. The horror.
(when ;(>= unload-idx 0)
(and (>= unload-idx 0) (< 1 (- (-> *display* real-clock integral-frame-counter) *dgo-time*)))
(let ((lev-to-unload (-> *level* level unload-idx)))
(format 0 "Discarding level ~A~%" (-> lev-to-unload name))
(level-status-update! lev-to-unload 'inactive) ;; kill it.
)
(set! discarded-level #t)
)
)
)
)
;; next, start loads
(let ((no-levels-at-all #f))
;; see if all levels inactive
(countdown (a0-9 LEVEL_MAX)
(when (!= (-> *level* level a0-9 status) 'inactive)
(set! all-levels-inactive #f)
(goto cfg-23)
)
)
(set! all-levels-inactive #t)
(label cfg-23)
(if all-levels-inactive
(set! no-levels-at-all #t) ;; weird macro or something.
)
(if discarded-level ;; if we discarded stuff on this frame, don't also start a load
(return 0)
)
;; build array of desired levels that we might want to load
(let ((desired-levels (new 'static 'boxed-array :type symbol :length 0 :allocated-length LEVEL_MAX)))
(countdown (a0-14 LEVEL_MAX)
(set! (-> desired-levels a0-14) #f)
)
(dotimes (want-lev-idx LEVEL_MAX) ;; loop over wants
(when (-> obj want want-lev-idx name)
(set! (-> desired-levels want-lev-idx) (-> obj want want-lev-idx name))
;; check if this wanted level is already present, in any state.
(dotimes (a1-17 LEVEL_MAX)
(let ((a2-13 (-> *level* level a1-17)))
(if (and (!= (-> a2-13 status) 'inactive) (= (-> a2-13 name) (-> obj want want-lev-idx name)))
(set! (-> desired-levels want-lev-idx) #f) ;; it's already there, not candidate for load start
)
)
)
)
)
;; find the first level in the possible load array that's not #f (nothing, or already assigned to a level)
(let ((want-lev-idx-to-load -1))
(dotimes (a0-20 LEVEL_MAX)
(when (-> desired-levels a0-20)
(set! want-lev-idx-to-load a0-20)
(goto cfg-51)
)
)
(label cfg-51)
(when (!= want-lev-idx-to-load -1)
;; we have a level that we should start loading!
;; loading only starts if we're not busy - there's a strange exception that if we have no levels at all,
;; and dgo is busy, we at least start the load.
(when (and (or no-levels-at-all (not (check-busy *load-dgo-rpc*))) (not (load-in-progress? *level*)))
(format 0 "Adding level ~A~%" (-> obj want want-lev-idx-to-load name))
;; do the actual level assignment
(let ((new-lev (level-get-for-use *level* (-> obj want want-lev-idx-to-load name) 'loaded)))
;; if we have no levels at all, there's nothing we can show until this one is loading, so block here and load.
(when (and no-levels-at-all (-> obj want want-lev-idx-to-load display?))
(format 0 "Waiting for level to load~%")
(while (or (= (-> new-lev status) 'loading) (= (-> new-lev status) 'loading-bt) (= (-> new-lev status) 'login))
(load-continue new-lev)
)
)
)
)
)
)
)
)
)
;; process other changes in want.
;; loop over all wanted levels
(dotimes (want-lev-i LEVEL_MAX)
(when (-> obj want want-lev-i name)
;; and find the associated level
(dotimes (lev-i LEVEL_TOTAL)
(let ((lev (-> *level* level lev-i)))
(when (!= (-> lev status) 'inactive)
(when (= (-> lev name) (-> obj want want-lev-i name))
;; change in display:
(when (!= (-> lev display?) (-> obj want want-lev-i display?))
(cond
((not (-> lev display?)) ;; off to on:
(cond
((or (= (-> lev status) 'loaded) (= (-> lev status) 'active))
(format 0 "Displaying level ~A [~A]~%" (-> obj want want-lev-i name) (-> obj want want-lev-i display?))
;; will activate/birth, starting entities and background drawing.
(level-get-for-use *level* (-> lev info name) 'active)
(set! (-> lev display?) (-> obj want want-lev-i display?))
)
(else
;; but the level isn't ready! trip jak (unless we have display-no-wait.)
(if (and (-> lev info wait-for-load) (!= (-> obj want want-lev-i display?) 'display-no-wait))
(send-event *target* 'loading)
)
(if (= *cheat-mode* 'debug)
(format *stdcon* "display on for ~A but level is loading~%" (-> obj want want-lev-i name))
)
)
)
)
((not (-> obj want want-lev-i display?)) ;; on -> off.
(set! (-> lev display?) #f)
(format 0 "Turning level ~A off~%" (-> lev name))
(deactivate lev)
)
(else
;; other change (special, etc)
(format 0 "Setting level ~A display command to ~A~%"
(-> obj want want-lev-i name)
(-> obj want want-lev-i display?)
)
(set! (-> lev display?) (-> obj want want-lev-i display?))
)
)
)
;; update force-all-visible
(when (!= (-> lev force-all-visible?) (-> obj want want-lev-i force-vis?))
(set! (-> lev force-all-visible?) (-> obj want want-lev-i force-vis?))
(format 0 "Setting force-all-visible?[~A] to ~A~%"
(-> obj want want-lev-i name)
(-> obj want want-lev-i force-vis?)
)
)
;; update force-inside
(when (!= (-> lev force-inside?) (-> obj want want-lev-i force-inside?))
(format 0 "Setting force-inside?[~A] ~A->~A~%"
(-> obj want want-lev-i name)
(-> lev force-inside?)
(-> obj want want-lev-i force-inside?)
)
(set! (-> lev force-inside?) (-> obj want want-lev-i force-inside?))
)
)
)
)
)
)
)
;; update vis level. this actually modifies the load state.
(let ((lev-for-vis (the-as level #f))
(num-vis-levs 0)
)
(dotimes (a1-35 (-> *level* length))
(let ((a2-32 (-> *level* level a1-35)))
(when (= (-> a2-32 status) 'active)
;; take any level that we're inside of, and has continue points
(when (and (-> a2-32 inside-boxes) (not (null? (-> a2-32 info continues))))
(if (= (-> a2-32 name) (-> obj vis-nick))
(goto cfg-125)
)
(set! lev-for-vis a2-32)
(+! num-vis-levs 1)
)
)
)
)
(if (and (>= num-vis-levs 1) (!= (-> lev-for-vis name) (-> obj vis-nick)))
(want-vis-level obj (-> lev-for-vis name))
)
)
(label cfg-125)
(update-sound-banks)
0
)
;; "draw" levels:
;; the "draw level" system is used to order the levels for drawing.
;; the draw-level array of level-group stores levels in the order they should be drawn.
;; eg: level3 of the DMA bucket array is actually (-> *level* draw-level 3), not (-> *level* level 3).
(defmethod assign-draw-indices level-group ((obj level-group))
"Sort the levels by draw priority."
(local-vars (t0-3 symbol))
(set! (-> obj draw-level-count) 0)
(dotimes (v1-0 LEVEL_TOTAL)
(let ((f0-0 100000.0)
(a1-1 (the-as level #f))
)
(dotimes (a2-0 (-> obj length))
(let ((a3-3 (-> obj level a2-0)))
(when (= (-> a3-3 status) 'active)
(set! t0-3 (and (< (-> a3-3 draw-priority) f0-0) (begin
(dotimes (t0-4 (-> obj draw-level-count))
(when (= a3-3 (-> obj draw-level t0-4))
(set! t0-3 #f)
(goto cfg-14)
)
)
#t
)
)
)
(label cfg-14)
(when t0-3
(set! a1-1 a3-3)
(set! f0-0 (-> a1-1 draw-priority))
)
)
)
)
(when a1-1
(set! (-> obj draw-level (-> obj draw-level-count)) a1-1)
(set! (-> a1-1 draw-index) (-> obj draw-level-count))
(+! (-> obj draw-level-count) 1)
)
)
)
(while (< (-> obj draw-level-count) LEVEL_TOTAL)
(set! (-> obj draw-level (-> obj draw-level-count)) #f)
(+! (-> obj draw-level-count) 1)
)
(set! (-> obj draw-level LEVEL_MAX) (-> obj default-level))
(set! (-> (&-> obj default-level draw-index) 0) LEVEL_MAX)
(dotimes (v1-12 LEVEL_TOTAL)
(let ((a2-9 (-> obj level v1-12)))
(if a2-9
(set! (-> obj draw-index-map v1-12) (the-as uint (-> a2-9 draw-index)))
)
)
)
0
(none)
)
(defmethod level-update level-group ((obj level-group))
(local-vars (v1-101 symbol))
(camera-pos)
(new 'static 'boxed-array :type symbol :length 0 :allocated-length LEVEL_MAX)
(update *setting-control*)
(update *gui-control* #t)
(update *art-control* #t)
(clear-rec *art-control*)
(dotimes (s5-0 LEVEL_MAX)
(load-continue (-> obj level s5-0))
)
(dotimes (s5-1 (-> obj length))
(let ((s4-0 (-> obj level s5-1)))
(when (= (-> s4-0 status) 'active)
(set! (-> s4-0 inside-boxes) (inside-boxes-check s4-0 (-> *math-camera* trans)))
(if (-> s4-0 inside-boxes)
(set! (-> s4-0 meta-inside?) #t)
)
)
)
)
(update! *load-state*)
(dotimes (s5-2 (-> obj length))
(let ((s4-1 (-> obj level s5-2)))
(when (= (-> s4-1 status) 'active)
(when (-> s4-1 inside-boxes)
(dotimes (v1-40 (-> obj length))
(let ((a0-13 (-> obj level v1-40)))
(when (= (-> a0-13 status) 'active)
(if (and (!= s4-1 a0-13) (not (-> a0-13 inside-boxes)))
(set! (-> a0-13 meta-inside?) #f)
)
)
)
)
)
(when (and (null? (-> obj load-commands))
(= (-> s4-1 name) (-> *load-state* vis-nick))
(begin
(set! (-> *setting-control* user-default music) (-> s4-1 info music-bank))
(set! (-> *setting-control* user-default sound-reverb) (-> s4-1 info sound-reverb))
#t
)
(or (-> *level* border?) (logtest? (-> *game-info* current-continue flags) (continue-flags change-continue)))
(or (!= (-> s4-1 name) (-> *game-info* current-continue level))
(logtest? (-> *game-info* current-continue flags) (continue-flags change-continue))
)
(not (null? (-> s4-1 info continues)))
(-> *setting-control* user-current allow-continue)
)
(let ((s3-0 (car (-> s4-1 info continues))))
(let* ((s2-0 (target-pos 0))
(s4-2 (-> s4-1 info continues))
(s1-0 (car s4-2))
)
(while (not (null? s4-2))
(when (and (or (< (vector-vector-distance s2-0 (-> (the-as continue-point s1-0) trans))
(vector-vector-distance s2-0 (-> (the-as continue-point s3-0) trans))
)
(string= (-> *game-info* current-continue name) (-> (the-as continue-point s1-0) name))
)
(not (logtest? (-> (the-as continue-point s1-0) flags) (continue-flags change-continue no-auto)))
)
(set! s3-0 (the-as continue-point s1-0))
(if (string= (-> *game-info* current-continue name) (-> (the-as continue-point s1-0) name))
(goto cfg-59)
)
)
(set! s4-2 (cdr s4-2))
(set! s1-0 (car s4-2))
)
)
(label cfg-59)
(if (and (the-as continue-point s3-0)
(not (logtest? (-> (the-as continue-point s3-0) flags) (continue-flags change-continue no-auto)))
)
(set-continue! *game-info* (the-as basic s3-0) #f)
)
)
)
)
)
)
(dotimes (v1-88 (-> obj length))
(let ((a0-48 (-> obj level v1-88)))
(when (= (-> a0-48 status) 'active)
(set! (-> a0-48 vis-self-index) 0)
0
)
)
)
(when (= *cheat-mode* 'debug)
(dotimes (s5-3 (-> obj length))
(let ((v1-96 (-> obj level s5-3)))
(when (= (-> v1-96 status) 'active)
(if (and (= (-> v1-96 status) 'active)
(!= (-> v1-96 display?) 'special)
(nonzero? (-> v1-96 bsp cam-outside-bsp))
)
(format *stdcon* "~3Loutside of bsp ~S~%~0L" (-> v1-96 name))
)
)
)
)
)
(countdown (v1-100 LEVEL_MAX)
(when (-> obj level v1-100 inside-boxes)
(set! v1-101 #f)
(goto cfg-90)
)
)
(set! v1-101 #t)
(label cfg-90)
(cond
(v1-101
0
)
(else
(dotimes (s5-4 (-> obj length))
(let ((s4-3 (-> obj level s5-4)))
(when (= (-> s4-3 status) 'active)
(dotimes (s3-1 8)
(let ((s2-1 (-> s4-3 vis-info s3-1)))
(when s2-1
(set! (-> s2-1 flags) (the-as vis-info-flag (logclear (-> s2-1 flags) (vis-info-flag vis-valid))))
(cond
((= s3-1 (-> s4-3 vis-self-index))
(set! (-> s2-1 from-bsp) (-> s4-3 bsp))
)
(else
(let ((v1-114 (level-get obj (-> s2-1 from-level))))
(set! (-> s2-1 from-bsp) (if v1-114
(-> v1-114 bsp)
)
)
)
)
)
)
)
)
(let ((v1-117 #f))
(cond
((= (-> s4-3 display?) 'display-self)
(let ((v1-121 (-> s4-3 vis-info (-> s4-3 vis-self-index))))
(if v1-121
(set! (-> v1-121 flags) (the-as vis-info-flag (logior (vis-info-flag vis-valid) (-> v1-121 flags))))
)
)
)
((and (-> s4-3 inside-boxes) (not v1-117))
(let ((v1-126 (-> s4-3 vis-info (-> s4-3 vis-self-index))))
(if v1-126
(set! (-> v1-126 flags) (the-as vis-info-flag (logior (vis-info-flag vis-valid) (-> v1-126 flags))))
)
)
)
)
)
)
)
)
)
)
(assign-draw-indices obj)
(when (or *display-level-border* *display-texture-distances* *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?)
)
(let ((t9-18 format)
(a0-86 *stdcon*)
(a1-30 " nick ~A cur ~S cont ~A~%~%")
(a2-6 (-> *load-state* vis-nick))
(v1-147 (and *target* (-> *target* current-level) (-> *target* current-level name)))
)
(t9-18
a0-86
a1-30
a2-6
(if v1-147
(symbol->string (the-as symbol v1-147))
)
(-> *game-info* current-continue name)
)
)
)
(dotimes (s5-5 LEVEL_TOTAL)
(let ((s4-4 (-> obj level s5-5)))
(when (or (= (-> s4-4 status) 'active) (= (-> s4-4 status) 'reserved))
(let ((t9-19 format)
(a0-90 *stdcon*)
(a1-31 "~A: ~S ~A~%")
(a2-7 (-> s4-4 name))
(a3-3 (if (-> s4-4 inside-boxes)
"inside"
)
)
)
(t9-19 a0-90 a1-31 a2-7 a3-3 (-> s4-4 display?))
(when *display-texture-distances*
(format *stdcon* "~10Htfrag: ~8,,0m" (-> s4-4 closest-object) (the-as none a3-3))
(format *stdcon* "~140Hshrub: ~8,,0m" (-> s4-4 closest-object-array 2) (the-as none a3-3))
(format *stdcon* "~272Halpha: ~8,,0m~%" (-> s4-4 closest-object-array 3) (the-as none a3-3))
(format *stdcon* "~27Htie: ~8,,0m" (-> s4-4 closest-object-array 10) (the-as none a3-3))
(format *stdcon* "~140Hfg-tf: ~8,,0m" (-> s4-4 closest-object-array 11) (the-as none a3-3))
(format *stdcon* "~270Hfg-pr: ~8,,0m~%" (-> s4-4 closest-object-array 12) (the-as none a3-3))
(format *stdcon* "~10Hfg-wa: ~8,,0m" (-> s4-4 closest-object-array 15) (the-as none a3-3))
(format *stdcon* "~140Hfg-sh: ~8,,0m" (-> s4-4 closest-object-array 13) (the-as none a3-3))
(format *stdcon* "~267Hfg-p2: ~8,,0m~%" (-> s4-4 closest-object-array 17) (the-as none a3-3))
)
)
(when *display-texture-download*
(format
*stdcon*
"~30Htf: ~8D~134Hpr: ~8D~252Hsh: ~8D~370Hhd: ~8D~%"
(-> s4-4 upload-size 0)
(-> s4-4 upload-size 1)
(-> s4-4 upload-size 2)
(-> s4-4 upload-size 8)
)
(let ((t9-30 format)
(a0-101 *stdcon*)
(a1-42 "~30Hal: ~8D~131Hwa: ~8D~252Hsp: ~8D~370Hwp: ~8D~%")
(a2-18 (-> s4-4 upload-size 3))
(a3-5 (-> s4-4 upload-size 4))
)
(t9-30 a0-101 a1-42 a2-18 a3-5 (-> s4-4 upload-size 7) (-> s4-4 upload-size 5))
(format *stdcon* "~30Hp2: ~8D~%~1K" (-> s4-4 upload-size 6) (the-as none a3-5))
)
)
(if *display-split-box-info*
(debug-print-region-splitbox s4-4 (-> *math-camera* trans) *stdcon*)
)
)
)
)
)
(when (and (-> obj disk-load-timing?) (-> obj load-level))
(let ((s5-6 format)
(s4-5 *stdcon*)
(s3-2 "~0Kload ~16S ~5S ~5DK ~5,,2fs ~5,,2fs~1K ~5,,0f k/s~%")
(s2-2 (-> obj load-level))
(v1-180 (lookup-level-info (-> obj load-level)))
)
(s5-6
s4-5
s3-2
s2-2
(if v1-180
(-> v1-180 nickname)
""
)
(shr (-> obj load-size) 10)
(-> obj load-time)
(-> obj load-login-time)
(if (= (-> obj load-time) 0.0)
0
(* 0.0009765625 (/ (the float (-> obj load-size)) (-> obj load-time)))
)
)
)
)
;; pc port note : this was hardcoded to the top of EE memory (#x2000000)
(let ((v1-186 (&- (-> global top-base) (-> global current))))
(if (and (not *debug-segment*) (< v1-186 (* 64 1024)))
(format *stdcon* "~3Lglobal heap fatally low at ~DK free~%~0L" (/ v1-186 (* 1024 1024)))
)
)
;; pc port added
(let ((lev-names (new 'stack-no-clear 'array 'string LEVEL_MAX)))
(dotimes (i LEVEL_MAX)
(cond
((= (-> obj level i status) 'inactive)
(set! (-> lev-names i) "none")
)
(else
(set! (-> lev-names i) (symbol->string (-> obj level i nickname)))
)
)
)
(__pc-set-levels lev-names)
)
0
(none)
)
(defun-debug show-level ((arg0 symbol))
(set! (-> *setting-control* user-default border-mode) #t)
(let ((s5-0 (new 'stack-no-clear 'array 'symbol 10)))
(set! (-> s5-0 5) #f)
(set! (-> s5-0 4) #f)
(set! (-> s5-0 3) #f)
(set! (-> s5-0 2) #f)
(set! (-> s5-0 1) arg0)
(set! (-> s5-0 0) (-> (level-get-target-inside *level*) name))
(want-levels *load-state* s5-0)
)
(want-display-level *load-state* arg0 'display)
0
)
(when (zero? (-> *level* level0 art-group))
(kmemopen global "level")
(let ((gp-0 *level*))
(set! (-> gp-0 loading-level) (-> gp-0 default-level))
(dotimes (s5-0 LEVEL_MAX)
(let ((s4-0 (-> gp-0 level s5-0)))
(set! (-> s4-0 art-group) (new 'global 'load-dir-art-group 100 s4-0))
(set! (-> s4-0 vis-bits) (malloc 'global 2048))
(vis-clear s4-0)
(set! (-> s4-0 tfrag-masks) (new 'global 'texture-masks-array 1))
(set! (-> s4-0 tfrag-dists) (malloc 'global 4))
(set! (-> s4-0 shrub-masks) (new 'global 'texture-masks-array 1))
(set! (-> s4-0 shrub-dists) (malloc 'global 4))
(set! (-> s4-0 alpha-masks) (new 'global 'texture-masks-array 1))
(set! (-> s4-0 alpha-dists) (malloc 'global 4))
(set! (-> s4-0 water-masks) (new 'global 'texture-masks-array 1))
(set! (-> s4-0 water-dists) (malloc 'global 4))
(clear-mood-context (-> s4-0 mood-context))
)
)
(set! (-> gp-0 default-level art-group) (new 'global 'load-dir-art-group 512 (-> gp-0 default-level)))
(dotimes (v1-31 LEVEL_TOTAL)
(let ((a0-53 (-> gp-0 level v1-31)))
(dotimes (a1-48 10)
(set! (-> a0-53 texture-anim-array a1-48) #f)
)
)
)
(set! (-> (&-> gp-0 default-level texture-anim-array 9) 0) *sky-texture-anim-array*)
(set! (-> (&-> gp-0 default-level texture-anim-array 1) 0) *darkjak-texture-anim-array*)
(set! (-> (&-> gp-0 default-level texture-anim-array 4) 0) *bomb-texture-anim-array*)
(set! (-> (&-> gp-0 default-level draw-priority) 0) 20.0)
(set! *default-level* (-> gp-0 default-level))
)
(kmemclose)
)