1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * Additional copyright for this file:
8  * Copyright (C) 1994-1998 Revolution Software Ltd.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24 
25 // MAKETEXT	- Constructs a single-frame text sprite: returns a handle to a
26 //		  FLOATING memory block containing the sprite, given a
27 //		  null-terminated string, max width allowed, pen color and
28 //		  pointer to required character set.
29 //
30 //		  NB 1) The routine does not create a standard file header or
31 //		  an anim header for the text sprite - the data simply begins
32 //		  with the frame header.
33 //
34 //		  NB 2) If pen color is zero, it copies the characters into
35 //		  the sprite without remapping the colors.
36 //		  ie. It can handle both the standard 2-color font for speech
37 //		  and any multicolored fonts for control panels, etc.
38 //
39 //		  Based on textsprt.c as used for Broken Sword 1, but updated
40 //		  for new system by JEL on 9oct96 and updated again (for font
41 //		  as a resource) on 5dec96.
42 
43 
44 #include "common/system.h"
45 #include "common/textconsole.h"
46 
47 #include "sword2/sword2.h"
48 #include "sword2/defs.h"
49 #include "sword2/header.h"
50 #include "sword2/logic.h"
51 #include "sword2/maketext.h"
52 #include "sword2/resman.h"
53 #include "sword2/screen.h"
54 
55 namespace Sword2 {
56 
57 #define MAX_LINES	30	// max character lines in output sprite
58 
59 #define BORDER_COL	200	// source color for character border (only
60 						// needed for remapping colors)
61 
62 #define LETTER_COL	193	// source color for bulk of character ( " )
63 #define LETTER_COL_PSX1 33
64 #define LETTER_COL_PSX2 34
65 #define SPACE		' '
66 #define FIRST_CHAR	SPACE	// first character in character set
67 #define LAST_CHAR	255	// last character in character set
68 #define DUD		64	// the first "chequered flag" (dud) symbol in
69 				// our character set is in the '@' position
70 
71 /**
72  * This function creates a new text sprite. The sprite data contains a
73  * FrameHeader, but not a standard file header.
74  *
75  * @param  sentence  pointer to a null-terminated string
76  * @param  maxWidth  the maximum allowed text sprite width in pixels
77  * @param  pen       the text color, or zero to use the source colors
78  * @param  fontRes   the font resource id
79  * @param  border    the border color; black by default
80  * @return a handle to a floating memory block containing the text sprite
81  * @note   The sentence must contain no leading, trailing or extra spaces.
82  *         Out-of-range characters in the string are replaced by a special
83  *         error-signal character (chequered flag)
84  */
85 
makeTextSprite(const byte * sentence,uint16 maxWidth,uint8 pen,uint32 fontRes,uint8 border)86 byte *FontRenderer::makeTextSprite(const byte *sentence, uint16 maxWidth, uint8 pen, uint32 fontRes, uint8 border) {
87 	debug(5, "makeTextSprite(\"%s\", maxWidth=%u)", sentence, maxWidth);
88 
89 	_borderPen = border;
90 
91 	// Line- and character spacing are hard-wired, rather than being part
92 	// of the resource.
93 
94 	if (fontRes == _vm->_speechFontId) {
95 		if (Sword2Engine::isPsx())
96 			_lineSpacing = -4; // Text would be unreadable with psx font if linespacing is higher
97 		else
98 			_lineSpacing = -6;
99 		_charSpacing = -3;
100 	} else if (fontRes == CONSOLE_FONT_ID) {
101 		_lineSpacing = 0;
102 		_charSpacing = 1;
103 	} else {
104 		_lineSpacing = 0;
105 		_charSpacing = 0;
106 	}
107 
108 	// Allocate memory for array of lineInfo structures
109 
110 	byte *line = (byte *)malloc(MAX_LINES * sizeof(LineInfo));
111 
112 	// Get details of sentence breakdown into array of LineInfo structures
113 	// and get the number of lines involved
114 
115 	uint16 noOfLines = analyzeSentence(sentence, maxWidth, fontRes, (LineInfo *)line);
116 
117 	// Construct the sprite based on the info gathered - returns floating
118 	// mem block
119 
120 	byte *textSprite = buildTextSprite(sentence, fontRes, pen, (LineInfo *)line, noOfLines);
121 
122 	free(line);
123 	return textSprite;
124 }
125 
analyzeSentence(const byte * sentence,uint16 maxWidth,uint32 fontRes,LineInfo * line)126 uint16 FontRenderer::analyzeSentence(const byte *sentence, uint16 maxWidth, uint32 fontRes, LineInfo *line) {
127 	// joinWidth = how much extra space is needed to append a word to a
128 	// line. NB. SPACE requires TWICE the '_charSpacing' to join a word
129 	// to line
130 
131 	uint16 joinWidth = charWidth(SPACE, fontRes) + 2 * _charSpacing;
132 
133 	uint16 lineNo = 0;
134 	uint16 pos = 0;
135 	bool firstWord = true;
136 
137 	byte ch;
138 
139 	do {
140 		uint16 wordWidth = 0;
141 		uint16 wordLength = 0;
142 
143 		// Calculate the width of the word.
144 
145 		ch = sentence[pos++];
146 
147 		while (ch && ch != SPACE) {
148 			wordWidth += charWidth(ch, fontRes) + _charSpacing;
149 			wordLength++;
150 			ch = sentence[pos++];
151 		}
152 
153 		// Don't include any character spacing at the end of the word.
154 		wordWidth -= _charSpacing;
155 
156 		// 'ch' is now the SPACE or NULL following the word
157 		// 'pos' indexes to the position following 'ch'
158 
159 		if (firstWord) {
160 			// This is the first word on the line, so no separating
161 			// space is needed.
162 
163 			line[0].width = wordWidth;
164 			line[0].length = wordLength;
165 			firstWord = false;
166 		} else {
167 			// See how much extra space this word will need to
168 			// fit on current line (with a separating space
169 			// character - also overlapped)
170 
171 			uint16 spaceNeeded = joinWidth + wordWidth;
172 
173 			if (line[lineNo].width + spaceNeeded <= maxWidth) {
174 				// The word fits on this line.
175 				line[lineNo].width += spaceNeeded;
176 				line[lineNo].length += (1 + wordLength);
177 			} else {
178 				// The word spills over to the next line, i.e.
179 				// no separating space.
180 
181 				lineNo++;
182 
183 				assert(lineNo < MAX_LINES);
184 
185 				line[lineNo].width = wordWidth;
186 				line[lineNo].length = wordLength;
187 			}
188 		}
189 	} while (ch);
190 
191 	return lineNo + 1;
192 }
193 
194 /**
195  * This function creates a new text sprite in a movable memory block. It must
196  * be locked before use, i.e. lock, draw sprite, unlock/free. The sprite data
197  * contains a FrameHeader, but not a standard file header.
198  *
199  * @param  sentence  pointer to a null-terminated string
200  * @param  fontRes   the font resource id
201  * @param  pen       the text color, or zero to use the source colors
202  * @param  line      array of LineInfo structures, created by analyzeSentence()
203  * @param  noOfLines the number of lines, i.e. the number of elements in 'line'
204  * @return a handle to a floating memory block containing the text sprite
205  * @note   The sentence must contain no leading, trailing or extra spaces.
206  *         Out-of-range characters in the string are replaced by a special
207  *         error-signal character (chequered flag)
208  */
209 
buildTextSprite(const byte * sentence,uint32 fontRes,uint8 pen,LineInfo * line,uint16 noOfLines)210 byte *FontRenderer::buildTextSprite(const byte *sentence, uint32 fontRes, uint8 pen, LineInfo *line, uint16 noOfLines) {
211 	uint16 i;
212 
213 	// Find the width of the widest line in the output text
214 
215 	uint16 spriteWidth = 0;
216 
217 	for (i = 0; i < noOfLines; i++)
218 		if (line[i].width > spriteWidth)
219 			spriteWidth = line[i].width;
220 
221 
222 	// Check that text sprite has even horizontal resolution in PSX version
223 	// (needed to work around a problem in some sprites, which reports an odd
224 	// number as horiz resolution, but then have the next even number as true width)
225 	if (Sword2Engine::isPsx())
226 		spriteWidth = (spriteWidth % 2) ? spriteWidth + 1 : spriteWidth;
227 
228 	// Find the total height of the text sprite: the total height of the
229 	// text lines, plus the total height of the spacing between them.
230 
231 	uint16 char_height = charHeight(fontRes);
232 	uint16 spriteHeight = char_height * noOfLines + _lineSpacing * (noOfLines - 1);
233 
234 	// Allocate memory for the text sprite
235 
236 	uint32 sizeOfSprite = spriteWidth * spriteHeight;
237 	byte *textSprite = (byte *)malloc(FrameHeader::size() + sizeOfSprite);
238 
239 	// At this stage, textSprite points to an unmovable memory block. Set
240 	// up the frame header.
241 
242 	FrameHeader frame_head;
243 
244 	frame_head.compSize = 0;
245 	frame_head.width = spriteWidth;
246 	frame_head.height = spriteHeight;
247 
248 	// Normally for PSX frame header we double the height
249 	// of the sprite artificially to regain correct aspect
250 	// ratio, but this is an "artificially generated" text
251 	// sprite, which gets created with correct aspect, so
252 	// fix the height.
253 	if (Sword2Engine::isPsx())
254 		frame_head.height /= 2;
255 
256 	frame_head.write(textSprite);
257 
258 	debug(4, "Text sprite size: %ux%u", spriteWidth, spriteHeight);
259 
260 	// Clear the entire sprite to make it transparent.
261 
262 	byte *linePtr = textSprite + FrameHeader::size();
263 	memset(linePtr, 0, sizeOfSprite);
264 
265 	byte *charSet = _vm->_resman->openResource(fontRes);
266 
267 	// Build the sprite, one line at a time
268 
269 	uint16 pos = 0;
270 
271 	for (i = 0; i < noOfLines; i++) {
272 		// Center each line
273 		byte *spritePtr = linePtr + (spriteWidth - line[i].width) / 2;
274 
275 		// copy the sprite for each character in this line to the
276 		// text sprite and inc the sprite ptr by the character's
277 		// width minus the 'overlap'
278 
279 		for (uint j = 0; j < line[i].length; j++) {
280 			byte *charPtr = findChar(sentence[pos++], charSet);
281 
282 			frame_head.read(charPtr);
283 
284 			assert(frame_head.height == char_height);
285 			copyChar(charPtr, spritePtr, spriteWidth, pen);
286 
287 			// We must remember to free memory for generated character in psx,
288 			// as it is extracted differently than pc version (copyed from a
289 			// char atlas).
290 			if (Sword2Engine::isPsx())
291 				free(charPtr);
292 
293 			spritePtr += frame_head.width + _charSpacing;
294 		}
295 
296 		// Skip space at end of last word in this line
297 		pos++;
298 
299 		if (Sword2Engine::isPsx())
300 			linePtr += (char_height / 2 + _lineSpacing) * spriteWidth;
301 		else
302 			linePtr += (char_height + _lineSpacing) * spriteWidth;
303 	}
304 
305 	_vm->_resman->closeResource(fontRes);
306 
307 	return textSprite;
308 }
309 
310 /**
311  * @param  ch      the ASCII code of the character
312  * @param  fontRes the font resource id
313  * @return the width of the character
314  */
315 
charWidth(byte ch,uint32 fontRes)316 uint16 FontRenderer::charWidth(byte ch, uint32 fontRes) {
317 	byte *charSet = _vm->_resman->openResource(fontRes);
318 	byte *charBuf;
319 
320 	FrameHeader frame_head;
321 
322 	charBuf = findChar(ch, charSet);
323 
324 	frame_head.read(charBuf);
325 
326 	if (Sword2Engine::isPsx())
327 		free(charBuf);
328 
329 	_vm->_resman->closeResource(fontRes);
330 
331 	return frame_head.width;
332 }
333 
334 /**
335  * @param  fontRes the font resource id
336  * @return the height of a character sprite
337  * @note   All characters in a font are assumed to have the same height, so
338  *         there is no need to specify which one to look at.
339  */
340 
341 // Returns the height of a character sprite, given the character's ASCII code
342 // and a pointer to the start of the character set.
343 
charHeight(uint32 fontRes)344 uint16 FontRenderer::charHeight(uint32 fontRes) {
345 	byte *charSet = _vm->_resman->openResource(fontRes);
346 	byte *charbuf;
347 
348 	FrameHeader frame_head;
349 
350 	charbuf = findChar(FIRST_CHAR, charSet);
351 
352 	frame_head.read(charbuf);
353 
354 	if (Sword2Engine::isPsx())
355 		free(charbuf);
356 
357 	_vm->_resman->closeResource(fontRes);
358 
359 	return frame_head.height;
360 }
361 
362 /**
363  * @param  ch      the ASCII code of the character to find
364  * @param  charSet pointer to the start of the character set
365  * @return pointer to the requested character or, if it's out of range, the
366  *         'dud' character (chequered flag)
367  */
368 
findChar(byte ch,byte * charSet)369 byte *FontRenderer::findChar(byte ch, byte *charSet) {
370 
371 	// PSX version doesn't use an animation table to keep all letters,
372 	// instead a big sprite (char atlas) is used, and the single char
373 	// must be extracted from that.
374 
375 	if (Sword2Engine::isPsx()) {
376 		byte *buffer;
377 		PSXFontEntry header;
378 		FrameHeader bogusHeader;
379 
380 		charSet += ResHeader::size() + 2;
381 
382 		if (ch < FIRST_CHAR)
383 			ch = DUD;
384 
385 		// Read font entry of the corresponding char.
386 		header.read(charSet + PSXFontEntry::size() * (ch - 32));
387 
388 		// We have no such character, generate an empty one
389 		// on the fly, size 6x12.
390 		if (header.charWidth == 0) {
391 
392 			// Prepare a "bogus" FrameHeader to be returned with
393 			// "empty" character data.
394 			bogusHeader.compSize = 0;
395 			bogusHeader.width = 6;
396 			bogusHeader.height = 12;
397 
398 			buffer = (byte *)malloc(24 * 3 + FrameHeader::size());
399 			memset(buffer, 0, 24 * 3 + FrameHeader::size());
400 			bogusHeader.write(buffer);
401 
402 			return buffer;
403 		}
404 
405 		buffer = (byte *)malloc(FrameHeader::size() + header.charWidth * header.charHeight * 4);
406 		byte *tempchar = (byte *)malloc(header.charWidth * header.charHeight);
407 
408 		// Prepare the "bogus" header to be returned with character
409 		bogusHeader.compSize = 0;
410 		bogusHeader.width = header.charWidth * 2;
411 		bogusHeader.height = header.charHeight;
412 
413 		// Go to the beginning of char atlas
414 		charSet += 2062;
415 
416 		memset(buffer, 0, FrameHeader::size() + header.charWidth * header.charHeight * 4);
417 
418 		bogusHeader.write(buffer);
419 
420 		// Copy and stretch the char into destination buffer
421 		for (int idx = 0; idx < header.charHeight; idx++) {
422 			memcpy(tempchar + header.charWidth * idx, charSet + header.offset + 128 * (header.skipLines + idx), header.charWidth);
423 		}
424 
425 		for (int line = 0; line < header.charHeight; line++) {
426 			for (int col = 0; col < header.charWidth; col++) {
427 				*(buffer + FrameHeader::size() + line * bogusHeader.width + col * 2) = *(tempchar + line * header.charWidth + col);
428 				*(buffer + FrameHeader::size() + line * bogusHeader.width + col * 2 + 1) = *(tempchar + line * header.charWidth + col);
429 			}
430 		}
431 
432 		free(tempchar);
433 
434 		return buffer;
435 
436 	} else {
437 		if (ch < FIRST_CHAR)
438 			ch = DUD;
439 		return _vm->fetchFrameHeader(charSet, ch - FIRST_CHAR);
440 	}
441 }
442 
443 /**
444  * Copies a character sprite to the sprite buffer.
445  * @param charPtr     pointer to the character sprite
446  * @param spritePtr   pointer to the sprite buffer
447  * @param spriteWidth the width of the character
448  * @param pen         If zero, copy the data directly. Otherwise remap the
449  *                    sprite's colors from BORDER_COL to _borderPen and from
450  *                    LETTER_COL to pen.
451  */
452 
copyChar(byte * charPtr,byte * spritePtr,uint16 spriteWidth,uint8 pen)453 void FontRenderer::copyChar(byte *charPtr, byte *spritePtr, uint16 spriteWidth, uint8 pen) {
454 	FrameHeader frame;
455 
456 	frame.read(charPtr);
457 
458 	byte *source = charPtr + FrameHeader::size();
459 	byte *rowPtr = spritePtr;
460 
461 	for (uint i = 0; i < frame.height; i++) {
462 		byte *dest = rowPtr;
463 
464 		if (pen) {
465 			// Use the specified colors
466 			for (uint j = 0; j < frame.width; j++) {
467 				switch (*source++) {
468 				case 0:
469 					// Do nothing if source pixel is zero,
470 					// ie. transparent
471 					break;
472 				case LETTER_COL_PSX1: // Values for colored zone
473 				case LETTER_COL_PSX2:
474 				case LETTER_COL:
475 					*dest = pen;
476 					break;
477 				case BORDER_COL:
478 				default:
479 					// Don't do a border pixel if there's
480 					// already a bit of another character
481 					// underneath (for overlapping!)
482 					if (!*dest)
483 						*dest = _borderPen;
484 					break;
485 				}
486 				dest++;
487 			}
488 		} else {
489 			// Pen is zero, so just copy character sprites
490 			// directly into text sprite without remapping colors.
491 			// Apparently overlapping is never considered here?
492 			memcpy(dest, source, frame.width);
493 			source += frame.width;
494 		}
495 		rowPtr += spriteWidth;
496 	}
497 }
498 
499 // Distance to keep speech text from edges of screen
500 #define TEXT_MARGIN 12
501 
502 /**
503  * Creates a text bloc in the list and returns the bloc number. The list of
504  * blocs is read and blitted at render time. Choose alignment type
505  * RDSPR_DISPLAYALIGN or 0
506  */
507 
buildNewBloc(byte * ascii,int16 x,int16 y,uint16 width,uint8 pen,uint32 type,uint32 fontRes,uint8 justification)508 uint32 FontRenderer::buildNewBloc(byte *ascii, int16 x, int16 y, uint16 width, uint8 pen, uint32 type, uint32 fontRes, uint8 justification) {
509 	uint32 i = 0;
510 
511 	while (i < MAX_text_blocs && _blocList[i].text_mem)
512 		i++;
513 
514 	assert(i < MAX_text_blocs);
515 
516 	// Create and position the sprite
517 
518 	_blocList[i].text_mem = makeTextSprite(ascii, width, pen, fontRes);
519 
520 	// 'NO_JUSTIFICATION' means print sprite with top-left at (x,y)
521 	// without margin checking - used for debug text
522 
523 	if (justification != NO_JUSTIFICATION) {
524 		FrameHeader frame_head;
525 
526 		frame_head.read(_blocList[i].text_mem);
527 
528 		switch (justification) {
529 		case POSITION_AT_CENTER_OF_BASE:
530 			// This one is always used for SPEECH TEXT; possibly
531 			// also for pointer text
532 			x -= (frame_head.width / 2);
533 			y -= frame_head.height;
534 			break;
535 		case POSITION_AT_CENTER_OF_TOP:
536 			x -= (frame_head.width / 2);
537 			break;
538 		case POSITION_AT_LEFT_OF_TOP:
539 			// The given coords are already correct for this!
540 			break;
541 		case POSITION_AT_RIGHT_OF_TOP:
542 			x -= frame_head.width;
543 			break;
544 		case POSITION_AT_LEFT_OF_BASE:
545 			y -= frame_head.height;
546 			break;
547 		case POSITION_AT_RIGHT_OF_BASE:
548 			x -= frame_head.width;
549 			y -= frame_head.height;
550 			break;
551 		case POSITION_AT_LEFT_OF_CENTER:
552 			y -= (frame_head.height / 2);
553 			break;
554 		case POSITION_AT_RIGHT_OF_CENTER:
555 			x -= frame_head.width;
556 			y -= (frame_head.height) / 2;
557 			break;
558 		}
559 
560 		// Ensure text sprite is a few pixels inside the visible screen
561 		// remember - it's RDSPR_DISPLAYALIGN
562 
563 		uint16 text_left_margin = TEXT_MARGIN;
564 		uint16 text_right_margin = 640 - TEXT_MARGIN - frame_head.width;
565 		uint16 text_top_margin = TEXT_MARGIN;
566 		uint16 text_bottom_margin = 400 - TEXT_MARGIN - frame_head.height;
567 
568 		// Move if too far left or too far right
569 
570 		if (x < text_left_margin)
571 			x = text_left_margin;
572 		else if (x > text_right_margin)
573 			x = text_right_margin;
574 
575 		// Move if too high or too low
576 
577 		if (y < text_top_margin)
578 			y = text_top_margin;
579 		else if (y > text_bottom_margin)
580 			y = text_bottom_margin;
581 	}
582 
583 	// The sprite is always uncompressed
584 	_blocList[i].type = type | RDSPR_NOCOMPRESSION;
585 
586 	_blocList[i].x = x;
587 	_blocList[i].y = y;
588 
589 	return i + 1;
590 }
591 
592 /**
593  * Called by buildDisplay()
594  */
595 
printTextBlocs()596 void FontRenderer::printTextBlocs() {
597 	for (uint i = 0; i < MAX_text_blocs; i++) {
598 		if (_blocList[i].text_mem) {
599 			FrameHeader frame_head;
600 			SpriteInfo spriteInfo;
601 
602 			frame_head.read(_blocList[i].text_mem);
603 
604 			spriteInfo.x = _blocList[i].x;
605 			spriteInfo.y = _blocList[i].y;
606 			spriteInfo.w = frame_head.width;
607 			spriteInfo.h = frame_head.height;
608 			spriteInfo.scale = 0;
609 			spriteInfo.scaledWidth = 0;
610 			spriteInfo.scaledHeight = 0;
611 			spriteInfo.type = _blocList[i].type;
612 			spriteInfo.blend = 0;
613 			spriteInfo.data = _blocList[i].text_mem + FrameHeader::size();
614 			spriteInfo.colorTable = 0;
615 			spriteInfo.isText = true;
616 
617 			uint32 rv = _vm->_screen->drawSprite(&spriteInfo);
618 			if (rv)
619 				error("Driver Error %.8x in printTextBlocs", rv);
620 		}
621 	}
622 }
623 
killTextBloc(uint32 bloc_number)624 void FontRenderer::killTextBloc(uint32 bloc_number) {
625 	bloc_number--;
626 	free(_blocList[bloc_number].text_mem);
627 	_blocList[bloc_number].text_mem = NULL;
628 }
629 
630 // Resource 3258 contains text from location script for 152 (install, save &
631 // restore text, etc)
632 
633 #define TEXT_RES	3258
634 
635 // Local line number of "save" (actor no. 1826)
636 
637 #define SAVE_LINE_NO	1
638 
initializeFontResourceFlags()639 void Sword2Engine::initializeFontResourceFlags() {
640 	byte *textFile = _resman->openResource(TEXT_RES);
641 
642 	// If language is Polish or Finnish it requires alternate fonts.
643 	// Otherwise, use regular fonts
644 
645 	// "tallenna"   Finnish for "save"
646 	// "zapisz"     Polish for "save"
647 
648 	// Get the text line (& skip the 2 chars containing the wavId)
649 	char *textLine = (char *)fetchTextLine(textFile, SAVE_LINE_NO) + 2;
650 
651 	if (strcmp(textLine, "tallenna") == 0)
652 		initializeFontResourceFlags(FINNISH_TEXT);
653 	else if (strcmp(textLine, "zapisz") == 0)
654 		initializeFontResourceFlags(POLISH_TEXT);
655 	else
656 		initializeFontResourceFlags(DEFAULT_TEXT);
657 
658 	// Get the game name for the windows application
659 
660 	// According to the GetGameName(), which was never called and has
661 	// therefore been removed, the name of the game is:
662 	//
663 	// ENGLISH:  "Broken Sword II"
664 	// AMERICAN: "Circle of Blood II"
665 	// GERMAN:   "Baphomet's Fluch II"
666 	// default:  "Some game or other, part 86"
667 	//
668 	// But we get it from the text resource instead.
669 
670 	if (_logic->readVar(DEMO))
671 		textLine = (char *)fetchTextLine(textFile, 451) + 2;
672 	else
673 		textLine = (char *)fetchTextLine(textFile, 54) + 2;
674 
675 	_system->setWindowCaption(textLine);
676 	_resman->closeResource(TEXT_RES);
677 }
678 
679 /**
680  * Called from initializeFontResourceFlags(), and also from console.cpp
681  */
682 
initializeFontResourceFlags(uint8 language)683 void Sword2Engine::initializeFontResourceFlags(uint8 language) {
684 	switch (language) {
685 	case FINNISH_TEXT:
686 		_speechFontId = FINNISH_SPEECH_FONT_ID;
687 		_controlsFontId = FINNISH_CONTROLS_FONT_ID;
688 		_redFontId = FINNISH_RED_FONT_ID;
689 		break;
690 	case POLISH_TEXT:
691 		_speechFontId = POLISH_SPEECH_FONT_ID;
692 		_controlsFontId = POLISH_CONTROLS_FONT_ID;
693 		_redFontId = POLISH_RED_FONT_ID;
694 		break;
695 	default:
696 		_speechFontId = ENGLISH_SPEECH_FONT_ID;
697 		_controlsFontId = ENGLISH_CONTROLS_FONT_ID;
698 		_redFontId = ENGLISH_RED_FONT_ID;
699 		break;
700 	}
701 }
702 
703 } // End of namespace Sword2
704