aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorbjörn Andersson2003-10-11 12:26:53 +0000
committerTorbjörn Andersson2003-10-11 12:26:53 +0000
commit02a157e745210d8986df83dd2114c2ee0ae86c88 (patch)
tree160b1cb10dbbf5ca5ea8a6ebd2f510ab6d3ee88d
parent650581eef80bcf2fbe5bb55218ae329a8673498e (diff)
downloadscummvm-rg350-02a157e745210d8986df83dd2114c2ee0ae86c88.tar.gz
scummvm-rg350-02a157e745210d8986df83dd2114c2ee0ae86c88.tar.bz2
scummvm-rg350-02a157e745210d8986df83dd2114c2ee0ae86c88.zip
Moved the text drawing stuff into a class of its own. (Adding another
global variable which will hopefully be dealt with later.) svn-id: r10734
-rw-r--r--sword2/anims.cpp9
-rw-r--r--sword2/build_display.cpp10
-rw-r--r--sword2/console.cpp8
-rw-r--r--sword2/controls.cpp66
-rw-r--r--sword2/driver/d_draw.cpp2
-rw-r--r--sword2/maketext.cpp208
-rw-r--r--sword2/maketext.h113
-rw-r--r--sword2/mouse.cpp6
-rw-r--r--sword2/resman.cpp10
-rw-r--r--sword2/speech.cpp9
-rw-r--r--sword2/startup.cpp12
-rw-r--r--sword2/sword2.cpp9
-rw-r--r--sword2/sword2.h6
13 files changed, 239 insertions, 229 deletions
diff --git a/sword2/anims.cpp b/sword2/anims.cpp
index 55f014b1ed..e61826ef03 100644
--- a/sword2/anims.cpp
+++ b/sword2/anims.cpp
@@ -33,7 +33,7 @@
#include "bs2/defs.h"
#include "bs2/header.h"
#include "bs2/interpreter.h"
-#include "bs2/maketext.h" // for MakeTextSprite used by FN_play_sequence ultimately
+#include "bs2/maketext.h" // for makeTextSprite used by FN_play_sequence ultimately
#include "bs2/object.h"
#include "bs2/protocol.h"
#include "bs2/resman.h"
@@ -475,7 +475,7 @@ typedef struct {
} _sequenceTextInfo;
// keeps count of number of text lines to disaply during the sequence
-uint32 sequenceTextLines = 0;
+static uint32 sequenceTextLines = 0;
static _sequenceTextInfo sequence_text_list[MAX_SEQUENCE_TEXT_LINES];
@@ -574,7 +574,10 @@ void CreateSequenceSpeech(_movieTextObject *sequenceText[]) {
// NB. The mem block containing the text sprite is
// currently FLOATING!
- sequence_text_list[line].text_mem = MakeTextSprite(text + 2, 600, 255, speech_font_id);
+ // When rendering text over a sequence we need a
+ // different colour for the border.
+
+ sequence_text_list[line].text_mem = fontRenderer.makeTextSprite(text + 2, 600, 255, g_sword2->_speechFontId, 1);
// ok to close the text resource now
res_man.close(text_res);
diff --git a/sword2/build_display.cpp b/sword2/build_display.cpp
index 60f122e641..a4c14d663d 100644
--- a/sword2/build_display.cpp
+++ b/sword2/build_display.cpp
@@ -250,7 +250,7 @@ void Build_display(void) {
// text blocks
// speech blocks and headup debug text
- Print_text_blocs();
+ fontRenderer.printTextBlocs();
// ---------------------------------------------------
// menu bar & icons
@@ -297,7 +297,7 @@ void Build_display(void) {
spriteInfo.scale = 0;
spriteInfo.scaledWidth = 0;
spriteInfo.scaledHeight = 0;
- spriteInfo.type = RDSPR_DISPLAYALIGN + RDSPR_NOCOMPRESSION;
+ spriteInfo.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION;
spriteInfo.blend = 0;
spriteInfo.data = console_sprite->ad;
spriteInfo.colourTable = 0;
@@ -340,7 +340,7 @@ void DisplayMsg(uint8 *text, int time) {
CloseMenuImmediately();
EraseBackBuffer();
- text_spr = MakeTextSprite(text, 640, 187, speech_font_id);
+ text_spr = fontRenderer.makeTextSprite(text, 640, 187, g_sword2->_speechFontId);
frame = (_frameHeader *) text_spr->ad;
@@ -354,7 +354,7 @@ void DisplayMsg(uint8 *text, int time) {
spriteInfo.scale = 0;
spriteInfo.scaledWidth = 0;
spriteInfo.scaledHeight = 0;
- spriteInfo.type = RDSPR_DISPLAYALIGN + RDSPR_NOCOMPRESSION + RDSPR_TRANS;
+ spriteInfo.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION | RDSPR_TRANS;
spriteInfo.blend = 0;
spriteInfo.data = text_spr->ad + sizeof(_frameHeader);
spriteInfo.colourTable = 0;
@@ -494,7 +494,7 @@ void Process_layer(uint32 layer_number) {
spriteInfo.scaledWidth = 0;
spriteInfo.scaledHeight = 0;
spriteInfo.h = layer_head->height;
- spriteInfo.type = RDSPR_TRANS + RDSPR_RLE256FAST;
+ spriteInfo.type = RDSPR_TRANS | RDSPR_RLE256FAST;
spriteInfo.blend = 0;
spriteInfo.data = file + sizeof(_standardHeader) + layer_head->offset;
spriteInfo.colourTable = 0;
diff --git a/sword2/console.cpp b/sword2/console.cpp
index 5f125ff117..bd43cf6662 100644
--- a/sword2/console.cpp
+++ b/sword2/console.cpp
@@ -36,7 +36,7 @@ uint32 console_status = 0; //0 off // LEFT IN RELEASE VERSION
#include "bs2/header.h"
#include "bs2/layers.h"
#include "bs2/logic.h"
-#include "bs2/maketext.h" // for InitialiseFontResourceFlags()
+#include "bs2/maketext.h" // for initialiseFontResourceFlags()
#include "bs2/mouse.h"
#include "bs2/mem_view.h"
#include "bs2/memory.h"
@@ -672,15 +672,15 @@ uint32 Parse_user_input(void) {
Print_to_console("SFX logging deactivated");
return 0;
case 44: // ENGLISH
- InitialiseFontResourceFlags(DEFAULT_TEXT);
+ initialiseFontResourceFlags(DEFAULT_TEXT);
Print_to_console("Default fonts selected");
return 0;
case 45: // FINNISH
- InitialiseFontResourceFlags(FINNISH_TEXT);
+ initialiseFontResourceFlags(FINNISH_TEXT);
Print_to_console("Finnish fonts selected");
return 0;
case 46: // POLISH
- InitialiseFontResourceFlags(POLISH_TEXT);
+ initialiseFontResourceFlags(POLISH_TEXT);
Print_to_console("Polish fonts selected");
return 0;
default:
diff --git a/sword2/controls.cpp b/sword2/controls.cpp
index a87e91bf74..28adfe2246 100644
--- a/sword2/controls.cpp
+++ b/sword2/controls.cpp
@@ -657,14 +657,14 @@ public:
class MiniDialog : public Dialog {
private:
int _textId;
- FontRendererGui *_fontRenderer;
+ FontRendererGui *_fr;
Widget *_panel;
Button *_okButton;
Button *_cancelButton;
public:
MiniDialog(uint32 textId) : _textId(textId) {
- _fontRenderer = new FontRendererGui(controls_font_id);
+ _fr = new FontRendererGui(g_sword2->_controlsFontId);
_panel = new Widget(this, 1);
_panel->createSurfaceImages(1996, 203, 104);
@@ -681,15 +681,15 @@ public:
}
~MiniDialog() {
- delete _fontRenderer;
+ delete _fr;
}
virtual void paint() {
Dialog::paint();
- _fontRenderer->drawText(_textId, 310, 134, kAlignCenter);
- _fontRenderer->drawText(149618688, 270, 214); // ok
- _fontRenderer->drawText(149618689, 270, 276); // cancel
+ _fr->drawText(_textId, 310, 134, kAlignCenter);
+ _fr->drawText(149618688, 270, 214); // ok
+ _fr->drawText(149618689, 270, 276); // cancel
}
virtual void onAction(Widget *widget, int result = 0) {
@@ -702,7 +702,7 @@ public:
class OptionsDialog : public Dialog {
private:
- FontRendererGui *_fontRenderer;
+ FontRendererGui *_fr;
Widget *_panel;
Switch *_objectLabelsSwitch;
Switch *_subtitlesSwitch;
@@ -722,7 +722,7 @@ private:
public:
OptionsDialog() {
- _fontRenderer = new FontRendererGui(controls_font_id);
+ _fr = new FontRendererGui(g_sword2->_controlsFontId);
_panel = new Widget(this, 1);
_panel->createSurfaceImages(3405, 0, 40);
@@ -793,7 +793,7 @@ public:
}
~OptionsDialog() {
- delete _fontRenderer;
+ delete _fr;
}
virtual void paint() {
@@ -812,31 +812,31 @@ public:
};
for (int i = 0; i < ARRAYSIZE(alignTextIds); i++) {
- width = _fontRenderer->getTextWidth(alignTextIds[i]);
+ width = _fr->getTextWidth(alignTextIds[i]);
if (width > maxWidth)
maxWidth = width;
}
// Options
- _fontRenderer->drawText(149618698, 321, 55, kAlignCenter);
+ _fr->drawText(149618698, 321, 55, kAlignCenter);
// Subtitles
- _fontRenderer->drawText(149618699, 500, 103, kAlignRight);
+ _fr->drawText(149618699, 500, 103, kAlignRight);
// Object labels
- _fontRenderer->drawText(149618700, 299 - maxWidth, 103);
+ _fr->drawText(149618700, 299 - maxWidth, 103);
// Music volume
- _fontRenderer->drawText(149618702, 299 - maxWidth, 161);
+ _fr->drawText(149618702, 299 - maxWidth, 161);
// Speech volume
- _fontRenderer->drawText(149618703, 299 - maxWidth, 208);
+ _fr->drawText(149618703, 299 - maxWidth, 208);
// FX volume
- _fontRenderer->drawText(149618704, 299 - maxWidth, 254);
+ _fr->drawText(149618704, 299 - maxWidth, 254);
// Reverse stereo
- _fontRenderer->drawText(149618709, 299 - maxWidth, 296);
+ _fr->drawText(149618709, 299 - maxWidth, 296);
// Graphics quality
- _fontRenderer->drawText(149618705, 299 - maxWidth, 341);
+ _fr->drawText(149618705, 299 - maxWidth, 341);
// Ok
- _fontRenderer->drawText(149618688, 193, 382, kAlignRight);
+ _fr->drawText(149618688, 193, 382, kAlignRight);
// Cancel
- _fontRenderer->drawText(149618689, 385, 382, kAlignRight);
+ _fr->drawText(149618689, 385, 382, kAlignRight);
}
virtual void onAction(Widget *widget, int result = 0) {
@@ -1032,8 +1032,8 @@ private:
int _editPos, _firstPos;
int _cursorTick;
- FontRendererGui *_fontRenderer1;
- FontRendererGui *_fontRenderer2;
+ FontRendererGui *_fr1;
+ FontRendererGui *_fr2;
Widget *_panel;
Slot *_slotButton[8];
ScrollButton *_zupButton;
@@ -1052,8 +1052,8 @@ public:
// FIXME: The "control font" and the "red font" are currently
// always the same font, so one should be eliminated.
- _fontRenderer1 = new FontRendererGui(controls_font_id);
- _fontRenderer2 = new FontRendererGui(red_font_id);
+ _fr1 = new FontRendererGui(g_sword2->_controlsFontId);
+ _fr2 = new FontRendererGui(g_sword2->_redFontId);
_panel = new Widget(this, 1);
_panel->createSurfaceImages(2016, 0, 40);
@@ -1101,8 +1101,8 @@ public:
}
~SaveLoadDialog() {
- delete _fontRenderer1;
- delete _fontRenderer2;
+ delete _fr1;
+ delete _fr2;
}
// There aren't really a hundred different button objects of course,
@@ -1119,11 +1119,11 @@ public:
if (gui._baseSlot + i == _selectedSlot) {
slot->setEditable(_mode == kSaveDialog);
slot->setState(1);
- fr = _fontRenderer2;
+ fr = _fr2;
} else {
slot->setEditable(false);
slot->setState(0);
- fr = _fontRenderer1;
+ fr = _fr1;
}
if (GetSaveDescription(gui._baseSlot + i, description) == SR_OK) {
@@ -1211,7 +1211,7 @@ public:
tmp = _editBuffer[_editPos];
_editBuffer[_editPos] = 0;
- textWidth = _fontRenderer2->getTextWidth(_editBuffer);
+ textWidth = _fr2->getTextWidth(_editBuffer);
_editBuffer[_editPos] = tmp;
if (textWidth < 340 && _editPos < SAVE_DESCRIPTION_LEN - 2) {
@@ -1251,7 +1251,7 @@ public:
// but I doubt that will make any noticeable difference.
slot->paint();
- _fontRenderer2->drawText(_editBuffer, 130, 78 + (_selectedSlot - gui._baseSlot) * 36);
+ _fr2->drawText(_editBuffer, 130, 78 + (_selectedSlot - gui._baseSlot) * 36);
}
virtual void paint() {
@@ -1259,13 +1259,13 @@ public:
if (_mode == kLoadDialog) {
// Restore
- _fontRenderer1->drawText(149618690, 165, 377);
+ _fr1->drawText(149618690, 165, 377);
} else {
// Save
- _fontRenderer1->drawText(149618691, 165, 377);
+ _fr1->drawText(149618691, 165, 377);
}
// Cancel
- _fontRenderer1->drawText(149618689, 382, 377);
+ _fr1->drawText(149618689, 382, 377);
}
virtual void setResult(int result) {
diff --git a/sword2/driver/d_draw.cpp b/sword2/driver/d_draw.cpp
index 2cf7959db4..f01c2314e1 100644
--- a/sword2/driver/d_draw.cpp
+++ b/sword2/driver/d_draw.cpp
@@ -171,7 +171,7 @@ int32 MoviePlayer::play(char *filename, _movieTextObject *text[], uint8 *musicOu
memset(lpBackBuffer, 0, screenWide * MENUDEEP);
uint8 msg[] = "Cutscene - Press ESC to exit";
- mem *data = MakeTextSprite(msg, 640, 255, speech_font_id);
+ mem *data = fontRenderer.makeTextSprite(msg, 640, 255, g_sword2->_speechFontId);
_frameHeader *frame = (_frameHeader *) data->ad;
_spriteInfo msgSprite;
uint8 *msgSurface;
diff --git a/sword2/maketext.cpp b/sword2/maketext.cpp
index f813a897d6..92ed4147b5 100644
--- a/sword2/maketext.cpp
+++ b/sword2/maketext.cpp
@@ -40,10 +40,6 @@
#define BORDER_COL 200 // source colour for character border (only
// needed for remapping colours)
#define LETTER_COL 193 // source colour for bulk of character ( " )
-#define BORDER_PEN 194 // output colour for character border - should
- // be black ( " ) but note that we have to use
- // a different pen number during sequences
-
#define NO_COL 0 // sprite background - 0 for transparency!
#define SPACE ' '
#define FIRST_CHAR SPACE // first character in character set
@@ -64,39 +60,11 @@
namespace Sword2 {
-extern uint32 sequenceTextLines; // see anims.cpp
+FontRenderer fontRenderer;
// info for each line of words in the output text sprite
-typedef struct {
- uint16 width; // width of line in pixels
- uint16 length; // length of line in characters
-} _lineInfo;
-
-uint16 AnalyseSentence(uint8 *sentence, uint16 maxWidth, uint32 fontRes, _lineInfo *line);
-mem* BuildTextSprite(uint8 *sentence, uint32 fontRes, uint8 pen, _lineInfo *line, uint16 noOfLines);
-uint16 CharWidth(uint8 ch, uint32 fontRes);
-uint16 CharHeight(uint32 fontRes);
-_frameHeader* FindChar(uint8 ch, uint8 *charSet);
-void CopyChar(_frameHeader *charPtr, uint8 *spritePtr, uint16 spriteWidth, uint8 pen);
-
-// global layout variables - these used to be defines, but now we're dealing
-// with 2 character sets (10dec96 JEL)
-
-int8 line_spacing; // no. of pixels to separate lines of characters in
- // the output sprite - negative for overlap
-int8 char_spacing; // no. of pixels to separate characters along each
- // line - negative for overlap
-uint8 border_pen; // output pen colour of character borders
-
-// Global font resource id variables, set up in 'SetUpFontResources()' at
-// bottom of this file
-
-uint32 speech_font_id;
-uint32 controls_font_id;
-uint32 red_font_id;
-
-mem* MakeTextSprite(uint8 *sentence, uint16 maxWidth, uint8 pen, uint32 fontRes) {
+mem* FontRenderer::makeTextSprite(uint8 *sentence, uint16 maxWidth, uint8 pen, uint32 fontRes, uint8 border) {
mem *line; // handle for the memory block which will
// contain the array of lineInfo structures
mem *textSprite; // handle for the block to contain the text
@@ -104,45 +72,39 @@ mem* MakeTextSprite(uint8 *sentence, uint16 maxWidth, uint8 pen, uint32 fontRes)
uint16 noOfLines; // no of lines of text required to fit within
// a sprite of width 'maxWidth' pixels
- debug(5, "MakeTextSprite(\"%s\", maxWidth=%u)", sentence, maxWidth);
+ debug(5, "makeTextSprite(\"%s\", maxWidth=%u)", sentence, maxWidth);
+
+ _borderPen = border;
// NB. ensure sentence contains no leading/tailing/extra spaces - if
// necessary, copy to another array first, missing the extra spaces.
- // set the global layout variables (10dec96 JEL)
+ // set the global layout variables
- if (fontRes == speech_font_id) {
- line_spacing = -6; // overlap lines by 6 pixels
- char_spacing = -3; // overlap characters by 3 pixels
+ if (fontRes == g_sword2->_speechFontId) {
+ _lineSpacing = -6; // overlap lines by 6 pixels
+ _charSpacing = -3; // overlap characters by 3 pixels
} else if (fontRes == CONSOLE_FONT_ID) {
- line_spacing = 0; // no space or overlap between lines
- char_spacing = 1; // 1 pixel spacing between each character
+ _lineSpacing = 0; // no space or overlap between lines
+ _charSpacing = 1; // 1 pixel spacing between each character
} else {
- line_spacing = 0;
- char_spacing = 0;
+ _lineSpacing = 0;
+ _charSpacing = 0;
}
- // If rendering text over a sequence we need a different colour for
- // the border.
-
- if (sequenceTextLines)
- border_pen = 1;
- else
- border_pen = BORDER_PEN;
-
// allocate memory for array of lineInfo structures
- line = memory.allocMemory(MAX_LINES * sizeof(_lineInfo), MEM_locked, UID_temp);
+ line = memory.allocMemory(MAX_LINES * sizeof(LineInfo), MEM_locked, UID_temp);
- // get details of sentence breakdown into array of _lineInfo structures
+ // get details of sentence breakdown into array of LineInfo structures
// and get the no of lines involved
- noOfLines = AnalyseSentence(sentence, maxWidth, fontRes, (_lineInfo *) line->ad);
+ noOfLines = analyseSentence(sentence, maxWidth, fontRes, (LineInfo *) line->ad);
// construct the sprite based on the info gathered - returns floating
// mem block
- textSprite = BuildTextSprite(sentence, fontRes, pen, (_lineInfo *) line->ad, noOfLines);
+ textSprite = buildTextSprite(sentence, fontRes, pen, (LineInfo *) line->ad, noOfLines);
// free up the lineInfo array now
memory.freeMemory(line);
@@ -150,17 +112,17 @@ mem* MakeTextSprite(uint8 *sentence, uint16 maxWidth, uint8 pen, uint32 fontRes)
return textSprite;
}
-uint16 AnalyseSentence(uint8 *sentence, uint16 maxWidth, uint32 fontRes, _lineInfo *line) {
+uint16 FontRenderer::analyseSentence(uint8 *sentence, uint16 maxWidth, uint32 fontRes, LineInfo *line) {
uint16 pos = 0, wordWidth, wordLength, spaceNeeded;
uint16 lineNo = 0;
uint8 ch;
bool firstWord = true;
// joinWidth = how much extra space is needed to append a word to a
- // line. NB. SPACE requires TWICE the 'char_spacing' to join a word
+ // line. NB. SPACE requires TWICE the '_charSpacing' to join a word
// to line
- uint16 joinWidth = CharWidth(SPACE, fontRes) + 2 * char_spacing;
+ uint16 joinWidth = charWidth(SPACE, fontRes) + 2 * _charSpacing;
// while not reached the NULL terminator
@@ -175,13 +137,13 @@ uint16 AnalyseSentence(uint8 *sentence, uint16 maxWidth, uint32 fontRes, _lineIn
// while not SPACE or NULL terminator
while ((ch != SPACE) && ch) {
- wordWidth += CharWidth(ch, fontRes) + char_spacing;
+ wordWidth += charWidth(ch, fontRes) + _charSpacing;
wordLength++;
ch = sentence[pos++];
}
- // no char_spacing after final letter of word!
- wordWidth -= char_spacing;
+ // no _charSpacing after final letter of word!
+ wordWidth -= _charSpacing;
// 'ch' is now the SPACE or NULL following the word
// 'pos' indexes to the position following 'ch'
@@ -209,7 +171,7 @@ uint16 AnalyseSentence(uint8 *sentence, uint16 maxWidth, uint32 fontRes, _lineIn
// put word (without separating SPACE) at
// start of next line
- // for next _lineInfo structure in the array
+ // for next LineInfo structure in the array
lineNo++;
// exception if lineNo >= MAX_LINES
@@ -228,16 +190,16 @@ uint16 AnalyseSentence(uint8 *sentence, uint16 maxWidth, uint32 fontRes, _lineIn
// Returns a handle to a floating memory block containing a text sprite, given
// a pointer to a null-terminated string, pointer to required character set,
// required text pen colour (or zero to use source colours), pointer to the
-// array of linInfo structures created by 'AnalyseSentence()', and the number
+// array of linInfo structures created by 'analyseSentence()', and the number
// of lines (ie. no. of elements in the 'line' array).
// PC Version of BuildTextSprite
-mem* BuildTextSprite(uint8 *sentence, uint32 fontRes, uint8 pen, _lineInfo *line, uint16 noOfLines) {
+mem* FontRenderer::buildTextSprite(uint8 *sentence, uint32 fontRes, uint8 pen, LineInfo *line, uint16 noOfLines) {
uint8 *linePtr, *spritePtr;
uint16 lineNo, pos = 0, posInLine, spriteWidth = 0, spriteHeight;
uint16 sizeOfSprite;
- uint16 charHeight = CharHeight(fontRes);
+ uint16 char_height = charHeight(fontRes);
_frameHeader *frameHeadPtr, *charPtr;
mem *textSprite;
uint8 *charSet;
@@ -251,7 +213,7 @@ mem* BuildTextSprite(uint8 *sentence, uint32 fontRes, uint8 pen, _lineInfo *line
// spriteHeight = tot height of char lines + tot height of separating
// lines
- spriteHeight = charHeight * noOfLines + line_spacing * (noOfLines - 1);
+ spriteHeight = char_height * noOfLines + _lineSpacing * (noOfLines - 1);
// total size (no of pixels)
sizeOfSprite = spriteWidth * spriteHeight;
@@ -286,7 +248,7 @@ mem* BuildTextSprite(uint8 *sentence, uint32 fontRes, uint8 pen, _lineInfo *line
// fill sprite with characters, one line at a time
- for(lineNo = 0; lineNo < noOfLines; lineNo++) {
+ for (lineNo = 0; lineNo < noOfLines; lineNo++) {
// position the start of the line so that it is centred
// across the sprite
@@ -297,22 +259,22 @@ mem* BuildTextSprite(uint8 *sentence, uint32 fontRes, uint8 pen, _lineInfo *line
// width minus the 'overlap'
for (posInLine = 0; posInLine < line[lineNo].length; posInLine++) {
- charPtr = FindChar(sentence[pos++], charSet);
+ charPtr = findChar(sentence[pos++], charSet);
#ifdef _SWORD2_DEBUG
- if (charPtr->height != charHeight)
+ if (charPtr->height != char_height)
Con_fatal_error("FONT ERROR: '%c' is not same height as the space", sentence[pos - 1]);
#endif
- CopyChar(charPtr, spritePtr, spriteWidth, pen);
- spritePtr += charPtr->width + char_spacing;
+ copyChar(charPtr, spritePtr, spriteWidth, pen);
+ spritePtr += charPtr->width + _charSpacing;
}
// skip space at end of last word in this line
pos++;
// move to start of next character line in text sprite
- linePtr += (charHeight + line_spacing) * spriteWidth;
+ linePtr += (char_height + _lineSpacing) * spriteWidth;
}
// close font file
@@ -327,7 +289,7 @@ mem* BuildTextSprite(uint8 *sentence, uint32 fontRes, uint8 pen, _lineInfo *line
// Returns the width of a character sprite, given the character's ASCII code
// and a pointer to the start of the character set.
-uint16 CharWidth(uint8 ch, uint32 fontRes) {
+uint16 FontRenderer::charWidth(uint8 ch, uint32 fontRes) {
_frameHeader *charFrame;
uint8 *charSet;
uint16 width;
@@ -336,7 +298,7 @@ uint16 CharWidth(uint8 ch, uint32 fontRes) {
charSet = res_man.open(fontRes);
// move to approp. sprite (header)
- charFrame = FindChar(ch, charSet);
+ charFrame = findChar(ch, charSet);
width = charFrame->width;
// close font file
@@ -349,7 +311,7 @@ uint16 CharWidth(uint8 ch, uint32 fontRes) {
// Returns the height of a character sprite, given the character's ASCII code
// and a pointer to the start of the character set.
-uint16 CharHeight(uint32 fontRes) {
+uint16 FontRenderer::charHeight(uint32 fontRes) {
_frameHeader *charFrame;
uint8 *charSet;
uint16 height;
@@ -358,7 +320,7 @@ uint16 CharHeight(uint32 fontRes) {
charSet = res_man.open(fontRes);
// assume all chars the same height, i.e. FIRST_CHAR is as good as any
- charFrame = FindChar(FIRST_CHAR, charSet);
+ charFrame = findChar(FIRST_CHAR, charSet);
height = charFrame->height;
// close font file
@@ -371,7 +333,7 @@ uint16 CharHeight(uint32 fontRes) {
// Returns a pointer to the header of a character sprite, given the character's
// ASCII code and a pointer to the start of the character set.
-_frameHeader* FindChar(uint8 ch, uint8 *charSet) {
+_frameHeader* FontRenderer::findChar(uint8 ch, uint8 *charSet) {
// if 'ch' out of range, print the 'dud' character (chequered flag)
if (ch < FIRST_CHAR)
ch = DUD;
@@ -381,10 +343,10 @@ _frameHeader* FindChar(uint8 ch, uint8 *charSet) {
// Copies a character sprite from 'charPtr' to the sprite buffer at 'spritePtr'
// of width 'spriteWidth'. If pen is zero, it copies the data across directly,
-// otherwise it maps pixels of BORDER_COL to 'border_pen', and LETTER_COL to
+// otherwise it maps pixels of BORDER_COL to '_borderPen', and LETTER_COL to
// 'pen'.
-void CopyChar(_frameHeader *charPtr, uint8 *spritePtr, uint16 spriteWidth, uint8 pen) {
+void FontRenderer::copyChar(_frameHeader *charPtr, uint8 *spritePtr, uint16 spriteWidth, uint8 pen) {
uint8 *rowPtr, *source, *dest;
uint16 rows, cols;
@@ -412,7 +374,7 @@ void CopyChar(_frameHeader *charPtr, uint8 *spritePtr, uint16 spriteWidth, uint8
// underneath (for overlapping!)
if (!*dest)
- *dest = border_pen;
+ *dest = _borderPen;
break;
// do nothing if source pixel is zero,
@@ -434,30 +396,6 @@ void CopyChar(_frameHeader *charPtr, uint8 *spritePtr, uint16 spriteWidth, uint8
}
}
-#ifdef _SWORD2_DEBUG
-// allow enough for all the debug text blocks (see debug.cpp)
-#define MAX_text_blocs MAX_DEBUG_TEXT_BLOCKS + 1
-#else
-// only need one for speech, and possibly one for "PAUSED"
-#define MAX_text_blocs 2
-#endif
-
-typedef struct {
- int16 x;
- int16 y;
- // RDSPR_ status bits - see defintion of _spriteInfo structure for
- // correct size!
- uint16 type;
- mem *text_mem;
-} text_bloc;
-
-static text_bloc text_sprite_list[MAX_text_blocs];
-
-void Init_text_bloc_system(void) {
- for (int j = 0; j < MAX_text_blocs; j++)
- text_sprite_list[j].text_mem = 0;
-}
-
// distance to keep speech text from edges of screen
#define TEXT_MARGIN 12
@@ -465,7 +403,7 @@ void Init_text_bloc_system(void) {
// blocs are read and blitted at render time choose alignment type
// RDSPR_DISPLAYALIGN or 0
-uint32 Build_new_block(uint8 *ascii, int16 x, int16 y, uint16 width, uint8 pen, uint32 type, uint32 fontRes, uint8 justification) {
+uint32 FontRenderer::buildNewBloc(uint8 *ascii, int16 x, int16 y, uint16 width, uint8 pen, uint32 type, uint32 fontRes, uint8 justification) {
uint32 j = 0;
_frameHeader *frame_head;
int16 text_left_margin;
@@ -474,7 +412,7 @@ uint32 Build_new_block(uint8 *ascii, int16 x, int16 y, uint16 width, uint8 pen,
int16 text_bottom_margin;
// find a free slot
- while(j < MAX_text_blocs && text_sprite_list[j].text_mem)
+ while (j < MAX_text_blocs && _blocList[j].text_mem)
j++;
#ifdef _SWORD2_DEBUG
@@ -484,7 +422,7 @@ uint32 Build_new_block(uint8 *ascii, int16 x, int16 y, uint16 width, uint8 pen,
#endif
// make the sprite!
- text_sprite_list[j].text_mem = MakeTextSprite(ascii, width, pen, fontRes);
+ _blocList[j].text_mem = makeTextSprite(ascii, width, pen, fontRes);
// speech to be centred above point (x,y), but kept on-screen
// where (x,y) is a point somewhere just above the talker's head
@@ -497,7 +435,7 @@ uint32 Build_new_block(uint8 *ascii, int16 x, int16 y, uint16 width, uint8 pen,
// without margin checking - used for debug text
if (justification != NO_JUSTIFICATION) {
- frame_head = (_frameHeader *) text_sprite_list[j].text_mem->ad;
+ frame_head = (_frameHeader *) _blocList[j].text_mem->ad;
switch (justification) {
// this one is always used for SPEECH TEXT; possibly
@@ -554,16 +492,16 @@ uint32 Build_new_block(uint8 *ascii, int16 x, int16 y, uint16 width, uint8 pen,
y = text_bottom_margin;
}
- text_sprite_list[j].x = x;
- text_sprite_list[j].y = y;
+ _blocList[j].x = x;
+ _blocList[j].y = y;
// always uncompressed
- text_sprite_list[j].type = type | RDSPR_NOCOMPRESSION;
+ _blocList[j].type = type | RDSPR_NOCOMPRESSION;
return j + 1;
}
-void Print_text_blocs(void) {
+void FontRenderer::printTextBlocs(void) {
//called by build_display
_frameHeader *frame;
@@ -572,19 +510,19 @@ void Print_text_blocs(void) {
uint32 j;
for (j = 0; j < MAX_text_blocs; j++) {
- if (text_sprite_list[j].text_mem) {
- frame = (_frameHeader*) text_sprite_list[j].text_mem->ad;
+ if (_blocList[j].text_mem) {
+ frame = (_frameHeader*) _blocList[j].text_mem->ad;
- spriteInfo.x = text_sprite_list[j].x;
- spriteInfo.y = text_sprite_list[j].y;
+ spriteInfo.x = _blocList[j].x;
+ spriteInfo.y = _blocList[j].y;
spriteInfo.w = frame->width;
spriteInfo.h = frame->height;
spriteInfo.scale = 0;
spriteInfo.scaledWidth = 0;
spriteInfo.scaledHeight = 0;
- spriteInfo.type = text_sprite_list[j].type;
+ spriteInfo.type = _blocList[j].type;
spriteInfo.blend = 0;
- spriteInfo.data = text_sprite_list[j].text_mem->ad + sizeof(_frameHeader);
+ spriteInfo.data = _blocList[j].text_mem->ad + sizeof(_frameHeader);
spriteInfo.colourTable = 0;
rv = DrawSprite(&spriteInfo);
@@ -594,20 +532,22 @@ void Print_text_blocs(void) {
}
}
-void Kill_text_bloc(uint32 bloc_number) {
+void FontRenderer::killTextBloc(uint32 bloc_number) {
//back to real
bloc_number--;
- if (text_sprite_list[bloc_number].text_mem) {
+ if (_blocList[bloc_number].text_mem) {
// release the floating memory and mark it as free
- memory.freeMemory(text_sprite_list[bloc_number].text_mem);
- text_sprite_list[bloc_number].text_mem = 0;
+ memory.freeMemory(_blocList[bloc_number].text_mem);
+ _blocList[bloc_number].text_mem = 0;
} else {
// illegal kill - stop the system
Con_fatal_error("closing closed text bloc number %d", bloc_number);
}
}
+// The rest of this file doesn't belong in the FontRenderer class!
+
// called from InitialiseGame() in sword2.cpp
// resource 3258 contains text from location script for 152 (install, save &
@@ -619,7 +559,7 @@ void Kill_text_bloc(uint32 bloc_number) {
#define SAVE_LINE_NO 1
-void InitialiseFontResourceFlags(void) {
+void Sword2Engine::initialiseFontResourceFlags(void) {
uint8 *textFile, *textLine;
uint8 language;
@@ -644,7 +584,7 @@ void InitialiseFontResourceFlags(void) {
language = DEFAULT_TEXT;
// Set the game to use the appropriate fonts
- InitialiseFontResourceFlags(language);
+ initialiseFontResourceFlags(language);
// Get the game name for the windows application
@@ -671,22 +611,22 @@ void InitialiseFontResourceFlags(void) {
// called from the above function, and also from console.cpp
-void InitialiseFontResourceFlags(uint8 language) {
+void Sword2Engine::initialiseFontResourceFlags(uint8 language) {
switch (language) {
case FINNISH_TEXT: // special Finnish fonts
- speech_font_id = FINNISH_SPEECH_FONT_ID;
- controls_font_id = FINNISH_CONTROLS_FONT_ID;
- red_font_id = FINNISH_RED_FONT_ID;
+ _speechFontId = FINNISH_SPEECH_FONT_ID;
+ _controlsFontId = FINNISH_CONTROLS_FONT_ID;
+ _redFontId = FINNISH_RED_FONT_ID;
break;
case POLISH_TEXT: // special Polish fonts
- speech_font_id = POLISH_SPEECH_FONT_ID;
- controls_font_id = POLISH_CONTROLS_FONT_ID;
- red_font_id = POLISH_RED_FONT_ID;
+ _speechFontId = POLISH_SPEECH_FONT_ID;
+ _controlsFontId = POLISH_CONTROLS_FONT_ID;
+ _redFontId = POLISH_RED_FONT_ID;
break;
default: // DEFAULT_TEXT - regular fonts
- speech_font_id = ENGLISH_SPEECH_FONT_ID;
- controls_font_id = ENGLISH_CONTROLS_FONT_ID;
- red_font_id = ENGLISH_RED_FONT_ID;
+ _speechFontId = ENGLISH_SPEECH_FONT_ID;
+ _controlsFontId = ENGLISH_CONTROLS_FONT_ID;
+ _redFontId = ENGLISH_RED_FONT_ID;
break;
}
}
diff --git a/sword2/maketext.h b/sword2/maketext.h
index d3defa1c55..47be05cfc6 100644
--- a/sword2/maketext.h
+++ b/sword2/maketext.h
@@ -59,40 +59,105 @@
#include "bs2/memory.h"
+#ifdef _SWORD2_DEBUG
+#include "bs2/debug.h"
+#endif
+
+// Output colour for character border - should be be black but note that we
+// have to use a different pen number during sequences
+
+#define BORDER_PEN 194
+
namespace Sword2 {
-// only for debug text, since it doesn't keep text inside the screen margin!
-#define NO_JUSTIFICATION 0
-// these all force text inside the screen edge margin when necessary
-#define POSITION_AT_CENTRE_OF_BASE 1
-#define POSITION_AT_CENTRE_OF_TOP 2
-#define POSITION_AT_LEFT_OF_TOP 3
-#define POSITION_AT_RIGHT_OF_TOP 4
-#define POSITION_AT_LEFT_OF_BASE 5
-#define POSITION_AT_RIGHT_OF_BASE 6
-#define POSITION_AT_LEFT_OF_CENTRE 7
-#define POSITION_AT_RIGHT_OF_CENTRE 8
+#ifdef _SWORD2_DEBUG
+// allow enough for all the debug text blocks (see debug.cpp)
+#define MAX_text_blocs MAX_DEBUG_TEXT_BLOCKS + 1
+#else
+// only need one for speech, and possibly one for "PAUSED"
+#define MAX_text_blocs 2
+#endif
+
+enum {
+ // only for debug text, since it doesn't keep text inside the screen
+ // margin!
+ NO_JUSTIFICATION = 0,
+
+ // these all force text inside the screen edge margin when necessary
+ POSITION_AT_CENTRE_OF_BASE = 1,
+ POSITION_AT_CENTRE_OF_TOP = 2,
+ POSITION_AT_LEFT_OF_TOP = 3,
+ POSITION_AT_RIGHT_OF_TOP = 4,
+ POSITION_AT_LEFT_OF_BASE = 5,
+ POSITION_AT_RIGHT_OF_BASE = 6,
+ POSITION_AT_LEFT_OF_CENTRE = 7,
+ POSITION_AT_RIGHT_OF_CENTRE = 8
+};
+
+enum {
+ DEFAULT_TEXT = 0,
+ FINNISH_TEXT = 1,
+ POLISH_TEXT = 2
+};
-mem* MakeTextSprite(uint8 *sentence, uint16 maxWidth, uint8 pen, uint32 fontRes);
-void Init_text_bloc_system(void);
+typedef struct {
+ int16 x;
+ int16 y;
+ // RDSPR_ status bits - see defintion of _spriteInfo structure for
+ // correct size!
+ uint16 type;
+ mem *text_mem;
+} TextBloc;
-void Kill_text_bloc(uint32 bloc_number);
-void Print_text_blocs(void);
+typedef struct {
+ uint16 width; // width of line in pixels
+ uint16 length; // length of line in characters
+} LineInfo;
-uint32 Build_new_block(uint8 *ascii, int16 x, int16 y, uint16 width, uint8 pen, uint32 type, uint32 fontRes, uint8 justification);
+class FontRenderer {
+private:
+ TextBloc _blocList[MAX_text_blocs];
-#define DEFAULT_TEXT 0
-#define FINNISH_TEXT 1
-#define POLISH_TEXT 2
+ // layout variables - these used to be defines, but now we're dealing
+ // with 2 character sets
+
+ int8 _lineSpacing; // no. of pixels to separate lines of
+ // characters in the output sprite - negative
+ // for overlap
+ int8 _charSpacing; // no. of pixels to separate characters along
+ // each line - negative for overlap
+ uint8 _borderPen; // output pen colour of character borders
+
+ uint16 analyseSentence(uint8 *sentence, uint16 maxWidth, uint32 fontRes, LineInfo *line);
+ mem* buildTextSprite(uint8 *sentence, uint32 fontRes, uint8 pen, LineInfo *line, uint16 noOfLines);
+ uint16 charWidth(uint8 ch, uint32 fontRes);
+ uint16 charHeight(uint32 fontRes);
+ _frameHeader* findChar(uint8 ch, uint8 *charSet);
+ void copyChar(_frameHeader *charPtr, uint8 *spritePtr, uint16 spriteWidth, uint8 pen);
+
+public:
+ FontRenderer() {
+ for (int i = 0; i < MAX_text_blocs; i++)
+ _blocList[i].text_mem = NULL;
+ }
+
+ mem* makeTextSprite(uint8 *sentence, uint16 maxWidth, uint8 pen, uint32 fontRes, uint8 border = BORDER_PEN);
+
+ void killTextBloc(uint32 bloc_number);
+ void printTextBlocs(void);
+
+ uint32 buildNewBloc(uint8 *ascii, int16 x, int16 y, uint16 width, uint8 pen, uint32 type, uint32 fontRes, uint8 justification);
+};
+
+extern
// this one works out the language from the text cluster
-void InitialiseFontResourceFlags(void);
+void initialiseFontResourceFlags(void);
+
// this one allow you to select the fonts yourself
-void InitialiseFontResourceFlags(uint8 language);
+void initialiseFontResourceFlags(uint8 language);
-extern uint32 speech_font_id;
-extern uint32 controls_font_id;
-extern uint32 red_font_id;
+extern FontRenderer fontRenderer;
} // End of namespace Sword2
diff --git a/sword2/mouse.cpp b/sword2/mouse.cpp
index 9291efa7c5..c429baf6c4 100644
--- a/sword2/mouse.cpp
+++ b/sword2/mouse.cpp
@@ -1016,11 +1016,11 @@ void CreatePointerText(uint32 textId, uint32 pointerRes) {
// 'text+2' to skip the first 2 bytes which form the
// line reference number
- pointer_text_bloc_no = Build_new_block(
+ pointer_text_bloc_no = fontRenderer.buildNewBloc(
text + 2, mousex + xOffset, mousey + yOffset,
POINTER_TEXT_WIDTH, POINTER_TEXT_PEN,
RDSPR_TRANS | RDSPR_DISPLAYALIGN,
- speech_font_id, justification);
+ g_sword2->_speechFontId, justification);
// now ok to close the text file
res_man.close(text_res);
@@ -1030,7 +1030,7 @@ void CreatePointerText(uint32 textId, uint32 pointerRes) {
void ClearPointerText(void) {
if (pointer_text_bloc_no) {
- Kill_text_bloc(pointer_text_bloc_no);
+ fontRenderer.killTextBloc(pointer_text_bloc_no);
pointer_text_bloc_no = 0;
}
}
diff --git a/sword2/resman.cpp b/sword2/resman.cpp
index 5e3f523f7e..b6db4f0361 100644
--- a/sword2/resman.cpp
+++ b/sword2/resman.cpp
@@ -1149,7 +1149,7 @@ void ResourceManager::cacheNewCluster(uint32 newCluster) {
uint8 *loadingBar;
_cdtEntry *cdt;
- text_spr = MakeTextSprite(FetchTextLine(res_man.open(2283), 8) + 2, 640, 187, speech_font_id);
+ text_spr = fontRenderer.makeTextSprite(FetchTextLine(res_man.open(2283), 8) + 2, 640, 187, g_sword2->_speechFontId);
frame = (_frameHeader*) text_spr->ad;
@@ -1160,7 +1160,7 @@ void ResourceManager::cacheNewCluster(uint32 newCluster) {
textSprite.scale = 0;
textSprite.scaledWidth = 0;
textSprite.scaledHeight = 0;
- textSprite.type = RDSPR_DISPLAYALIGN + RDSPR_NOCOMPRESSION + RDSPR_TRANS;
+ textSprite.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION | RDSPR_TRANS;
textSprite.blend = 0;
textSprite.colourTable = 0;
@@ -1178,7 +1178,7 @@ void ResourceManager::cacheNewCluster(uint32 newCluster) {
barSprite.scale = 0;
barSprite.scaledWidth = 0;
barSprite.scaledHeight = 0;
- barSprite.type = RDSPR_RLE256FAST + RDSPR_TRANS;
+ barSprite.type = RDSPR_RLE256FAST | RDSPR_TRANS;
barSprite.blend = 0;
barSprite.colourTable = 0;
@@ -1375,7 +1375,7 @@ void ResourceManager::getCd(int cd) {
textRes = res_man.open(2283);
DisplayMsg(FetchTextLine(textRes, 5 + cd) + 2, 0);
- text_spr = MakeTextSprite(FetchTextLine(textRes, 5 + cd) + 2, 640, 187, speech_font_id);
+ text_spr = fontRenderer.makeTextSprite(FetchTextLine(textRes, 5 + cd) + 2, 640, 187, g_sword2->_speechFontId);
frame = (_frameHeader*) text_spr->ad;
@@ -1386,7 +1386,7 @@ void ResourceManager::getCd(int cd) {
spriteInfo.scale = 0;
spriteInfo.scaledWidth = 0;
spriteInfo.scaledHeight = 0;
- spriteInfo.type = RDSPR_DISPLAYALIGN + RDSPR_NOCOMPRESSION + RDSPR_TRANS;
+ spriteInfo.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION | RDSPR_TRANS;
spriteInfo.blend = 0;
spriteInfo.data = text_spr->ad + sizeof(_frameHeader);
spriteInfo.colourTable = 0;
diff --git a/sword2/speech.cpp b/sword2/speech.cpp
index 8c61702857..b09f46155d 100644
--- a/sword2/speech.cpp
+++ b/sword2/speech.cpp
@@ -1356,7 +1356,7 @@ int32 FN_i_speak(int32 *params) {
// if there is text
if (speech_text_bloc_no) {
// kill the text block
- Kill_text_bloc(speech_text_bloc_no);
+ fontRenderer.killTextBloc(speech_text_bloc_no);
speech_text_bloc_no = 0;
}
@@ -1547,10 +1547,11 @@ void Form_text(int32 *params) {
// 'text + 2' to skip the first 2 bytes which form the line
// reference number
- speech_text_bloc_no = Build_new_block(text + 2, text_x, text_y,
+ speech_text_bloc_no = fontRenderer.buildNewBloc(
+ text + 2, text_x, text_y,
textWidth, ob_speech->pen,
- RDSPR_TRANS | RDSPR_DISPLAYALIGN, speech_font_id,
- POSITION_AT_CENTRE_OF_BASE);
+ RDSPR_TRANS | RDSPR_DISPLAYALIGN,
+ g_sword2->_speechFontId, POSITION_AT_CENTRE_OF_BASE);
// now ok to close the text file
res_man.close(text_res);
diff --git a/sword2/startup.cpp b/sword2/startup.cpp
index c4bd03445a..623ff682e7 100644
--- a/sword2/startup.cpp
+++ b/sword2/startup.cpp
@@ -225,14 +225,14 @@ uint32 Con_start(uint8 *input) {
char *raw_data_ad;
uint32 null_pc;
- // so that typing 'S' then <enter> works on NT (James26feb97)
+ // so that typing 'S' then <enter> works on NT
if (input[0] == 0) {
Con_print_start_menu();
return 1;
}
while (input[j]) {
- if (input[j] >= '0' && input[j] <= '9')
+ if (isdigit(input[j]))
j++;
else
break;
@@ -276,15 +276,15 @@ uint32 Con_start(uint8 *input) {
// if there was speech text, kill the text block
if (speech_text_bloc_no) {
- Kill_text_bloc(speech_text_bloc_no);
- speech_text_bloc_no=0;
+ fontRenderer.killTextBloc(speech_text_bloc_no);
+ speech_text_bloc_no = 0;
}
// set the key
// Open George
- raw_data_ad = (char*) (res_man.open(8));
- raw_script = (char*) (res_man.open(start_list[start].start_res_id));
+ raw_data_ad = (char *) (res_man.open(8));
+ raw_script = (char *) (res_man.open(start_list[start].start_res_id));
// denotes script to run
null_pc = start_list[start].key & 0xffff;
diff --git a/sword2/sword2.cpp b/sword2/sword2.cpp
index 42e671762b..a143184369 100644
--- a/sword2/sword2.cpp
+++ b/sword2/sword2.cpp
@@ -157,8 +157,8 @@ int32 Sword2Engine::InitialiseGame(void) {
// Set up font resource variables for this language version
- debug(5, "CALLING: InitialiseFontResourceFlags");
- InitialiseFontResourceFlags();
+ debug(5, "CALLING: initialiseFontResourceFlags");
+ initialiseFontResourceFlags();
// set up the console system
@@ -172,11 +172,6 @@ int32 Sword2Engine::InitialiseGame(void) {
Init_start_menu();
#endif
- // no blocs live
-
- debug(5, "CALLING: Init_text_bloc_system");
- Init_text_bloc_system();
-
debug(5, "CALLING: Init_sync_system");
Init_sync_system();
diff --git a/sword2/sword2.h b/sword2/sword2.h
index 0e0fd28447..8d4da8fc3e 100644
--- a/sword2/sword2.h
+++ b/sword2/sword2.h
@@ -73,6 +73,10 @@ public:
Sound *_sound;
Common::RandomSource _rnd;
+ uint32 _speechFontId;
+ uint32 _controlsFontId;
+ uint32 _redFontId;
+
private:
bool _quit;
uint32 _bootParam;
@@ -80,6 +84,8 @@ private:
public:
void errorString(const char *buf_input, char *buf_output);
+ void initialiseFontResourceFlags(void);
+ void initialiseFontResourceFlags(uint8 language);
};
extern Sword2Engine *g_sword2;