mirror of
https://github.com/open-goal/jak-project
synced 2026-08-20 14:24:45 -04:00
414 lines
22 KiB
Common Lisp
414 lines
22 KiB
Common Lisp
;;-*-Lisp-*-
|
|
(in-package goal)
|
|
(bundles "ENGINE.CGO" "GAME.CGO")
|
|
(require "engine/ui/text-h.gc")
|
|
(require "engine/debug/debug.gc")
|
|
(require "engine/load/load-dgo.gc")
|
|
|
|
;; This file contains functions for:
|
|
;; - loading text files containing translated game text
|
|
;; - managing the memory for text
|
|
;; - looking up strings from text
|
|
;; - helpers to draw text on the screen
|
|
|
|
;; It seems like there it would be possible to have multiple "groups" of text,
|
|
;; but in practice, only the COMMON group is used.
|
|
|
|
;; DECOMP BEGINS
|
|
|
|
;; State of text drawing.
|
|
(define *game-text-word* (new 'global 'string 128 (the string '#f)))
|
|
|
|
(define *game-text-line* (new 'global 'string 256 (the string '#f)))
|
|
|
|
(define *level-text-file-load-flag* #t)
|
|
|
|
;; allocate the game text heap if it isn't already allocated.
|
|
(when (zero? (-> *common-text-heap* base))
|
|
;; PC text data can exceed the original 34 KiB allocation.
|
|
(kheap-alloc *common-text-heap* (#if PC_PORT (* 64 1024) #x8800)))
|
|
|
|
;; The game-text-info stores records for each string in the loaded text on the text heap.
|
|
|
|
(defmethod length ((this game-text-info))
|
|
"Return the number of translated-text records."
|
|
(-> this length))
|
|
|
|
(defmethod asize-of ((this game-text-info))
|
|
"Return the fixed header size plus eight bytes for each translated-text record."
|
|
(the-as int (+ (-> this type size) (* (-> this length) 8))))
|
|
|
|
(defmethod inspect ((this game-text-info))
|
|
(format '#t "[~8x] ~A~%" this (-> this type))
|
|
(format '#t "~Tlength: ~D~%" (-> this length))
|
|
(format '#t "~Tdata[~D]: @ #x~X~%" (-> this length) (-> this data))
|
|
(dotimes (i (-> this length))
|
|
(format '#t "~T [~D] #x~X ~A~%" i (-> this data i id) (-> this data i text)))
|
|
this)
|
|
|
|
(defmethod mem-usage ((this game-text-info) (usage memory-usage-block) (flags mem-usage-flags))
|
|
"Account for the game-text-info allocation and every string owned by its records."
|
|
(mem-usage-add! usage string 1 (asize-of this))
|
|
(dotimes (i (-> this length))
|
|
(mem-usage-add! usage string 1 (asize-of (-> this data i text))))
|
|
this)
|
|
|
|
;; og:preserve-this extracted implementation out so that callers of `lookup-text!` were uneffected
|
|
;; this implementation is different from the original (has fallback text lookup)
|
|
(define-extern lookup-text-impl! (function game-text-info text-id symbol symbol string))
|
|
|
|
(defun lookup-text-impl! ((this game-text-info) (id text-id) (return-false? symbol) (fallback-call? symbol))
|
|
"Binary-search this text group for id. Use return-false? to select #f or an `UNKNOWN ID n` string
|
|
when it is absent. On PC, try the English fallback group first unless fallback-call? marks that
|
|
recursive lookup."
|
|
(let* ((lower-index 0)
|
|
(upper-index (+ (-> this length) 1))
|
|
(i (/ (+ lower-index upper-index) 2)))
|
|
(let ((previous-index -1))
|
|
(while (and (!= (-> this data i id) id) (!= i previous-index))
|
|
(if (< (the-as uint id) (the-as uint (-> this data i id))) (set! upper-index i) (set! lower-index i))
|
|
(set! previous-index i)
|
|
(set! i (/ (+ lower-index upper-index) 2))))
|
|
(cond
|
|
((!= (-> this data i id) id)
|
|
(cond
|
|
(return-false?
|
|
;; og:preserve-this Added fallback to english is string is not found.
|
|
(#if PC_PORT
|
|
(if (and *fallback-text-lookup?* (not fallback-call?))
|
|
(aif (lookup-text-impl! *fallback-text* id #t #t) it (the-as string #f))
|
|
(the-as string #f))
|
|
(the-as string #f)))
|
|
(else
|
|
;; og:preserve-this Added fallback to english is string is not found.
|
|
(#if PC_PORT
|
|
(if (and *fallback-text-lookup?* (not fallback-call?))
|
|
(aif (lookup-text-impl! *fallback-text* id #t #t) it (string-format "UNKNOWN ID ~D" id))
|
|
(string-format "UNKNOWN ID ~D" id))
|
|
(string-format "UNKNOWN ID ~D" id)))))
|
|
(else (-> this data i text)))))
|
|
|
|
(defmethod lookup-text! ((this game-text-info) (id text-id) (return-false? symbol))
|
|
"Binary-search the sorted records for id. Return its string; when id is absent, return #f if
|
|
return-false? is true, otherwise return a temporary `UNKNOWN ID n` string. On PC, a missing
|
|
translation can be looked up in the English fallback text first."
|
|
;; og:preserve-this call custom function
|
|
(lookup-text-impl! this id return-false? #f))
|
|
|
|
;; Game text loading.
|
|
;; The implementation of loading is blocking.
|
|
;; If you change languages, the game will freeze for a second while it loads
|
|
|
|
;; This loading flag is never used.
|
|
;; loading is complete once load-game-text-info returns
|
|
(define text-is-loading #f)
|
|
|
|
(defun load-game-text-info ((group-name string) (destination-symbol symbol) (heap kheap))
|
|
"Synchronously ensure group-name is loaded in the selected language into heap and publish the
|
|
linked game-text-info through destination-symbol. Reuse matching data; otherwise reset the heap,
|
|
load and link the language/group TXT file, and clear destination-symbol on link failure. EE maps
|
|
English to UK English in SCEE territory; PC reads its selected text language. Errors are reported
|
|
while the function always returns zero."
|
|
(local-vars (result int) (loaded-text game-text-info) (language-id language-enum) (load-size int) (heap-free int))
|
|
(set! loaded-text (the-as game-text-info (-> destination-symbol value)))
|
|
;; split languages in PC port
|
|
(set! language-id
|
|
(#if PC_PORT (the language-enum (-> *pc-settings* text-language)) (-> *setting-control* current language)))
|
|
(set! load-size 0)
|
|
(set! heap-free (&- (-> heap top) (the-as uint (-> heap base))))
|
|
;; english -> UK english in PAL
|
|
;; og:preserve-this no longer necessary.
|
|
(#unless PC_PORT
|
|
(if (and (= (scf-get-territory) GAME_TERRITORY_SCEE) (= language-id (language-enum english)))
|
|
(set! language-id (language-enum uk-english))))
|
|
;; only load if we actually need to
|
|
(when (or (= loaded-text #f) ;; nothing loaded
|
|
(!= (-> loaded-text language-id) (the-as uint language-id)) ;; loaded, but wrong lang
|
|
(not (string= (-> loaded-text group-name) group-name)) ;; loaded, but wrong group
|
|
)
|
|
;; clear the heap!
|
|
(let ((text-heap heap)) (set! (-> text-heap current) (-> text-heap base)))
|
|
(b! #t cfg-14)
|
|
(label cfg-13)
|
|
(load-dbg "Strange error during text load.~%")
|
|
(set! result 0)
|
|
(b! #t cfg-27)
|
|
(label cfg-14)
|
|
;; call str-load to start loading the TXT file to the heap
|
|
(let ((load-function str-load))
|
|
(format (clear *temp-string*) "~D~S.TXT" language-id group-name)
|
|
;; this branch is super weird.
|
|
(b! (not (load-function *temp-string*
|
|
-1
|
|
(logand -64 (&+ (-> heap current) 63))
|
|
(&- (-> heap top) (the-as uint (-> heap current)))))
|
|
cfg-13))
|
|
;; loop to wait until loading is complete
|
|
(label cfg-16)
|
|
(let ((loader-status (str-load-status (the-as (pointer int32) (& load-size)))))
|
|
(cond
|
|
((= loader-status 'error) (format 0 "Error loading text~%") (return 0))
|
|
((>= load-size (+ heap-free -300)) (format 0 "Game text heap overrun!~%") (return 0))
|
|
((= loader-status 'busy) (begin (nop!) (nop!) (nop!) (nop!) (nop!) (nop!) (goto cfg-16)))))
|
|
;; loading is done. now we link.
|
|
(let ((link-address (logand -64 (&+ (-> heap current) 63))))
|
|
(flush-cache 0)
|
|
(let ((link-function link))
|
|
(format (clear *temp-string*) "~D~S.TXT" language-id group-name)
|
|
(set! (-> destination-symbol value) (link-function link-address (-> *temp-string* data) load-size heap 0))))
|
|
;; linking error occured?
|
|
(if (<= (the-as int (-> destination-symbol value)) 0) (set! (-> destination-symbol value) (the-as object #f))))
|
|
(set! result 0)
|
|
(label cfg-27)
|
|
result)
|
|
|
|
(defun load-level-text-files ((level-index int))
|
|
"Load the common text group when level text loading is enabled or level-index is nonnegative. The
|
|
PC port also loads an English copy used for missing-translation fallback."
|
|
(when (or *level-text-file-load-flag* (>= level-index 0))
|
|
(load-game-text-info "common" '*common-text* *common-text-heap*)
|
|
(#when PC_PORT
|
|
(protect ((-> *pc-settings* text-language))
|
|
(set! (-> *pc-settings* text-language) (pc-language english))
|
|
(load-game-text-info "common" '*fallback-text* *fallback-text-heap*))))
|
|
(none))
|
|
|
|
(defun draw-debug-text-box ((context font-context))
|
|
"Draw the transformed rectangle described by context's origin, width, and height as four gray
|
|
debug lines."
|
|
(let ((line-color (new 'static 'vector4w))
|
|
(corners (new 'static 'matrix)))
|
|
(#when PC_PORT
|
|
(if (logtest? (-> context flags) (font-flags right)) (set! (-> context width) (- (-> context width)))))
|
|
(let ((corner (new 'static 'vector)))
|
|
(set-vector! corner (-> context origin x) (-> context origin y) 0.0 1.0)
|
|
(set! (-> corner x) (* (-> corner x) (-> *video-parms* relative-x-scale-reciprical)))
|
|
(vector-matrix*! corner corner (-> context mat))
|
|
(set-vector! (-> corners vector 0)
|
|
(the-as float (the int (-> corner x)))
|
|
(the-as float (the int (-> corner y)))
|
|
(the-as float (the int (-> corner z)))
|
|
(the-as float 1))
|
|
(set-vector! corner (+ (-> context origin x) (-> context width)) (-> context origin y) 0.0 1.0)
|
|
(set! (-> corner x) (* (-> corner x) (-> *video-parms* relative-x-scale-reciprical)))
|
|
(vector-matrix*! corner corner (-> context mat))
|
|
(set-vector! (-> corners vector 1)
|
|
(the-as float (the int (-> corner x)))
|
|
(the-as float (the int (-> corner y)))
|
|
(the-as float (the int (-> corner z)))
|
|
(the-as float 1))
|
|
(set-vector! corner (+ (-> context origin x) (-> context width)) (+ (-> context origin y) (-> context height)) 0.0 1.0)
|
|
(set! (-> corner x) (* (-> corner x) (-> *video-parms* relative-x-scale-reciprical)))
|
|
(vector-matrix*! corner corner (-> context mat))
|
|
(set-vector! (-> corners vector 2)
|
|
(the-as float (the int (-> corner x)))
|
|
(the-as float (the int (-> corner y)))
|
|
(the-as float (the int (-> corner z)))
|
|
(the-as float 1))
|
|
(set-vector! corner (-> context origin x) (+ (-> context origin y) (-> context height)) 0.0 1.0)
|
|
(set! (-> corner x) (* (-> corner x) (-> *video-parms* relative-x-scale-reciprical)))
|
|
(vector-matrix*! corner corner (-> context mat))
|
|
(set-vector! (-> corners vector 3)
|
|
(the-as float (the int (-> corner x)))
|
|
(the-as float (the int (-> corner y)))
|
|
(the-as float (the int (-> corner z)))
|
|
(the-as float 1)))
|
|
(set-vector! line-color 128 128 128 128)
|
|
(add-debug-line2d #t (bucket-id debug-no-zbuf) (-> corners vector 0) (-> corners vector 1) (the-as vector line-color))
|
|
(add-debug-line2d #t (bucket-id debug-no-zbuf) (-> corners vector 1) (-> corners vector 2) (the-as vector line-color))
|
|
(add-debug-line2d #t (bucket-id debug-no-zbuf) (-> corners vector 2) (-> corners vector 3) (the-as vector line-color))
|
|
(add-debug-line2d #t (bucket-id debug-no-zbuf) (-> corners vector 3) (-> corners vector 0) (the-as vector line-color))
|
|
(#when PC_PORT
|
|
(if (logtest? (-> context flags) (font-flags right)) (set! (-> context width) (- (-> context width))))))
|
|
0
|
|
(none))
|
|
|
|
(defun set-font-color-alpha ((color-index font-color) (alpha int))
|
|
"Set alpha on all four palette variants for color-index and on the font shadow."
|
|
(set! (-> *font-work* color-table color-index color 0 a) alpha)
|
|
(set! (-> *font-work* color-table color-index color 1 a) alpha)
|
|
(set! (-> *font-work* color-table color-index color 2 a) alpha)
|
|
(set! (-> *font-work* color-table color-index color 3 a) alpha)
|
|
(set! (-> *font-work* color-shadow w) alpha)
|
|
0
|
|
(none))
|
|
|
|
(defun print-game-text-scaled ((str string) (scale float) (context font-context) (alpha int))
|
|
"Temporarily scale context's bounds and font scale around its centering flags, draw str with
|
|
alpha, and restore the context."
|
|
(let ((original-width (-> context width))
|
|
(original-height (-> context height))
|
|
(original-x (-> context origin x))
|
|
(original-y (-> context origin y))
|
|
(original-scale (-> context scale)))
|
|
(let ((scaled-width (* (-> context width) scale))
|
|
(scaled-height (* (-> context height) scale)))
|
|
(if (logtest? (-> context flags) (font-flags middle)) (+! (-> context origin x) (* 0.5 (- original-width scaled-width))))
|
|
(if (logtest? (-> context flags) (font-flags middle-vert))
|
|
;; The integer half-difference is reinterpreted as float bits, so ordinary offsets contribute
|
|
;; only a denormal-sized adjustment. Horizontal centering above performs the intended float math.
|
|
(+! (-> context origin y) (the-as float (/ (the int (- original-height scaled-height)) 2))))
|
|
(set-scale! context (* original-scale scale))
|
|
(set! (-> context width) scaled-width)
|
|
(set! (-> context height) scaled-height))
|
|
(print-game-text str context #f alpha 22)
|
|
(set! (-> context origin x) original-x)
|
|
(set! (-> context origin y) original-y)
|
|
(set! (-> context width) original-width)
|
|
(set! (-> context height) original-height)
|
|
(set! (-> context scale) original-scale))
|
|
0
|
|
(none))
|
|
|
|
(defun print-game-text ((str string) (font-ctxt font-context) (no-draw symbol) (alpha int) (line-height int))
|
|
"Word-wrap str within font-ctxt's bounds, honoring its alignment and start-line. Draw each visible
|
|
line unless no-draw is true, in which case perform the same layout pass for measurement. Alpha is
|
|
applied while drawing; line-height supplies the spacing for large text, while ordinary text uses
|
|
14 units. Remove trailing spaces and formatting-only font commands at line boundaries, append drawn
|
|
packet ranges to the debug DMA bucket, and return the total height of the nonempty lines that fit."
|
|
(local-vars
|
|
(saved-matrix-x float)
|
|
(saved-matrix-y float)
|
|
(saved-relative-x-scale float)
|
|
(saved-relative-y-scale float)
|
|
(saved-relative-x-reciprocal float)
|
|
(saved-relative-y-reciprocal float)
|
|
(text-scale float)
|
|
(input-cursor (pointer uint8))
|
|
(line-end-x float)
|
|
(line-start-x float)
|
|
(max-x float)
|
|
(max-y float)
|
|
(space-width float)
|
|
(line-step float)
|
|
(line-count int)
|
|
(current-char int)
|
|
(word-length int)
|
|
(line-length int)
|
|
(line-index int)
|
|
(word-complete? symbol)
|
|
(line-complete? symbol))
|
|
(let ((layout-context (new 'stack
|
|
'font-context
|
|
*font-default-matrix*
|
|
(the int (-> font-ctxt origin x))
|
|
(the int (-> font-ctxt origin y))
|
|
0.0
|
|
(font-color default)
|
|
(font-flags shadow kerning))))
|
|
(when (< 0.1 (-> font-ctxt scale))
|
|
(set! saved-matrix-x (-> font-ctxt mat vector 0 x))
|
|
(set! saved-matrix-y (-> font-ctxt mat vector 1 y))
|
|
(set! saved-relative-x-scale (-> *video-parms* relative-x-scale))
|
|
(set! saved-relative-y-scale (-> *video-parms* relative-y-scale))
|
|
(set! saved-relative-x-reciprocal (-> *video-parms* relative-x-scale-reciprical))
|
|
(set! saved-relative-y-reciprocal (-> *video-parms* relative-y-scale-reciprical))
|
|
(set! text-scale (-> font-ctxt scale))
|
|
(set! (-> layout-context origin z) (-> font-ctxt origin z))
|
|
(set! (-> layout-context flags) (-> font-ctxt flags))
|
|
(set! (-> layout-context color) (-> font-ctxt color))
|
|
(set! (-> layout-context scale) text-scale)
|
|
(when (logtest? (-> layout-context flags) (font-flags middle-vert))
|
|
(logclear! (-> layout-context flags) (font-flags middle-vert))
|
|
(let ((saved-width (-> layout-context width))
|
|
(saved-height (-> layout-context height)))
|
|
(set! (-> layout-context width) (-> font-ctxt width))
|
|
(set! (-> layout-context height) (-> font-ctxt height))
|
|
(+! (-> layout-context origin y)
|
|
(the float (the int (* 0.5 (- (-> layout-context height) (print-game-text str layout-context #t 128 22))))))
|
|
(set! (-> layout-context width) saved-width)
|
|
(set! (-> layout-context height) saved-height)))
|
|
(set! (-> layout-context mat vector 0 x) (* (-> layout-context mat vector 0 x) text-scale))
|
|
(set! (-> layout-context mat vector 1 y) (* (-> layout-context mat vector 1 y) text-scale))
|
|
(set! (-> *video-parms* relative-x-scale) (* (-> *video-parms* relative-x-scale) text-scale))
|
|
(set! (-> *video-parms* relative-y-scale) (* (-> *video-parms* relative-y-scale) text-scale))
|
|
(set! (-> *video-parms* relative-x-scale-reciprical) (/ 1.0 (-> *video-parms* relative-x-scale)))
|
|
(set! (-> *video-parms* relative-y-scale-reciprical) (/ 1.0 text-scale))
|
|
(set! input-cursor (-> str data))
|
|
(set! line-end-x (-> layout-context origin x))
|
|
(set! line-start-x (-> layout-context origin x))
|
|
(set! max-x (+ (-> layout-context origin x) (-> font-ctxt width)))
|
|
(set! max-y (+ (-> layout-context origin y) (-> font-ctxt height)))
|
|
(set! space-width (* (get-string-length " " layout-context) (-> *video-parms* relative-x-scale)))
|
|
(set! line-step
|
|
(* (if (logtest? (-> layout-context flags) (font-flags large)) (the float line-height) 14.0) text-scale))
|
|
(set! line-count 0)
|
|
(if (logtest? (-> layout-context flags) (font-flags middle)) (+! (-> layout-context origin x) (* 0.5 (-> font-ctxt width))))
|
|
(set! current-char (the-as int (-> input-cursor 0)))
|
|
(set! word-length 0)
|
|
(set! line-length 0)
|
|
(set! line-index 0)
|
|
(set! word-complete? (the-as symbol #f))
|
|
(set! line-complete? (the-as symbol #f))
|
|
(set! (-> *game-text-line* data 0) (the-as uint 0))
|
|
(while (or (not (and (zero? current-char) (zero? word-length) (zero? line-length))) (>= max-y (-> layout-context origin y)))
|
|
(cond
|
|
((= current-char 32)
|
|
(set! (-> *game-text-word* data word-length) (the-as uint current-char))
|
|
(set! word-length (+ word-length 1))
|
|
(set! word-complete? #t))
|
|
((zero? current-char) (if (zero? word-length) (set! line-complete? #t) (set! word-complete? #t)))
|
|
(else
|
|
;; og:preserve-this PAL patch here
|
|
(if (= current-char 3) (set! current-char 32))
|
|
(set! (-> *game-text-word* data word-length) (the-as uint current-char))
|
|
(set! word-length (+ word-length 1))))
|
|
(when (= word-complete? #t)
|
|
(set! (-> *game-text-word* data word-length) (the-as uint 0))
|
|
(let* ((word-start-x line-end-x)
|
|
(word-width (* (get-string-length *game-text-word* layout-context) (-> *video-parms* relative-x-scale)))
|
|
(word-end-x (+ word-start-x word-width)))
|
|
(if (= (-> *game-text-word* data (+ word-length -1)) 32) (set! word-end-x (- word-end-x space-width)))
|
|
(cond
|
|
((< max-x word-end-x) (set! line-end-x (+ line-start-x word-width)) (set! line-complete? #t))
|
|
(else (set! line-end-x (+ line-end-x word-width))))))
|
|
(when (= line-complete? #t)
|
|
(when (>= line-index (the-as int (-> layout-context start-line)))
|
|
(let ((next-line-y (+ (-> layout-context origin y) line-step)))
|
|
(when (>= max-y next-line-y)
|
|
(when (= (-> *game-text-line* data (+ line-length -1)) 32)
|
|
(set! (-> *game-text-line* data (+ line-length -1)) (the-as uint 0))
|
|
(when (and (= (-> *game-text-line* data (+ line-length -5)) 126) (= (-> *game-text-line* data (+ line-length -2)) 72))
|
|
(set! (-> *game-text-line* data (+ line-length -5)) (the-as uint 0))
|
|
0)))
|
|
(when (and (= (-> *game-text-line* data (+ line-length -4)) 126) (= (-> *game-text-line* data (+ line-length -1)) 72))
|
|
(set! (-> *game-text-line* data (+ line-length -4)) (the-as uint 0))
|
|
0)
|
|
(if (nonzero? (-> *game-text-line* data 0)) (set! line-count (+ line-count 1)))
|
|
(when (not no-draw)
|
|
(with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) frame global-buf)) (bucket-id debug)) :bucket-group (-> *display* frames (-> *display* on-screen) frame bucket-group) (set-font-color-alpha (-> font-ctxt color) alpha) (draw-string *game-text-line* dma-buf layout-context) (set-font-color-alpha (-> font-ctxt color) 128) (set! (-> layout-context color) (-> *font-work* last-color))))
|
|
(set! (-> layout-context origin y) next-line-y)))
|
|
(set! line-index (+ line-index 1))
|
|
(set! (-> *game-text-line* data 0) (the-as uint 0))
|
|
(set! line-length 0)
|
|
(set! line-complete? (the-as symbol #f)))
|
|
(when (= word-complete? #t)
|
|
(copy-charp<-charp (&-> *game-text-line* data line-length) (-> *game-text-word* data))
|
|
(set! line-length (+ line-length word-length))
|
|
(set! word-length 0)
|
|
(set! word-complete? (the-as symbol #f)))
|
|
(when (nonzero? current-char)
|
|
(set! input-cursor (&-> input-cursor 1))
|
|
(set! current-char (the-as int (-> input-cursor 0)))))
|
|
(set! (-> layout-context mat vector 0 x) saved-matrix-x)
|
|
(set! (-> layout-context mat vector 1 y) saved-matrix-y)
|
|
(set! (-> *video-parms* relative-x-scale) saved-relative-x-scale)
|
|
(set! (-> *video-parms* relative-y-scale) saved-relative-y-scale)
|
|
(set! (-> *video-parms* relative-x-scale-reciprical) saved-relative-x-reciprocal)
|
|
(set! (-> *video-parms* relative-y-scale-reciprical) saved-relative-y-reciprocal)
|
|
(#when PC_PORT
|
|
(if (and *debug-segment* *display-text-box*) (draw-debug-text-box font-ctxt)))
|
|
(if (> line-count 0) (* line-step (the float line-count)) 0.0))))
|
|
|
|
(defun disable-level-text-file-loading ()
|
|
"Prevent calls with a negative level index from loading the common text group."
|
|
(set! *level-text-file-load-flag* #f)
|
|
0
|
|
(none))
|
|
|
|
(defun enable-level-text-file-loading ()
|
|
"Allow calls with a negative level index to load the common text group."
|
|
(set! *level-text-file-load-flag* #t)
|
|
0
|
|
(none))
|