{-# enc CP932 #- rlBabel.kh: dynamically lineated text display engine with proportional text support. Copyright (c) 2006 Peter Jolly. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA As a special exception to the GNU Lesser General Public License, you may include a publicly distributed version of the library in a "work that uses the Library" to produce a scenario file containing portions of the library, and distribute that scenario file under terms of your choice, without any of the additional requirements listed in clause 6 of the GNU Lesser General Public License. A "publicly distributed version of the library" means either an unmodified library as distributed by Haeleth, or a modified version of the library that is distributed under the conditions defined in clause 2 of the GNU Lesser General Public License. Note that this exception does not invalidate any other reasons why the scenario file might be covered by the GNU Lesser General Public License. -} #ifdef __TEXTOUT_KH__ #error 'The Textout and rlBabel libraries are mutually exclusive: you can only use one or the other.' #endif #ifndef __RLBABEL_KH__ #define __RLBABEL_KH__ #ifndef __DynamicLineation__ #define __DynamicLineation__ #endif #if !__DynamicLineation__ #set __DynamicLineation__ = 1 #endif #ifdef __dynamic_textout_print #undef __dynamic_textout_print #endif #if target_lt (1,2) #error 'The rlBabel library can only be used with RealLive 1.2 or greater.' #endif #const OldType = target_lt (1,2,5) #ifndef rlBabel #if OldType #const rlBabel = 'rlBabelF' #else #const rlBabel = 'rlBabel' #endif #endif // DLL index... this won't apply to 1.2.3.5 etc, of course. #ifndef rlBabelDLL #const rlBabelDLL = -1 #if OldType #set rlBabelDLL = 0 #else #for i = 0 .. 15: #if rlBabelDLL == -1 #if __equal_strings? (gameexe ('DLL.\i:3{i}', 0, ''), rlBabel) #set rlBabelDLL = i #endif #endif; #if rlBabelDLL == -1 #error 'load of ' + rlBabel + ' not found' #endif #endif #endif // Static variables #if default (__DebugTextout__, 0) && !defined? (__NoDebug__) #define __AllLabelled__ #endif int __rlb_glosses_active, __rlb_temp[4] str __rlb_buffer, __rlb_empty, __rlb_nest_buffer #if default (__DebugTextout__, 0) && !defined? (__NoDebug__) #undef __AllLabelled__ #endif // Function IDs: DLL #const dllInitialise = 0 // Function IDs: Textout #const dllTextoutStart = 10, dllTextoutAppend = 11, dllTextoutGetChar = 12, dllTextoutNewScreen = 13, dllClearGlosses = 20, dllNewGloss = 21, dllAddGloss = 22, dllTestGlosses = 23 // Function IDs: Utility #const dllSetNameMod = 100, dllGetNameMod = 101, dllSetWindowName = 102, dllGetTextWindow = 103, dllGetRCommandMod = 104, dllMessageBox = 105 // Function IDs: Select #const dllSelectAdd = 200 // Return values #const getcError = 0, getcEndOfString = 1, getcPrintChar = 2, getcNewLine = 3, getcNewScreen = 4, getcSetIndent = 5, getcClearIndent = 6, getcBeginGloss = 7 // DLL wrappers: DLL #inline __initialise_dynamic_textout (): #if OldType if !LoadDLL (0, rlBabel) rlcError ('failed to initialise text rendering engine') #endif strclear (__rlb_empty) __rlb_glosses_active = 0 objOfText (255, 'A') // to force the font to load -_-; return CallDLL (rlBabelDLL, dllInitialise, rlBabelDLL); // Public utility functions #inline GetTextWindow (): return CallDLL (rlBabelDLL, dllGetTextWindow); #inline SetNameMod (__value, __window = -1): return CallDLL (rlBabelDLL, dllSetNameMod, __window, __value); #inline GetNameMod (__window = -1): return CallDLL (rlBabelDLL, dllGetNameMod, __window); #inline SetCurrentWindowName (__value): #if !__variable? (__value) str s = __value CallDLL (rlBabelDLL, dllSetWindowName, __addr(s)) #else CallDLL (rlBabelDLL, dllSetWindowName, __addr(__value)) #endif return store; #inline GetRCommandMod (__window = -1): return CallDLL (rlBabelDLL, dllGetRCommandMod, __window); #inline MessageBox (__text, __title = 0): #if integer? (__title) #bind tval = __title #elseif __variable? (__title) #const tval = __addr(__title) #else str t = __title #const tval = __addr(t) #endif #if !__variable? (__text) str s if integer? (__text), s = itoa (__text) else s = __text CallDLL (rlBabelDLL, dllMessageBox, __addr(s), tval) #else CallDLL (rlBabelDLL, dllMessageBox, __addr(__text), tval) #endif return store; // DLL wrappers: Textout #inline __vwf_TryLoad() if !LoadDLL (0, rlBabel) rlcError ('failed to initialise text rendering engine') #inline __vwf_TextoutStart (__string, __is_start = 1): // Initialise textout and print an empty token to fix a save point here. #ifndef __DynamicLineationUsed__ #define __DynamicLineationUsed__ #endif if __is_start, strout (__rlb_empty) // Define the argument to pass the startup routine. #if !__variable? (__string) #if __empty_string? (__string) #sdefine arg = -1 #else __rlb_buffer = __string #sdefine arg = __addr(__rlb_buffer) #endif #else #sdefine arg = __addr(__string) #endif #if OldType // Old versions unload the DLL when a saved game is loaded. We have to // check for such failures and force it to be reloaded when necessary. while !CallDLL (rlBabelDLL, dllTextoutStart, arg) __vwf_TryLoad #else CallDLL (rlBabelDLL, dllTextoutStart, arg) #endif return store; #inline __vwf_TextoutAppend (__string): #if !__variable? (__string) #if !__empty_string? (__string) __rlb_buffer = __string CallDLL (rlBabelDLL, dllTextoutAppend, __addr(__rlb_buffer)) #endif #else CallDLL (rlBabelDLL, dllTextoutAppend, __addr(__string)) #endif; // DLL wrappers: Select #inline __vwf_SelectInit (__window, [__string1], [__string2], [__string3]): #ifndef __DynamicLineationUsed__ #define __DynamicLineationUsed__ #endif strout (__rlb_empty) DisableAutoSavepoints #if OldType // Old versions unload the DLL when a saved game is loaded. We have to // check for such failures and force it to be reloaded when necessary. #if defined?(__string3) while !CallDLL (rlBabelDLL, dllSelectAdd, __window, __addr(__string1), __addr(__string2), __addr(__string3)) __vwf_TryLoad #elseif defined?(__string2) while !CallDLL (rlBabelDLL, dllSelectAdd, __window, __addr(__string1), __addr(__string2)) __vwf_TryLoad #elseif defined?(__string1) while !CallDLL (rlBabelDLL, dllSelectAdd, __window, __addr(__string1)) __vwf_TryLoad #else while !CallDLL (rlBabelDLL, dllSelectAdd, __window) __vwf_TryLoad #endif #else #if defined?(__string3) CallDLL (rlBabelDLL, dllSelectAdd, __window, __addr(__string1), __addr(__string2), __addr(__string3)) #elseif defined?(__string2) CallDLL (rlBabelDLL, dllSelectAdd, __window, __addr(__string1), __addr(__string2)) #elseif defined?(__string1) CallDLL (rlBabelDLL, dllSelectAdd, __window, __addr(__string1)) #else CallDLL (rlBabelDLL, dllSelectAdd, __window) #endif #endif; #inline __vwf_SelectAdd (__window, [__string1], [__string2], [__string3]): #if defined?(__string3) CallDLL (rlBabelDLL, dllSelectAdd, __window, __addr(__string1), __addr(__string2), __addr(__string3)) #elseif defined?(__string2) CallDLL (rlBabelDLL, dllSelectAdd, __window, __addr(__string1), __addr(__string2)) #elseif defined?(__string1) CallDLL (rlBabelDLL, dllSelectAdd, __window, __addr(__string1)) #else CallDLL (rlBabelDLL, dllSelectAdd, __window) #endif; #inline __vwf_SelectCleanup (__dest = store): EnableAutoSavepoints return __dest; // DLL wrappers: glosses #inline __vwf_BeginGloss (): FontColour (6) // TODO: make customisable, disableable, etc. CallDLL (rlBabelDLL, dllNewGloss) __rlb_glosses_active += 1 ; #inline __vwf_GlossTextStart (__string): __rlb_buffer = __string; #inline __vwf_GlossTextAppend (__string): __rlb_buffer += __string; #inline __vwf_GlossTextSet ([__setstring]): #ifdef __setstring __vwf_GlossTextStart (__setstring) // different name because naive compiler = name capture = nontermination #endif; #inline __vwf_EndGloss (): CallDLL (rlBabelDLL, dllAddGloss, __addr(__rlb_buffer)) FontColour ; // Pause function wrappers #define __HideFunctionsSilently__ #const rlbPauseContinue = 0, rlbPauseClear = 1, rlbPauseClearUnlessNovel = 2 #inline __vwf_DoPauseFunc (__func, __clear): if defined?(__EnableGlosses__) && __rlb_glosses_active rlc_parse_string ('gosub @__vwf_handle_glosses_\i{__clear}__') else at (__CALLER_FILE__, __CALLER_LINE__, __func) ; #inline pause () __vwf_DoPauseFunc ('pause', rlbPauseClearUnlessNovel) #inline spause () __vwf_DoPauseFunc ('spause', rlbPauseContinue) #inline page () __vwf_DoPauseFunc ('page', rlbPauseClear) {- Wrap direct calls to breaking functions with calls to the textout routines. This will ensure that screen overflows are handled properly. A consequence is that it becomes more space-efficient to use control codes in strings than to call the functions directly. -} #inline br () '\n' #inline par () '\r' #undef __HideFunctionsSilently__ // The main rlBabel functions #inline __vwf_TextoutDisplay ([__text]): #bind a = __rlb_temp[0], buf = __rlb_buffer #ifndef __text gosub @__textoutdisplay__ #elseif __empty_string? (__text) gosub @__textoutdisplay__ #else // Initialise textout and print an empty token to fix a save point here. #ifndef __DynamicLineationUsed__ #define __DynamicLineationUsed__ #endif // strout (__rlb_empty) // let's try moving this to rlBabel.ml #if !__variable? (__text) buf = __text gosub @__textoutdisplay_start_buffer__ #else a = __addr(__text) & $fff gosub @__textoutdisplay_start__ #endif #endif; #inline __dynamic_textout_print (): // Inserted at the end of scenarios using rlBabel #bind a = __rlb_temp[0], b = __rlb_temp[1], x = __rlb_temp[2], y = __rlb_temp[3], buf = __rlb_buffer halt @__textoutdisplay_start__ __vwf_TextoutStart (strS[a], 0) goto @__textoutdisplay__ @__textoutdisplay_start_buffer__ __vwf_TextoutStart (buf, 0) @__textoutdisplay__ DisableAutoSavepoints stralloc (__rlb_buffer, 512) while 1 case CallDLL (rlBabelDLL, dllTextoutGetChar, __addr(buf), __addr(a)) of getcNewLine #hiding br, br continue of getcNewScreen page TextPos (0, 0) // page() doesn't reset the values that are otherwise perfect position counters? CallDLL (rlBabelDLL, dllTextoutNewScreen, __addr(buf)) continue of getcSetIndent SetIndent continue of getcClearIndent ClearIndent continue of getcBeginGloss __vwf_BeginGloss // fall through of getcPrintChar strout (buf) TextPosX (a) continue of getcError __rlb_empty = buf buf = "Error: " buf += __rlb_empty buf += ". Unable to format text." strclear (__rlb_empty) FastText strout (buf) NormalText of getcEndOfString other EnableAutoSavepoints ret ecase #ifdef __EnableGlosses__ // Pause handling in the presence of glosses. @__vwf_handle_glosses_0__ a = rlbPauseContinue goto @__vwf_handle_glosses__ @__vwf_handle_glosses_1__ a = rlbPauseClear goto @__vwf_handle_glosses__ @__vwf_handle_glosses_2__ a = rlbPauseClearUnlessNovel @__vwf_handle_glosses__ stralloc (__rlb_nest_buffer, 2048) while 1: FlushClick #hiding spause, spause GetCursorPos (x, y, b, store) if b != 2, break if !CallDLL (rlBabelDLL, dllTestGlosses, x, y, __addr(__rlb_nest_buffer), GetWakuAll), break #ifdef rlBabelGlossCallback // If the user has supplied a gloss callback, do what they want. rlBabelGlossCallback (__rlb_nest_buffer) #else // Default gloss behaviour: simple & sane MessageBox (__rlb_nest_buffer, 1) #endif; case a of rlbPauseClearUnlessNovel if GetRCommandMod: par break; of rlbPauseClear __rlb_glosses_active = 0 msgClear CallDLL (rlBabelDLL, dllClearGlosses) of rlbPauseContinue ecase store = 1 ret #endif; #endif // !defined? (__VWF_KH__)