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  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "hopkins/talk.h"
24 
25 #include "hopkins/files.h"
26 #include "hopkins/globals.h"
27 #include "hopkins/graphics.h"
28 #include "hopkins/hopkins.h"
29 #include "hopkins/objects.h"
30 
31 #include "common/system.h"
32 #include "common/endian.h"
33 #include "common/file.h"
34 #include "common/textconsole.h"
35 
36 namespace Hopkins {
37 
TalkManager(HopkinsEngine * vm)38 TalkManager::TalkManager(HopkinsEngine *vm) {
39 	_vm = vm;
40 	_characterBuffer = NULL;
41 	_characterPalette = NULL;
42 	_characterSprite = NULL;
43 	_characterAnim = NULL;
44 	_characterSize = 0;
45 	_dialogueMesgId1 = _dialogueMesgId2 = _dialogueMesgId3 = _dialogueMesgId4 = 0;
46 	_paletteBufferIdx = 0;
47 }
48 
startAnimatedCharacterDialogue(const Common::String & filename)49 void TalkManager::startAnimatedCharacterDialogue(const Common::String &filename) {
50 	Common::String spriteFilename;
51 
52 	_vm->_fontMan->hideText(5);
53 	_vm->_fontMan->hideText(9);
54 	_vm->_events->refreshScreenAndEvents();
55 	_vm->_graphicsMan->_scrollStatus = 1;
56 	bool oldDisableInventFl = _vm->_globals->_disableInventFl;
57 	_vm->_globals->_disableInventFl = true;
58 	bool fileFoundFl = false;
59 	_characterBuffer = _vm->_fileIO->searchCat(filename, RES_PER, fileFoundFl);
60 	_characterSize = _vm->_fileIO->_catalogSize;
61 	if (!fileFoundFl) {
62 		_characterBuffer = _vm->_fileIO->loadFile(filename);
63 		_characterSize = _vm->_fileIO->fileSize(filename);
64 	}
65 
66 	_vm->_globals->_saveData->_data[svDialogField4] = 0;
67 
68 	getStringFromBuffer(40, spriteFilename, (const char *)_characterBuffer);
69 	getStringFromBuffer(0, _questionsFilename, (const char *)_characterBuffer);
70 	getStringFromBuffer(20, _answersFilename, (const char *)_characterBuffer);
71 
72 	switch (_vm->_globals->_language) {
73 	case LANG_FR:
74 		_answersFilename = _questionsFilename = "RUE.TXT";
75 		break;
76 	case LANG_EN:
77 		_answersFilename = _questionsFilename = "RUEAN.TXT";
78 		break;
79 	case LANG_SP:
80 		_answersFilename = _questionsFilename = "RUEES.TXT";
81 		break;
82 	default:
83 		break;
84 	}
85 	_dialogueMesgId1 = READ_LE_INT16((uint16 *)_characterBuffer + 40);
86 	_paletteBufferIdx = 20 * READ_LE_INT16((uint16 *)_characterBuffer + 42) + 110;
87 	fileFoundFl = false;
88 	_characterSprite = _vm->_fileIO->searchCat(spriteFilename, RES_SAN, fileFoundFl);
89 	if (!fileFoundFl) {
90 		_characterSprite = _vm->_objectsMan->loadSprite(spriteFilename);
91 	} else {
92 		_characterSprite = _vm->_objectsMan->loadSprite("RES_SAN.RES");
93 	}
94 
95 	_vm->_graphicsMan->backupScreen();
96 
97 	if (!_vm->_graphicsMan->_lineNbr)
98 		_vm->_graphicsMan->_scrollOffset = 0;
99 	_vm->_graphicsMan->displayScreen(true);
100 	_vm->_objectsMan->_charactersEnabledFl = true;
101 	searchCharacterPalette(_paletteBufferIdx, false);
102 	startCharacterAnim0(_paletteBufferIdx, false);
103 	initCharacterAnim();
104 	_dialogueMesgId2 = _dialogueMesgId1 + 1;
105 	_dialogueMesgId3 = _dialogueMesgId1 + 2;
106 	_dialogueMesgId4 = _dialogueMesgId1 + 3;
107 	int oldMouseCursorId = _vm->_events->_mouseCursorId;
108 	_vm->_events->_mouseCursorId = 4;
109 	_vm->_events->changeMouseCursor(0);
110 	if (!_vm->_globals->_introSpeechOffFl) {
111 		int answer = 0;
112 		int dlgAnswer;
113 		do {
114 			dlgAnswer = dialogQuestion(false);
115 			if (dlgAnswer != _dialogueMesgId4)
116 				answer = dialogAnswer(dlgAnswer, false);
117 			if (answer == -1)
118 				dlgAnswer = _dialogueMesgId4;
119 			_vm->_events->refreshScreenAndEvents();
120 		} while (dlgAnswer != _dialogueMesgId4);
121 	}
122 	if (_vm->_globals->_introSpeechOffFl) {
123 		int idx = 1;
124 		int answer;
125 		do {
126 			answer = dialogAnswer(idx++, false);
127 		} while (answer != -1);
128 	}
129 	clearCharacterAnim();
130 	_vm->_globals->_introSpeechOffFl = false;
131 	_characterBuffer = _vm->_globals->freeMemory(_characterBuffer);
132 	_characterSprite = _vm->_globals->freeMemory(_characterSprite);
133 	_vm->_graphicsMan->displayScreen(false);
134 
135 	_vm->_graphicsMan->restoreScreen();
136 
137 	_vm->_objectsMan->_charactersEnabledFl = false;
138 	_vm->_events->_mouseCursorId = oldMouseCursorId;
139 
140 	_vm->_events->changeMouseCursor(oldMouseCursorId);
141 	_vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
142 
143 	if (_vm->getIsDemo() == false)
144 		_vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
145 
146 	_vm->_graphicsMan->initColorTable(145, 150, _vm->_graphicsMan->_palette);
147 	_vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
148 	_vm->_graphicsMan->display8BitRect(_vm->_graphicsMan->_backBuffer, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
149 	memcpy(_vm->_graphicsMan->_frontBuffer, _vm->_graphicsMan->_backBuffer, 614399);
150 	_vm->_globals->_disableInventFl = oldDisableInventFl;
151 	_vm->_graphicsMan->updateScreen();
152 	for (int i = 0; i <= 4; i++)
153 		_vm->_events->refreshScreenAndEvents();
154 	_vm->_graphicsMan->_scrollStatus = 0;
155 }
156 
startStaticCharacterDialogue(const Common::String & filename)157 void TalkManager::startStaticCharacterDialogue(const Common::String &filename) {
158 	// TODO: The original disables the mouse cursor here
159 	bool oldDisableInventFl = _vm->_globals->_disableInventFl;
160 	_vm->_globals->_disableInventFl = true;
161 	bool fileFoundFl = false;
162 	_characterBuffer = _vm->_fileIO->searchCat(filename, RES_PER, fileFoundFl);
163 	_characterSize = _vm->_fileIO->_catalogSize;
164 	if (!fileFoundFl) {
165 		_characterBuffer = _vm->_fileIO->loadFile(filename);
166 		_characterSize = _vm->_fileIO->fileSize(filename);
167 	}
168 
169 	_vm->_globals->_saveData->_data[svDialogField4] = 0;
170 
171 	getStringFromBuffer(0, _questionsFilename, (const char *)_characterBuffer);
172 	getStringFromBuffer(20, _answersFilename, (const char *)_characterBuffer);
173 
174 	switch (_vm->_globals->_language) {
175 	case LANG_EN:
176 		_questionsFilename = "RUEAN.TXT";
177 		_answersFilename = "RUEAN.TXT";
178 		break;
179 	case LANG_FR:
180 		_questionsFilename = "RUE.TXT";
181 		_answersFilename = "RUE.TXT";
182 		break;
183 	case LANG_SP:
184 		_questionsFilename = "RUEES.TXT";
185 		_answersFilename = "RUEES.TXT";
186 		break;
187 	default:
188 		break;
189 	}
190 
191 	_dialogueMesgId1 = READ_LE_INT16((uint16 *)_characterBuffer + 40);
192 	_paletteBufferIdx = 20 * READ_LE_INT16((uint16 *)_characterBuffer + 42) + 110;
193 	searchCharacterPalette(_paletteBufferIdx, false);
194 	_dialogueMesgId2 = _dialogueMesgId1 + 1;
195 	_dialogueMesgId3 = _dialogueMesgId1 + 2;
196 	_dialogueMesgId4 = _dialogueMesgId1 + 3;
197 	int oldMouseCursorId = _vm->_events->_mouseCursorId;
198 	_vm->_events->_mouseCursorId = 4;
199 	_vm->_events->changeMouseCursor(0);
200 
201 	if (!_vm->_globals->_introSpeechOffFl) {
202 		int answer;
203 		do {
204 			answer = dialogQuestion(true);
205 			if (answer != _dialogueMesgId4) {
206 				if (dialogAnswer(answer, true) == -1)
207 					answer = _dialogueMesgId4;
208 			}
209 		} while (answer != _dialogueMesgId4);
210 	}
211 
212 	if (_vm->_globals->_introSpeechOffFl) {
213 		int idx = 1;
214 		int answer;
215 		do {
216 			answer = dialogAnswer(idx++, true);
217 		} while (answer != -1);
218 	}
219 
220 	_characterBuffer = _vm->_globals->freeMemory(_characterBuffer);
221 	_vm->_events->_mouseCursorId = oldMouseCursorId;
222 
223 	_vm->_events->changeMouseCursor(oldMouseCursorId);
224 	_vm->_graphicsMan->initColorTable(145, 150, _vm->_graphicsMan->_palette);
225 	_vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
226 	// TODO: The original re-enables the mouse cursor here
227 	_vm->_globals->_disableInventFl = oldDisableInventFl;
228 }
229 
getStringFromBuffer(int srcStart,Common::String & dest,const char * srcData)230 void TalkManager::getStringFromBuffer(int srcStart, Common::String &dest, const char *srcData) {
231 	dest = Common::String(srcData + srcStart);
232 }
233 
dialogQuestion(bool animatedFl)234 int TalkManager::dialogQuestion(bool animatedFl) {
235 	if (animatedFl) {
236 		uint16 *bufPtr = (uint16 *)_characterBuffer + 48;
237 		int curVal = READ_LE_INT16(bufPtr);
238 		if (curVal != 0)
239 			_vm->_objectsMan->setBobAnimation(curVal);
240 		if (curVal != 1)
241 			_vm->_objectsMan->setBobAnimation(READ_LE_INT16(bufPtr + 1));
242 		if (curVal != 2)
243 			_vm->_objectsMan->setBobAnimation(READ_LE_INT16(bufPtr + 2));
244 		if (curVal != 3)
245 			_vm->_objectsMan->setBobAnimation(READ_LE_INT16(bufPtr + 3));
246 		if (curVal != 4)
247 			_vm->_objectsMan->setBobAnimation(READ_LE_INT16(bufPtr + 4));
248 	} else {
249 		dialogWait();
250 	}
251 
252 	int sentence1LineNumb = countBoxLines(_dialogueMesgId1, _questionsFilename);
253 	int sentence2LineNumb = countBoxLines(_dialogueMesgId2, _questionsFilename);
254 	int sentence3LineNumb = countBoxLines(_dialogueMesgId3, _questionsFilename);
255 	int sentence4LineNumb = countBoxLines(_dialogueMesgId4, _questionsFilename);
256 
257 	int sentence4PosY = 420 - 20 * sentence4LineNumb;
258 	int sentence3PosY = sentence4PosY - 20 * sentence3LineNumb;
259 	int sentence2PosY = sentence3PosY - 20 * sentence2LineNumb;
260 	int sentence1PosY = sentence2PosY - 20 * sentence1LineNumb;
261 
262 	_vm->_fontMan->initTextBuffers(5, _dialogueMesgId1, _questionsFilename, 5, sentence1PosY, 0, 65, 255);
263 	_vm->_fontMan->initTextBuffers(6, _dialogueMesgId2, _questionsFilename, 5, sentence2PosY, 0, 65, 255);
264 	_vm->_fontMan->initTextBuffers(7, _dialogueMesgId3, _questionsFilename, 5, sentence3PosY, 0, 65, 255);
265 	_vm->_fontMan->initTextBuffers(8, _dialogueMesgId4, _questionsFilename, 5, sentence4PosY, 0, 65, 255);
266 	_vm->_fontMan->showText(5);
267 	_vm->_fontMan->showText(6);
268 	_vm->_fontMan->showText(7);
269 	_vm->_fontMan->showText(8);
270 
271 	int retVal = -1;
272 	bool loopCond = false;
273 	do {
274 		int mousePosY = _vm->_events->getMouseY();
275 		if (sentence1PosY < mousePosY && mousePosY < (sentence2PosY - 1)) {
276 			_vm->_fontMan->setOptimalColor(6, 7, 8, 5);
277 			retVal = _dialogueMesgId1;
278 		}
279 		if (sentence2PosY < mousePosY && mousePosY < (sentence3PosY - 1)) {
280 			_vm->_fontMan->setOptimalColor(5, 7, 8, 6);
281 			retVal = _dialogueMesgId2;
282 		}
283 		if (sentence3PosY < mousePosY && mousePosY < (sentence4PosY - 1)) {
284 			_vm->_fontMan->setOptimalColor(5, 6, 8, 7);
285 			retVal = _dialogueMesgId3;
286 		}
287 		if (sentence4PosY < mousePosY && mousePosY < 419) {
288 			_vm->_fontMan->setOptimalColor(5, 6, 7, 8);
289 			retVal = _dialogueMesgId4;
290 		}
291 
292 		_vm->_events->refreshScreenAndEvents();
293 		if (_vm->_events->getMouseButton())
294 			loopCond = true;
295 		if (retVal == -1)
296 			loopCond = false;
297 	} while (!_vm->shouldQuit() && !loopCond);
298 
299 	_vm->_soundMan->mixVoice(retVal, 1);
300 	_vm->_fontMan->hideText(5);
301 	_vm->_fontMan->hideText(6);
302 	_vm->_fontMan->hideText(7);
303 	_vm->_fontMan->hideText(8);
304 
305 	if (animatedFl) {
306 		uint16 *bufPtr = (uint16 *)_characterBuffer + 48;
307 
308 		int curVal = READ_LE_INT16(bufPtr);
309 		if (curVal != 0)
310 			_vm->_objectsMan->stopBobAnimation(curVal);
311 
312 		curVal = READ_LE_INT16(bufPtr + 1);
313 		if (curVal != 1)
314 			_vm->_objectsMan->stopBobAnimation(curVal);
315 
316 		curVal = READ_LE_INT16(bufPtr + 2);
317 		if (curVal != 2)
318 			_vm->_objectsMan->stopBobAnimation(curVal);
319 
320 		curVal = READ_LE_INT16(bufPtr + 3);
321 		if (curVal != 3)
322 			_vm->_objectsMan->stopBobAnimation(curVal);
323 
324 		curVal = READ_LE_INT16(bufPtr + 4);
325 		if (curVal != 4)
326 			_vm->_objectsMan->stopBobAnimation(curVal);
327 	} else {
328 		dialogTalk();
329 	}
330 
331 	_vm->_events->refreshScreenAndEvents();
332   return retVal;
333 }
334 
dialogAnswer(int idx,bool animatedFl)335 int TalkManager::dialogAnswer(int idx, bool animatedFl) {
336 	int charIdx;
337 	byte *charBuf;
338 	for (charBuf = _characterBuffer + 110, charIdx = 0; READ_LE_INT16(charBuf) != idx; charBuf += 20) {
339 		++charIdx;
340 		if (READ_LE_INT16((uint16 *)_characterBuffer + 42) < charIdx)
341 			return -1;
342 	}
343 
344 	int mesgId = READ_LE_INT16((uint16 *)charBuf + 1);
345 	int mesgPosX = READ_LE_INT16((uint16 *)charBuf + 2);
346 	int mesgPosY = READ_LE_INT16((uint16 *)charBuf + 3);
347 	int mesgLength = READ_LE_INT16((uint16 *)charBuf + 4);
348 	_dialogueMesgId1 = READ_LE_INT16((uint16 *)charBuf + 5);
349 	_dialogueMesgId2 = READ_LE_INT16((uint16 *)charBuf + 6);
350 	_dialogueMesgId3 = READ_LE_INT16((uint16 *)charBuf + 7);
351 	int frameNumb = READ_LE_INT16((uint16 *)charBuf + 8);
352 
353 	int curBufVal = READ_LE_INT16((uint16 *)charBuf + 9);
354 	if (curBufVal)
355 		_vm->_globals->_saveData->_data[svDialogField4] = curBufVal;
356 
357 	if (!frameNumb)
358 		frameNumb = 10;
359 	if (animatedFl) {
360 		uint16 *bufPtr = (uint16 *)_characterBuffer + 43;
361 		int curVal = READ_LE_INT16(bufPtr);
362 		if (curVal)
363 			_vm->_objectsMan->stopBobAnimation(curVal);
364 
365 		curVal = READ_LE_INT16(bufPtr + 1);
366 		if (curVal)
367 			_vm->_objectsMan->stopBobAnimation(curVal);
368 
369 		curVal = READ_LE_INT16(bufPtr + 2);
370 		if (curVal)
371 			_vm->_objectsMan->stopBobAnimation(curVal);
372 
373 		curVal = READ_LE_INT16(bufPtr + 3);
374 		if (curVal)
375 			_vm->_objectsMan->stopBobAnimation(curVal);
376 
377 		curVal = READ_LE_INT16(bufPtr + 4);
378 		if (curVal)
379 			_vm->_objectsMan->stopBobAnimation(curVal);
380 	} else {
381 		dialogAnim();
382 	}
383 
384 	bool displayedTxtFl = false;
385 	if (!_vm->_soundMan->_textOffFl) {
386 		_vm->_fontMan->initTextBuffers(9, mesgId, _answersFilename, mesgPosX, mesgPosY, 5, mesgLength, 252);
387 		_vm->_fontMan->showText(9);
388 		displayedTxtFl = true;
389 	}
390 	if (!_vm->_soundMan->mixVoice(mesgId, 1, displayedTxtFl)) {
391 		_vm->_events->_curMouseButton = 0;
392 		_vm->_events->_mouseButton = 0;
393 
394 		if (_vm->getIsDemo()) {
395 			for (int i = 0; i < frameNumb; i++) {
396 				_vm->_events->refreshScreenAndEvents();
397 			}
398 		} else {
399 			for (int i = 0; i < frameNumb; i++) {
400 				_vm->_events->refreshScreenAndEvents();
401 				if (_vm->_events->_mouseButton || _vm->_events->_curMouseButton)
402 					break;
403 				if (_vm->_events->getMouseButton() && i + 1 > abs(frameNumb / 5))
404 					break;
405 			}
406 		}
407 	}
408 
409 	if (!_vm->_soundMan->_textOffFl)
410 		_vm->_fontMan->hideText(9);
411 	if (animatedFl) {
412 		uint16 *bufPtr = (uint16 *)_characterBuffer + 43;
413 		int curVal = READ_LE_INT16(bufPtr);
414 		if (curVal)
415 			_vm->_objectsMan->stopBobAnimation(curVal);
416 
417 		curVal = READ_LE_INT16(bufPtr + 1);
418 		if (curVal)
419 			_vm->_objectsMan->stopBobAnimation(curVal);
420 
421 		curVal = READ_LE_INT16(bufPtr + 2);
422 		if (curVal)
423 			_vm->_objectsMan->stopBobAnimation(curVal);
424 
425 		curVal = READ_LE_INT16(bufPtr + 3);
426 		if (curVal)
427 			_vm->_objectsMan->stopBobAnimation(curVal);
428 
429 		curVal = READ_LE_INT16(bufPtr + 4);
430 		if (curVal)
431 			_vm->_objectsMan->stopBobAnimation(curVal);
432 	} else {
433 		dialogEndTalk();
434 	}
435 	int result = 0;
436 	if (!_dialogueMesgId1)
437 		result = -1;
438 
439 	return result;
440 }
441 
searchCharacterPalette(int startIdx,bool dark)442 void TalkManager::searchCharacterPalette(int startIdx, bool dark) {
443 	int palettePos = 0;
444 	size_t curIdx = startIdx;
445 	for (;;) {
446 		if (READ_BE_UINT24(&_characterBuffer[curIdx]) == MKTAG24('P', 'A', 'L')) {
447 			palettePos = curIdx;
448 			break;
449 		}
450 		++curIdx;
451 		if (_characterSize == curIdx)
452 			return;
453 	}
454 
455 	_characterPalette = _characterBuffer + palettePos + 5;
456 	_characterPalette[0] = 0;
457 	_characterPalette[1] = 0;
458 	_characterPalette[2] = 0;
459 	_characterPalette[759] = 255;
460 	_characterPalette[760] = 255;
461 	_characterPalette[762] = 0;
462 	_characterPalette[763] = 0;
463 	_characterPalette[764] = 0;
464 	_characterPalette[765] = 224;
465 	_characterPalette[766] = 224;
466 	_characterPalette[767] = 255;
467 
468 	if (!dark)
469 		_characterPalette[761] = 86;
470 	else
471 		_characterPalette[761] = 255;
472 
473 	_vm->_graphicsMan->setPaletteVGA256(_characterPalette);
474 	_vm->_graphicsMan->initColorTable(145, 150, _characterPalette);
475 }
476 
dialogWait()477 void TalkManager::dialogWait() {
478 	for (int idx = 26; idx <= 30; ++idx) {
479 		if (_vm->_animMan->_animBqe[idx]._enabledFl)
480 			displayBobDialogAnim(idx);
481 	}
482 }
483 
dialogTalk()484 void TalkManager::dialogTalk() {
485 	for (int idx = 26; idx <= 30; ++idx) {
486 		if (_vm->_animMan->_animBqe[idx]._enabledFl)
487 			_vm->_objectsMan->hideBob(idx);
488 	}
489 
490 	for (int idx = 26; idx <= 30; ++idx) {
491 		if (_vm->_animMan->_animBqe[idx]._enabledFl)
492 			_vm->_objectsMan->resetBob(idx);
493 	}
494 }
495 
dialogEndTalk()496 void TalkManager::dialogEndTalk() {
497 	for (int idx = 21; idx <= 25; ++idx) {
498 		if (_vm->_animMan->_animBqe[idx]._enabledFl)
499 			_vm->_objectsMan->hideBob(idx);
500 	}
501 
502 	_vm->_events->refreshScreenAndEvents();
503 	_vm->_events->refreshScreenAndEvents();
504 
505 	for (int idx = 21; idx <= 25; ++idx) {
506 		if (_vm->_animMan->_animBqe[idx]._enabledFl)
507 			_vm->_objectsMan->resetBob(idx);
508 	}
509 }
510 
countBoxLines(int idx,const Common::String & file)511 int TalkManager::countBoxLines(int idx, const Common::String &file) {
512 	_vm->_fontMan->_fontFixedWidth = 11;
513 
514 	// Build up the filename
515 	Common::String filename;
516 	Common::String dest;
517 	filename = dest = file;
518 	while (filename.lastChar() != '.')
519 		filename.deleteLastChar();
520 	filename += "IND";
521 
522 	Common::File f;
523 	if (!f.open(filename))
524 		error("Could not open file - %s", filename.c_str());
525 	int filesize = f.size();
526 	assert(filesize < 16188);
527 
528 	uint32 indexData[4047];
529 	for (int i = 0; i < (filesize / 4); ++i)
530 		indexData[i] = f.readUint32LE();
531 	f.close();
532 
533 	if (!f.open(dest))
534 		error("Error opening file - %s", dest.c_str());
535 
536 	f.seek(indexData[idx]);
537 	byte *decryptBuf = _vm->_globals->allocMemory(2058);
538 	assert(decryptBuf);
539 
540 	f.read(decryptBuf, 2048);
541 	f.close();
542 
543 	// Decrypt buffer
544 	byte *curDecryptPtr = decryptBuf;
545 	for (int i = 0; i < 2048; i++) {
546 		char curByte = *curDecryptPtr;
547 		if ((byte)(curByte + 46) > 27) {
548 			if ((byte)(curByte + 80) > 27) {
549 				if ((curByte >= 'A' && curByte <= 'Z') || (curByte >= 'a' && curByte <= 'z'))
550 					curByte = ' ';
551 			} else {
552 				curByte -= 79;
553 			}
554 		} else {
555 			curByte += 111;
556 		}
557 		*curDecryptPtr = curByte;
558 		curDecryptPtr++;
559 	}
560 
561 	// Separate strings
562 	for (int i = 0; i < 2048; i++) {
563 		if ( decryptBuf[i] == 10 || decryptBuf[i] == 13)
564 			decryptBuf[i] = 0;
565 	}
566 
567 	// Check size of each strings in order to compute box width
568 	int curBufIndx = 0;
569 	int lineCount = 0;
570 	int lineSize = 0;
571 	char curChar;
572 	do {
573 		int curLineSize = 0;
574 		for (;;) {
575 			lineSize = curLineSize;
576 			do {
577 				curChar = decryptBuf[curBufIndx + curLineSize];
578 				++curLineSize;
579 			} while (curChar != ' ' && curChar != '%');
580 
581 			if (curLineSize >= MIN_LETTERS_PER_LINE - 1) {
582 				if (curChar == '%')
583 					curChar = ' ';
584 				break;
585 			}
586 
587 			if (curChar == '%') {
588 				lineSize = curLineSize;
589 				break;
590 			}
591 		}
592 		++lineCount;
593 		curBufIndx += lineSize;
594 	} while (curChar != '%');
595 	_vm->_globals->freeMemory(decryptBuf);
596 	return lineCount;
597 }
598 
dialogAnim()599 void TalkManager::dialogAnim() {
600 	for (int idx = 21; idx <= 25; ++idx) {
601 		if (_vm->_animMan->_animBqe[idx]._enabledFl)
602 			displayBobDialogAnim(idx);
603 	}
604 }
605 
displayBobDialogAnim(int idx)606 void TalkManager::displayBobDialogAnim(int idx) {
607 	_vm->_objectsMan->_priorityFl = true;
608 	if (!_vm->_objectsMan->_bob[idx]._bobMode) {
609 		_vm->_objectsMan->resetBob(idx);
610 		byte *bqeData = _vm->_animMan->_animBqe[idx]._data;
611 		int newMode = READ_LE_INT16(bqeData + 2);
612 		if (!newMode)
613 			newMode = 1;
614 		if (READ_LE_INT16(bqeData + 24)) {
615 			_vm->_objectsMan->_bob[idx]._isSpriteFl = true;
616 			_vm->_objectsMan->_bob[idx]._zoomFactor = 0;
617 			_vm->_objectsMan->_bob[idx]._flipFl = false;
618 			_vm->_objectsMan->_bob[idx]._animData = _vm->_animMan->_animBqe[idx]._data;
619 			_vm->_objectsMan->_bob[idx]._bobMode = 10;
620 			_vm->_objectsMan->_bob[idx]._spriteData = _characterSprite;
621 			_vm->_objectsMan->_bob[idx]._bobModeChange = newMode;
622 			_vm->_objectsMan->_bob[idx]._modeChangeCtr = -1;
623 			_vm->_objectsMan->_bob[idx]._modeChangeUnused = 0;
624 		}
625 	}
626 }
627 
startCharacterAnim0(int startIdx,bool readOnlyFl)628 void TalkManager::startCharacterAnim0(int startIdx, bool readOnlyFl) {
629 	int animIdx = 0;
630 	size_t curIdx = startIdx;
631 	for (;;) {
632 		if (READ_BE_UINT32(&_characterBuffer[curIdx]) == MKTAG('A', 'N', 'I', 'M') && _characterBuffer[curIdx + 4] == 1) {
633 			animIdx = curIdx;
634 			break;
635 		}
636 		++curIdx;
637 		if (_characterSize == curIdx)
638 			return;
639 	}
640 	_characterAnim = _characterBuffer + animIdx + 25;
641 	if (!readOnlyFl) {
642 		int idx = 0;
643 		do {
644 			if (!READ_LE_INT16(&_characterAnim[2 * idx + 4]))
645 				break;
646 			if (_vm->_globals->_speed != 501)
647 				_vm->_graphicsMan->fastDisplay(_characterSprite, _vm->_events->_startPos.x + READ_LE_INT16(&_characterAnim[2 * idx]),
648 				    READ_LE_INT16(&_characterAnim[2 * idx + 2]), _characterAnim[2 * idx + 8]);
649 			idx += 5;
650 		} while (_vm->_globals->_speed != 501);
651 	}
652 }
653 
654 /**
655  * Initialize character animation
656  */
initCharacterAnim()657 void TalkManager::initCharacterAnim() {
658 	uint16 *bufPtr = (uint16 *)_characterBuffer + 43;
659 	byte *animPtr = _characterBuffer + 110;
660 	int curVal = READ_LE_INT16(bufPtr);
661 	if (curVal)
662 		searchCharacterAnim(21, animPtr, curVal, _characterSize);
663 
664 	curVal = READ_LE_INT16(bufPtr + 1);
665 	if (curVal)
666 		searchCharacterAnim(22, animPtr, curVal, _characterSize);
667 
668 	curVal = READ_LE_INT16(bufPtr + 2);
669 	if (curVal)
670 		searchCharacterAnim(23, animPtr, curVal, _characterSize);
671 
672 	curVal = READ_LE_INT16(bufPtr + 3);
673 	if (curVal)
674 		searchCharacterAnim(24, animPtr, curVal, _characterSize);
675 
676 	curVal = READ_LE_INT16(bufPtr + 4);
677 	if (curVal)
678 		searchCharacterAnim(25, animPtr, curVal, _characterSize);
679 
680 	curVal = READ_LE_INT16(bufPtr + 5);
681 	if (curVal)
682 		searchCharacterAnim(26, animPtr, curVal, _characterSize);
683 
684 	curVal = READ_LE_INT16(bufPtr + 6);
685 	if (curVal)
686 		searchCharacterAnim(27, animPtr, curVal, _characterSize);
687 
688 	curVal = READ_LE_INT16(bufPtr + 7);
689 	if (curVal)
690 		searchCharacterAnim(28, animPtr, curVal, _characterSize);
691 
692 	curVal = READ_LE_INT16(bufPtr + 8);
693 	if (curVal)
694 		searchCharacterAnim(29, animPtr, curVal, _characterSize);
695 
696 	curVal = READ_LE_INT16(bufPtr + 9);
697 	if (curVal)
698 		searchCharacterAnim(30, animPtr, curVal, _characterSize);
699 }
700 
clearCharacterAnim()701 void TalkManager::clearCharacterAnim() {
702 	for (int idx = 21; idx <= 34; ++idx) {
703 		_vm->_animMan->_animBqe[idx]._data = _vm->_globals->freeMemory(_vm->_animMan->_animBqe[idx]._data);
704 		_vm->_animMan->_animBqe[idx]._enabledFl = false;
705 	}
706 }
707 
searchCharacterAnim(int idx,const byte * bufPerso,int animId,int bufferSize)708 bool TalkManager::searchCharacterAnim(int idx, const byte *bufPerso, int animId, int bufferSize) {
709 	bool result = false;
710 
711 	for (int bufPos = 0; bufPos <= bufferSize; bufPos++) {
712 		if (READ_BE_UINT32(bufPerso + bufPos) == MKTAG('A', 'N', 'I', 'M') && bufPerso[bufPos + 4] == animId) {
713 			int bufIndx = bufPos + 5;
714 			const byte *curPtr = bufPerso + bufIndx;
715 			int animLength = 0;
716 			bool loopCond = false;
717 			do {
718 				if (READ_BE_UINT32(curPtr) == MKTAG('A', 'N', 'I', 'M') || READ_BE_UINT24(curPtr) == MKTAG24('F', 'I', 'N'))
719 					loopCond = true;
720 				if (bufIndx > bufferSize) {
721 					_vm->_animMan->_animBqe[idx]._enabledFl = false;
722 					_vm->_animMan->_animBqe[idx]._data = NULL;
723 					return false;
724 				}
725 				++bufIndx;
726 				++animLength;
727 				++curPtr;
728 			} while (!loopCond);
729 			_vm->_animMan->_animBqe[idx]._data = _vm->_globals->allocMemory(animLength + 50);
730 			_vm->_animMan->_animBqe[idx]._enabledFl = true;
731 			memcpy(_vm->_animMan->_animBqe[idx]._data, (const byte *)(bufPerso + bufPos + 5), 20);
732 			int bqeVal = READ_LE_INT16(bufPos + bufPerso + 29);
733 			WRITE_LE_UINT16(_vm->_animMan->_animBqe[idx]._data + 20, READ_LE_INT16(bufPos + bufPerso + 25));
734 			WRITE_LE_UINT16(_vm->_animMan->_animBqe[idx]._data + 22, READ_LE_INT16(bufPos + bufPerso + 27));
735 			WRITE_LE_UINT16(_vm->_animMan->_animBqe[idx]._data + 24, bqeVal);
736 			WRITE_LE_UINT16(_vm->_animMan->_animBqe[idx]._data + 26, READ_LE_INT16(bufPos + bufPerso + 31));
737 			_vm->_animMan->_animBqe[idx]._data[28] = bufPerso[bufPos + 33];
738 			_vm->_animMan->_animBqe[idx]._data[29] = bufPerso[bufPos + 34];
739 			byte *bqeCurData = _vm->_animMan->_animBqe[idx]._data + 20;
740 			const byte *curBufPerso = bufPos + bufPerso + 25;
741 			for (int i = 1; i < 5000; i++) {
742 				bqeCurData += 10;
743 				curBufPerso += 10;
744 				if (!bqeVal)
745 					break;
746 				bqeVal = READ_LE_INT16(curBufPerso + 4);
747 				WRITE_LE_UINT16(bqeCurData, READ_LE_INT16(curBufPerso));
748 				WRITE_LE_UINT16(bqeCurData + 2, READ_LE_INT16(curBufPerso + 2));
749 				WRITE_LE_UINT16(bqeCurData + 4, bqeVal);
750 				WRITE_LE_UINT16(bqeCurData + 6, READ_LE_INT16(curBufPerso + 6));
751 				bqeCurData[8] = curBufPerso[8];
752 				bqeCurData[9] = curBufPerso[9];
753 			}
754 			result = true;
755 		}
756 		if (READ_BE_UINT24(&bufPerso[bufPos]) == MKTAG24('F', 'I', 'N'))
757 			result = true;
758 
759 		if (result)
760 			break;
761 	}
762 
763 	return result;
764 }
765 
handleAnswer(int zone,int verb)766 void TalkManager::handleAnswer(int zone, int verb) {
767 	byte zoneObj = zone;
768 	byte verbObj = verb;
769 
770 	bool outerLoopFl;
771 	byte *ptr = NULL;
772 	do {
773 		outerLoopFl = false;
774 		bool tagFound = false;
775 		if (_vm->_globals->_answerBuffer == NULL)
776 			return;
777 
778 		byte *curAnswerBuf = _vm->_globals->_answerBuffer;
779 		for (;;) {
780 			if (READ_BE_UINT24(curAnswerBuf) == MKTAG24('F', 'I', 'N'))
781 				return;
782 			if (READ_BE_UINT24(curAnswerBuf) == MKTAG24('C', 'O', 'D')) {
783 				if (curAnswerBuf[3] == zoneObj && curAnswerBuf[4] == verbObj)
784 					tagFound = true;
785 			}
786 			if (!tagFound)
787 				curAnswerBuf++;
788 			else
789 				break;
790 		}
791 
792 		// 'COD' tag found
793 		curAnswerBuf += 5;
794 		ptr = _vm->_globals->allocMemory(620);
795 		assert(ptr);
796 		memset(ptr, 0, 620);
797 		uint16 curAnswerIdx = 0;
798 		int idx = 0;
799 		bool innerLoopCond = false;
800 		do {
801 			tagFound = false;
802 			if (READ_BE_UINT16(&curAnswerBuf[curAnswerIdx]) == MKTAG16('F', 'C')) {
803 				++idx;
804 				assert(idx < (620 / 20));
805 
806 				byte *answerBuf = (ptr + 20 * idx);
807 				uint16 anwerIdx = 0;
808 				do {
809 					assert(anwerIdx < 20);
810 					answerBuf[anwerIdx++] = curAnswerBuf[curAnswerIdx++];
811 					if (READ_BE_UINT16(&curAnswerBuf[curAnswerIdx]) == MKTAG16('F', 'F')) {
812 						tagFound = true;
813 						answerBuf[anwerIdx] = 'F';
814 						answerBuf[anwerIdx + 1] = 'F';
815 						++curAnswerIdx;
816 					}
817 				} while (!tagFound);
818 			}
819 			if (!tagFound) {
820 				uint32 signature24 = READ_BE_UINT24(&curAnswerBuf[curAnswerIdx]);
821 				if (signature24 == MKTAG24('C', 'O', 'D') || signature24 == MKTAG24('F', 'I', 'N'))
822 					innerLoopCond = true;
823 			}
824 			curAnswerBuf += curAnswerIdx + 1;
825 			curAnswerIdx = 0;
826 		} while (!innerLoopCond);
827 		innerLoopCond = false;
828 		int lastOpcodeResult = 1;
829 		do {
830 			int opcodeType = _vm->_script->handleOpcode(ptr + 20 * lastOpcodeResult);
831 			if (opcodeType == -1 || _vm->shouldQuit())
832 				return;
833 
834 			if (opcodeType == 2)
835 				// GOTO
836 				lastOpcodeResult =  _vm->_script->handleGoto(ptr + 20 * lastOpcodeResult);
837 			else if (opcodeType == 3)
838 				// IF
839 				lastOpcodeResult =  _vm->_script->handleIf(ptr, lastOpcodeResult);
840 
841 			if (lastOpcodeResult == -1)
842 				error("Invalid IFF function");
843 
844 			if (opcodeType == 1 || opcodeType == 4)
845 				// Already handled opcode or END IF
846 				++lastOpcodeResult;
847 			else if (!opcodeType || opcodeType == 5)
848 				// EXIT
849 				innerLoopCond = true;
850 			else if (opcodeType == 6) {
851 				// JUMP
852 				_vm->_globals->freeMemory(ptr);
853 				zoneObj = _vm->_objectsMan->_jumpZone;
854 				verbObj = _vm->_objectsMan->_jumpVerb;
855 				outerLoopFl = true;
856 				break;
857 			}
858 		} while (!innerLoopCond);
859 	} while (outerLoopFl);
860 	_vm->_globals->freeMemory(ptr);
861 	_vm->_globals->_saveData->_data[svLastZoneNum] = 0;
862 	return;
863 }
864 
handleForestAnswser(int zone,int verb)865 void TalkManager::handleForestAnswser(int zone, int verb) {
866 	int indx = 0;
867 	if (verb != 5 || _vm->_globals->_saveData->_data[svLastObjectIndex] != 4)
868 		return;
869 
870 	if (zone == 22 || zone == 23) {
871 		_vm->_objectsMan->setFlipSprite(0, false);
872 		_vm->_objectsMan->setSpriteIndex(0, 62);
873 		_vm->_objectsMan->showSpecialActionAnimationWithFlip(_vm->_objectsMan->_forestSprite, "2,3,4,5,6,7,8,9,10,11,12,-1,", 4, false);
874 		if (zone == 22) {
875 			_vm->_objectsMan->lockAnimX(6, _vm->_objectsMan->getBobPosX(3));
876 			_vm->_objectsMan->lockAnimX(8, _vm->_objectsMan->getBobPosX(3));
877 		} else { // zone == 23
878 			_vm->_objectsMan->lockAnimX(6, _vm->_objectsMan->getBobPosX(4));
879 			_vm->_objectsMan->lockAnimX(8, _vm->_objectsMan->getBobPosX(4));
880 		}
881 		_vm->_objectsMan->stopBobAnimation(3);
882 		_vm->_objectsMan->stopBobAnimation(4);
883 		_vm->_objectsMan->setBobAnimation(6);
884 		_vm->_soundMan->playSample(1);
885 		_vm->_objectsMan->showSpecialActionAnimation(_vm->_objectsMan->_forestSprite, "13,14,15,14,13,12,13,14,15,16,-1,", 4);
886 		do {
887 			_vm->_events->refreshScreenAndEvents();
888 		} while (_vm->_objectsMan->getBobAnimDataIdx(6) < 12);
889 		_vm->_objectsMan->stopBobAnimation(6);
890 		_vm->_objectsMan->setBobAnimation(8);
891 
892 		switch (_vm->_globals->_screenId) {
893 		case 35:
894 			indx = 201;
895 			break;
896 		case 36:
897 			indx = 203;
898 			break;
899 		case 37:
900 			indx = 205;
901 			break;
902 		case 38:
903 			indx = 207;
904 			break;
905 		case 39:
906 			indx = 209;
907 			break;
908 		case 40:
909 			indx = 211;
910 			break;
911 		case 41:
912 			indx = 213;
913 			break;
914 		default:
915 			break;
916 		}
917 		_vm->_globals->_saveData->_data[indx] = 2;
918 		_vm->_linesMan->disableZone(22);
919 		_vm->_linesMan->disableZone(23);
920 	} else if (zone == 20 || zone == 21) {
921 		_vm->_objectsMan->setFlipSprite(0, true);
922 		_vm->_objectsMan->setSpriteIndex(0, 62);
923 		_vm->_objectsMan->showSpecialActionAnimationWithFlip(_vm->_objectsMan->_forestSprite, "2,3,4,5,6,7,8,9,10,11,12,-1,", 4, true);
924 		if (zone == 20) {
925 			_vm->_objectsMan->lockAnimX(5, _vm->_objectsMan->getBobPosX(1));
926 			_vm->_objectsMan->lockAnimX(7, _vm->_objectsMan->getBobPosX(1));
927 		} else { // zone == 21
928 			_vm->_objectsMan->lockAnimX(5, _vm->_objectsMan->getBobPosX(2));
929 			_vm->_objectsMan->lockAnimX(7, _vm->_objectsMan->getBobPosX(2));
930 		}
931 		_vm->_objectsMan->stopBobAnimation(1);
932 		_vm->_objectsMan->stopBobAnimation(2);
933 		_vm->_objectsMan->setBobAnimation(5);
934 		_vm->_soundMan->playSample(1);
935 		_vm->_objectsMan->showSpecialActionAnimation(_vm->_objectsMan->_forestSprite, "13,14,15,14,13,12,13,14,15,16,-1,", 4);
936 		do {
937 			_vm->_events->refreshScreenAndEvents();
938 		} while (_vm->_objectsMan->getBobAnimDataIdx(5) < 12);
939 		_vm->_objectsMan->stopBobAnimation(5);
940 		_vm->_objectsMan->setBobAnimation(7);
941 		switch (_vm->_globals->_screenId) {
942 		case 35:
943 			indx = 200;
944 			break;
945 		case 36:
946 			indx = 202;
947 			break;
948 		case 37:
949 			indx = 204;
950 			break;
951 		case 38:
952 			indx = 206;
953 			break;
954 		case 39:
955 			indx = 208;
956 			break;
957 		case 40:
958 			indx = 210;
959 			break;
960 		case 41:
961 			indx = 212;
962 			break;
963 		default:
964 			break;
965 		}
966 		_vm->_globals->_saveData->_data[indx] = 2;
967 		_vm->_linesMan->disableZone(21);
968 		_vm->_linesMan->disableZone(20);
969 	}
970 }
971 
animateObject(const Common::String & filename)972 void TalkManager::animateObject(const Common::String &filename) {
973 	_vm->_fontMan->hideText(5);
974 	_vm->_fontMan->hideText(9);
975 	_vm->_events->refreshScreenAndEvents();
976 	_vm->_graphicsMan->_scrollStatus = 1;
977 	_vm->_linesMan->clearAllZones();
978 	_vm->_linesMan->resetLines();
979 	_vm->_objectsMan->resetHidingItems();
980 
981 	for (int i = 0; i <= 44; i++)
982 		_vm->_linesMan->_bobZone[i] = 0;
983 
984 	_vm->_objectsMan->_zoneNum = -1;
985 	_vm->_events->_mouseCursorId = 4;
986 	_vm->_events->changeMouseCursor(0);
987 	bool fileFoundFl = false;
988 	_characterBuffer = _vm->_fileIO->searchCat(filename, RES_PER, fileFoundFl);
989 	_characterSize = _vm->_fileIO->_catalogSize;
990 	if (!fileFoundFl) {
991 		_characterBuffer = _vm->_fileIO->loadFile(filename);
992 		_characterSize = _vm->_fileIO->fileSize(filename);
993 	}
994 	Common::String screenFilename;
995 	Common::String spriteFilename;
996 	Common::String curScreenFilename;
997 	getStringFromBuffer(40, spriteFilename, (const char *)_characterBuffer);
998 	getStringFromBuffer(0, screenFilename, (const char *)_characterBuffer);
999 	getStringFromBuffer(20, curScreenFilename, (const char *)_characterBuffer);
1000 
1001 	if (curScreenFilename == "NULL")
1002 		curScreenFilename = Common::String::format("IM%d", _vm->_globals->_screenId);
1003 
1004 	fileFoundFl = false;
1005 	_characterSprite = _vm->_fileIO->searchCat(spriteFilename, RES_SAN, fileFoundFl);
1006 	if (!fileFoundFl)
1007 		_characterSprite = _vm->_objectsMan->loadSprite(spriteFilename);
1008 	else
1009 		_characterSprite = _vm->_objectsMan->loadSprite("RES_SAN.RES");
1010 
1011 	_vm->_graphicsMan->backupScreen();
1012 
1013 	if (!_vm->_graphicsMan->_lineNbr)
1014 		_vm->_graphicsMan->_scrollOffset = 0;
1015 	_vm->_graphicsMan->displayScreen(true);
1016 	_paletteBufferIdx = 20 * READ_LE_INT16((uint16 *)_characterBuffer + 42) + 110;
1017 	_vm->_graphicsMan->displayScreen(true);
1018 	_vm->_objectsMan->_charactersEnabledFl = true;
1019 	searchCharacterPalette(_paletteBufferIdx, true);
1020 	startCharacterAnim0(_paletteBufferIdx, false);
1021 	byte *oldAnswerBufferPtr = _vm->_globals->_answerBuffer;
1022 	_vm->_globals->_answerBuffer = NULL;
1023 	_vm->_globals->_freezeCharacterFl = true;
1024 	_vm->_objectsMan->loadLinkFile(screenFilename);
1025 	_vm->_objectsMan->_charactersEnabledFl = true;
1026 	_vm->_globals->_actionMoveTo = false;
1027 	_vm->_objectsMan->_zoneNum = -1;
1028 	initCharacterAnim();
1029 	dialogAnim();
1030 	dialogWait();
1031 	_vm->_graphicsMan->initScreen(screenFilename, 2, true);
1032 	_vm->_globals->_freezeCharacterFl = true;
1033 	_vm->_objectsMan->_forceZoneFl = true;
1034 	_vm->_objectsMan->_zoneNum = -1;
1035 	do {
1036 		int mouseButton = _vm->_events->getMouseButton();
1037 		if (mouseButton == 1)
1038 			_vm->_objectsMan->handleLeftButton();
1039 		else if (mouseButton == 2)
1040 			_vm->_objectsMan->handleRightButton();
1041 
1042 		_vm->_linesMan->checkZone();
1043 		if (_vm->_globals->_actionMoveTo)
1044 			_vm->_objectsMan->paradise();
1045 		_vm->_events->refreshScreenAndEvents();
1046 	} while (!_vm->_globals->_exitId);
1047 	dialogEndTalk();
1048 	dialogTalk();
1049 	clearCharacterAnim();
1050 	clearCharacterAnim();
1051 	_vm->_globals->_introSpeechOffFl = false;
1052 	_characterBuffer = _vm->_globals->freeMemory(_characterBuffer);
1053 	_characterSprite = _vm->_globals->freeMemory(_characterSprite);
1054 	_vm->_graphicsMan->displayScreen(false);
1055 	_vm->_linesMan->clearAllZones();
1056 	_vm->_linesMan->resetLines();
1057 	_vm->_objectsMan->resetHidingItems();
1058 	for (int i = 0; i <= 44; i++)
1059 		_vm->_linesMan->_bobZone[i] = 0;
1060 
1061 	_vm->_globals->freeMemory(_vm->_globals->_answerBuffer);
1062 	_vm->_globals->_answerBuffer = oldAnswerBufferPtr;
1063 	_vm->_objectsMan->_disableFl = true;
1064 	_vm->_objectsMan->loadLinkFile(curScreenFilename);
1065 	_vm->_graphicsMan->initScreen(curScreenFilename, 2, true);
1066 	_vm->_objectsMan->_disableFl = false;
1067 	_vm->_globals->_freezeCharacterFl = false;
1068 	if (_vm->_globals->_exitId == 101)
1069 		_vm->_globals->_exitId = 0;
1070 
1071 	_vm->_graphicsMan->restoreScreen();
1072 
1073 	_vm->_objectsMan->_charactersEnabledFl = false;
1074 	_vm->_events->_mouseCursorId = 4;
1075 	_vm->_events->changeMouseCursor(4);
1076 	_vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
1077 
1078 	if (!_vm->getIsDemo())
1079 		_vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
1080 
1081 	_vm->_graphicsMan->initColorTable(145, 150, _vm->_graphicsMan->_palette);
1082 	_vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
1083 	_vm->_graphicsMan->display8BitRect(_vm->_graphicsMan->_backBuffer, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
1084 	_vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
1085 	memcpy(_vm->_graphicsMan->_frontBuffer, _vm->_graphicsMan->_backBuffer, 614399);
1086 	_vm->_globals->_disableInventFl = false;
1087 	_vm->_graphicsMan->updateScreen();
1088 	for (int i = 0; i <= 4; i++)
1089 		_vm->_events->refreshScreenAndEvents();
1090 	_vm->_graphicsMan->_scrollStatus = 0;
1091 }
1092 
1093 } // End of namespace Hopkins
1094