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