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