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 "kyra/text/text_hof.h"
24 #include "kyra/resource/resource.h"
25
26 #include "common/system.h"
27
28 namespace Kyra {
29
TextDisplayer_HoF(KyraEngine_HoF * vm,Screen_v2 * screen)30 TextDisplayer_HoF::TextDisplayer_HoF(KyraEngine_HoF *vm, Screen_v2 *screen)
31 : TextDisplayer(vm, screen), _vm(vm) {
32 }
33
backupTalkTextMessageBkgd(int srcPage,int dstPage)34 void TextDisplayer_HoF::backupTalkTextMessageBkgd(int srcPage, int dstPage) {
35 _screen->copyRegion(_talkCoords.x, _talkMessageY, 0, 144, _talkCoords.w, _talkMessageH, srcPage, dstPage);
36 }
37
restoreTalkTextMessageBkgd(int srcPage,int dstPage)38 void TextDisplayer_HoF::restoreTalkTextMessageBkgd(int srcPage, int dstPage) {
39 _screen->copyRegion(0, 144, _talkCoords.x, _talkMessageY, _talkCoords.w, _talkMessageH, srcPage, dstPage);
40 }
41
restoreScreen()42 void TextDisplayer_HoF::restoreScreen() {
43 _vm->restorePage3();
44 _vm->drawAnimObjects();
45 _screen->copyRegion(_talkCoords.x, _talkMessageY, _talkCoords.x, _talkMessageY, _talkCoords.w, _talkMessageH, 2, 0, Screen::CR_NO_P_CHECK);
46 _vm->flagAnimObjsForRefresh();
47 _vm->refreshAnimObjects(0);
48 }
49
printCustomCharacterText(const char * text,int x,int y,uint8 c1,int srcPage,int dstPage)50 void TextDisplayer_HoF::printCustomCharacterText(const char *text, int x, int y, uint8 c1, int srcPage, int dstPage) {
51 text = preprocessString(text);
52 int lineCount = buildMessageSubstrings(text);
53 int w = getWidestLineWidth(lineCount);
54 int h = lineCount * 10;
55 y = MAX(0, y - (lineCount * 10));
56 int x1 = 0, x2 = 0;
57 calcWidestLineBounds(x1, x2, w, x);
58
59 _talkCoords.x = x1;
60 _talkCoords.w = w+2;
61 _talkCoords.y = y;
62 _talkMessageY = y;
63 _talkMessageH = h;
64
65 backupTalkTextMessageBkgd(srcPage, dstPage);
66 int curPageBackUp = _screen->_curPage;
67 _screen->_curPage = srcPage;
68
69 if (_vm->textEnabled()) {
70 for (int i = 0; i < lineCount; ++i) {
71 const char *msg = &_talkSubstrings[i * TALK_SUBSTRING_LEN];
72 printText(msg, getCenterStringX(msg, x1, x2), i * 10 + _talkMessageY, c1, 0xCF, 0);
73 }
74 }
75
76 _screen->_curPage = curPageBackUp;
77 }
78
preprocessString(const char * str)79 char *TextDisplayer_HoF::preprocessString(const char *str) {
80 if (str != _talkBuffer) {
81 assert(strlen(str) < sizeof(_talkBuffer) - 1);
82 strcpy(_talkBuffer, str);
83 }
84
85 char *p = _talkBuffer;
86 while (*p) {
87 if (*p == '\r')
88 return _talkBuffer;
89 ++p;
90 }
91
92 p = _talkBuffer;
93 Screen::FontId curFont = _screen->setFont(Screen::FID_8_FNT);
94 _screen->_charWidth = -2;
95 int textWidth = _screen->getTextWidth(p);
96 _screen->_charWidth = 0;
97
98 int maxTextWidth = (_vm->language() == 0) ? 176 : 240;
99
100 if (textWidth > maxTextWidth) {
101 if (textWidth > (maxTextWidth*2)) {
102 int count = getCharLength(p, textWidth / 3);
103 int offs = dropCRIntoString(p, count);
104 p += count + offs;
105 _screen->_charWidth = -2;
106 textWidth = _screen->getTextWidth(p);
107 _screen->_charWidth = 0;
108 count = getCharLength(p, textWidth / 2);
109 dropCRIntoString(p, count);
110 } else {
111 int count = getCharLength(p, textWidth / 2);
112 dropCRIntoString(p, count);
113 }
114 }
115 _screen->setFont(curFont);
116 return _talkBuffer;
117 }
118
calcWidestLineBounds(int & x1,int & x2,int w,int x)119 void TextDisplayer_HoF::calcWidestLineBounds(int &x1, int &x2, int w, int x) {
120 x1 = x;
121 x1 -= (w >> 1);
122 x2 = x1 + w + 1;
123
124 if (x1 + w >= 311)
125 x1 = 311 - w - 1;
126
127 if (x1 < 8)
128 x1 = 8;
129
130 x2 = x1 + w + 1;
131 }
132
133 #pragma mark -
134
chatGetType(const char * str)135 int KyraEngine_HoF::chatGetType(const char *str) {
136 str += strlen(str);
137 --str;
138 switch (*str) {
139 case '!':
140 return 2;
141
142 case ')':
143 return -1;
144
145 case '?':
146 return 1;
147
148 default:
149 return 0;
150 }
151 }
152
chatCalcDuration(const char * str)153 int KyraEngine_HoF::chatCalcDuration(const char *str) {
154 static const uint8 durationMultiplicator[] = { 16, 14, 12, 10, 8, 8, 7, 6, 5, 4 };
155
156 int duration = strlen(str);
157 duration *= _flags.isTalkie ? 8 : durationMultiplicator[(_configTextspeed / 10)];
158 return MAX<int>(duration, 120);
159 }
160
objectChat(const char * str,int object,int vocHigh,int vocLow)161 void KyraEngine_HoF::objectChat(const char *str, int object, int vocHigh, int vocLow) {
162 setNextIdleAnimTimer();
163
164 _chatVocHigh = _chatVocLow = -1;
165
166 objectChatInit(str, object, vocHigh, vocLow);
167 _chatText = str;
168 _chatObject = object;
169 int chatType = chatGetType(str);
170 if (chatType == -1) {
171 _chatIsNote = true;
172 chatType = 0;
173 }
174
175 if (_mainCharacter.facing > 7)
176 _mainCharacter.facing = 5;
177
178 static const uint8 talkScriptTable[] = {
179 6, 7, 8,
180 3, 4, 5,
181 3, 4, 5,
182 0, 1, 2,
183 0, 1, 2,
184 0, 1, 2,
185 3, 4, 5,
186 3, 4, 5
187 };
188
189 assert(_mainCharacter.facing * 3 + chatType < ARRAYSIZE(talkScriptTable));
190 int script = talkScriptTable[_mainCharacter.facing * 3 + chatType];
191
192 static const char *const chatScriptFilenames[] = {
193 "_Z1FSTMT.EMC",
194 "_Z1FQUES.EMC",
195 "_Z1FEXCL.EMC",
196 "_Z1SSTMT.EMC",
197 "_Z1SQUES.EMC",
198 "_Z1SEXCL.EMC",
199 "_Z1BSTMT.EMC",
200 "_Z1BQUES.EMC",
201 "_Z1BEXCL.EMC"
202 };
203
204 objectChatProcess(chatScriptFilenames[script]);
205 _chatIsNote = false;
206
207 _text->restoreScreen();
208
209 _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
210 updateCharacterAnim(0);
211
212 _chatText = 0;
213 _chatObject = -1;
214
215 setNextIdleAnimTimer();
216 }
217
objectChatInit(const char * str,int object,int vocHigh,int vocLow)218 void KyraEngine_HoF::objectChatInit(const char *str, int object, int vocHigh, int vocLow) {
219 str = _text->preprocessString(str);
220 int lineNum = _text->buildMessageSubstrings(str);
221
222 int yPos = 0, xPos = 0;
223
224 if (!object) {
225 int scale = getScale(_mainCharacter.x1, _mainCharacter.y1);
226 yPos = _mainCharacter.y1 - ((_mainCharacter.height * scale) >> 8) - 8;
227 xPos = _mainCharacter.x1;
228 } else {
229 yPos = _talkObjectList[object].y;
230 xPos = _talkObjectList[object].x;
231 }
232
233 yPos -= lineNum * 10;
234 yPos = MAX(yPos, 0);
235 _text->_talkMessageY = yPos;
236 _text->_talkMessageH = lineNum*10;
237
238 int width = _text->getWidestLineWidth(lineNum);
239 _text->calcWidestLineBounds(xPos, yPos, width, xPos);
240 _text->_talkCoords.x = xPos;
241 _text->_talkCoords.w = width + 2;
242
243 restorePage3();
244 _text->backupTalkTextMessageBkgd(2, 2);
245
246 _chatTextEnabled = textEnabled();
247 if (_chatTextEnabled) {
248 objectChatPrintText(str, object);
249 _chatEndTime = _system->getMillis() + chatCalcDuration(str) * _tickLength;
250 } else {
251 _chatEndTime = _system->getMillis();
252 }
253
254 if (speechEnabled()) {
255 _chatVocHigh = vocHigh;
256 _chatVocLow = vocLow;
257 } else {
258 _chatVocHigh = _chatVocLow = -1;
259 }
260 }
261
objectChatPrintText(const char * str,int object)262 void KyraEngine_HoF::objectChatPrintText(const char *str, int object) {
263 int c1 = _talkObjectList[object].color;
264 str = _text->preprocessString(str);
265 int lineNum = _text->buildMessageSubstrings(str);
266 int maxWidth = _text->getWidestLineWidth(lineNum);
267 int x = (object == 0) ? _mainCharacter.x1 : _talkObjectList[object].x;
268 int cX1 = 0, cX2 = 0;
269 _text->calcWidestLineBounds(cX1, cX2, maxWidth, x);
270
271 for (int i = 0; i < lineNum; ++i) {
272 str = &_text->_talkSubstrings[i*_text->maxSubstringLen()];
273
274 int y = _text->_talkMessageY + i * 10;
275 x = _text->getCenterStringX(str, cX1, cX2);
276
277 _text->printText(str, x, y, c1, 0xCF, 0);
278 }
279 }
280
objectChatProcess(const char * script)281 void KyraEngine_HoF::objectChatProcess(const char *script) {
282 memset(&_chatScriptData, 0, sizeof(_chatScriptData));
283 memset(&_chatScriptState, 0, sizeof(_chatScriptState));
284
285 _emc->load(script, &_chatScriptData, &_opcodesAnimation);
286 _emc->init(&_chatScriptState, &_chatScriptData);
287 _emc->start(&_chatScriptState, 0);
288 while (_emc->isValid(&_chatScriptState))
289 _emc->run(&_chatScriptState);
290
291 _animShapeFilename[2] = _characterShapeFile + '0';
292 uint8 *shapeBuffer = _res->fileData(_animShapeFilename, 0);
293 if (shapeBuffer) {
294 int shapeCount = initAnimationShapes(shapeBuffer);
295
296 if (_chatVocHigh >= 0) {
297 playVoice(_chatVocHigh, _chatVocLow);
298 _chatVocHigh = _chatVocLow = -1;
299 }
300
301 objectChatWaitToFinish();
302
303 uninitAnimationShapes(shapeCount, shapeBuffer);
304 } else {
305 warning("couldn't load file '%s'", _animShapeFilename);
306 }
307
308 _emc->unload(&_chatScriptData);
309 }
310
objectChatWaitToFinish()311 void KyraEngine_HoF::objectChatWaitToFinish() {
312 int charAnimFrame = _mainCharacter.animFrame;
313 setCharacterAnimDim(_animShapeWidth, _animShapeHeight);
314
315 _emc->init(&_chatScriptState, &_chatScriptData);
316 _emc->start(&_chatScriptState, 1);
317
318 bool running = true;
319 const uint32 endTime = _chatEndTime;
320 resetSkipFlag();
321
322 while (running && !shouldQuit()) {
323 if (!_emc->isValid(&_chatScriptState))
324 _emc->start(&_chatScriptState, 1);
325
326 _animNeedUpdate = false;
327 while (!_animNeedUpdate && _emc->isValid(&_chatScriptState))
328 _emc->run(&_chatScriptState);
329
330 int curFrame = _animNewFrame;
331 uint32 delayTime = _animDelayTime;
332
333 if (!_chatIsNote)
334 _mainCharacter.animFrame = 33 + curFrame;
335
336 updateCharacterAnim(0);
337
338 uint32 nextFrame = _system->getMillis() + delayTime * _tickLength;
339
340 while (_system->getMillis() < nextFrame && !shouldQuit()) {
341 updateWithText();
342
343 const uint32 curTime = _system->getMillis();
344 if ((textEnabled() && curTime > endTime) || (speechEnabled() && !textEnabled() && !snd_voiceIsPlaying()) || skipFlag()) {
345 resetSkipFlag();
346 nextFrame = curTime;
347 running = false;
348 }
349
350 delay(10);
351 }
352 }
353
354 _mainCharacter.animFrame = charAnimFrame;
355 updateCharacterAnim(0);
356 resetCharacterAnimDim();
357 }
358
startDialogue(int dlgIndex)359 void KyraEngine_HoF::startDialogue(int dlgIndex) {
360 updateDlgBuffer();
361 int csEntry, vocH, unused1, unused2;
362 loadDlgHeader(csEntry, vocH, unused1, unused2);
363 int s = _conversationState[dlgIndex][csEntry];
364 uint8 bufferIndex = 8;
365
366 if (s == -1) {
367 bufferIndex += (dlgIndex * 6);
368 _conversationState[dlgIndex][csEntry] = 0;
369 } else if (!s || s == 2) {
370 bufferIndex += (dlgIndex * 6 + 2);
371 _conversationState[dlgIndex][csEntry] = 1;
372 } else {
373 bufferIndex += (dlgIndex * 6 + 4);
374 _conversationState[dlgIndex][csEntry] = 2;
375 }
376
377 int offs = READ_LE_UINT16(_dlgBuffer + bufferIndex);
378 processDialogue(offs, vocH, csEntry);
379 }
380
zanthSceneStartupChat()381 void KyraEngine_HoF::zanthSceneStartupChat() {
382 int lowest = _flags.isTalkie ? 6 : 5;
383 int tableIndex = _mainCharacter.sceneId - READ_LE_UINT16(&_ingameTalkObjIndex[lowest + _newChapterFile]);
384 if (queryGameFlag(0x159) || _newSceneDlgState[tableIndex])
385 return;
386
387 int csEntry, vocH, scIndex1, scIndex2;
388 updateDlgBuffer();
389 loadDlgHeader(csEntry, vocH, scIndex1, scIndex2);
390
391 uint8 bufferIndex = 8 + scIndex1 * 6 + scIndex2 * 4 + tableIndex * 2;
392 int offs = READ_LE_UINT16(_dlgBuffer + bufferIndex);
393 processDialogue(offs, vocH, csEntry);
394
395 _newSceneDlgState[tableIndex] = 1;
396 }
397
randomSceneChat()398 void KyraEngine_HoF::randomSceneChat() {
399 int lowest = _flags.isTalkie ? 6 : 5;
400 int tableIndex = (_mainCharacter.sceneId - READ_LE_UINT16(&_ingameTalkObjIndex[lowest + _newChapterFile])) << 2;
401 if (queryGameFlag(0x164))
402 return;
403
404 int csEntry, vocH, scIndex1, unused;
405 updateDlgBuffer();
406 loadDlgHeader(csEntry, vocH, scIndex1, unused);
407
408 if (_chatAltFlag) {
409 _chatAltFlag = 0;
410 tableIndex += 2;
411 } else {
412 _chatAltFlag = 1;
413 }
414
415 uint8 bufferIndex = 8 + scIndex1 * 6 + tableIndex;
416 int offs = READ_LE_UINT16(_dlgBuffer + bufferIndex);
417 processDialogue(offs, vocH, csEntry);
418 }
419
updateDlgBuffer()420 void KyraEngine_HoF::updateDlgBuffer() {
421 static const char suffixTalkie[] = "EFG";
422 static const char suffixTowns[] = "G J";
423
424 if (_currentChapter == _npcTalkChpIndex && _mainCharacter.dlgIndex == _npcTalkDlgIndex)
425 return;
426
427 _npcTalkChpIndex = _currentChapter;
428 _npcTalkDlgIndex = _mainCharacter.dlgIndex;
429
430 Common::String filename = Common::String::format("CH%.02d-S%.02d.DL", _currentChapter, _npcTalkDlgIndex);
431
432 const char *suffix = _flags.isTalkie ? suffixTalkie : suffixTowns;
433 if (_flags.platform != Common::kPlatformDOS || _flags.isTalkie)
434 filename += suffix[_lang];
435 else
436 filename += 'G';
437
438 delete[] _dlgBuffer;
439 _dlgBuffer = _res->fileData(filename.c_str(), 0);
440 }
441
loadDlgHeader(int & csEntry,int & vocH,int & scIndex1,int & scIndex2)442 void KyraEngine_HoF::loadDlgHeader(int &csEntry, int &vocH, int &scIndex1, int &scIndex2) {
443 csEntry = READ_LE_UINT16(_dlgBuffer);
444 vocH = READ_LE_UINT16(_dlgBuffer + 2);
445 scIndex1 = READ_LE_UINT16(_dlgBuffer + 4);
446 scIndex2 = READ_LE_UINT16(_dlgBuffer + 6);
447 }
448
processDialogue(int dlgOffset,int vocH,int csEntry)449 void KyraEngine_HoF::processDialogue(int dlgOffset, int vocH, int csEntry) {
450 int activeTimSequence = -1;
451 int nextTimSequence = -1;
452 int cmd = 0;
453 int vocHi = -1;
454 int vocLo = -1;
455 bool loop = true;
456 int offs = dlgOffset;
457
458 _screen->hideMouse();
459
460 while (loop) {
461 cmd = READ_LE_UINT16(_dlgBuffer + offs);
462 offs += 2;
463
464 nextTimSequence = READ_LE_UINT16(&_ingameTalkObjIndex[cmd]);
465
466 if (nextTimSequence == 10) {
467 if (queryGameFlag(0x3E))
468 nextTimSequence = 14;
469 if (queryGameFlag(0x3F))
470 nextTimSequence = 15;
471 if (queryGameFlag(0x40))
472 nextTimSequence = 16;
473 }
474
475 if (nextTimSequence == 27 && _mainCharacter.sceneId == 34)
476 nextTimSequence = 41;
477
478 if (queryGameFlag(0x72)) {
479 if (nextTimSequence == 18)
480 nextTimSequence = 43;
481 else if (nextTimSequence == 19)
482 nextTimSequence = 44;
483 }
484
485 if (_mainCharacter.x1 > 160) {
486 if (nextTimSequence == 4)
487 nextTimSequence = 46;
488 else if (nextTimSequence == 5)
489 nextTimSequence = 47;
490 }
491
492 if (cmd == 10) {
493 loop = false;
494
495 } else if (cmd == 4) {
496 csEntry = READ_LE_UINT16(_dlgBuffer + offs);
497 setDlgIndex(csEntry);
498 offs += 2;
499
500 } else {
501 if (!_flags.isTalkie || cmd == 11) {
502 int len = READ_LE_UINT16(_dlgBuffer + offs);
503 offs += 2;
504 if (_flags.isTalkie) {
505 vocLo = READ_LE_UINT16(_dlgBuffer + offs);
506 offs += 2;
507 }
508 memcpy(_unkBuf500Bytes, _dlgBuffer + offs, len);
509 _unkBuf500Bytes[len] = 0;
510 offs += len;
511 if (_flags.isTalkie)
512 continue;
513
514 } else if (_flags.isTalkie) {
515 int len = READ_LE_UINT16(_dlgBuffer + offs);
516 offs += 2;
517 static const int irnv[] = { 91, 105, 110, 114, 118 };
518 vocHi = irnv[vocH - 1] + csEntry;
519 vocLo = READ_LE_UINT16(_dlgBuffer + offs);
520 offs += 2;
521 memcpy(_unkBuf500Bytes, _dlgBuffer + offs, len);
522 _unkBuf500Bytes[len] = 0;
523 offs += len;
524 }
525
526 if (_unkBuf500Bytes[0]) {
527 if ((!_flags.isTalkie && cmd == 11) || (_flags.isTalkie && cmd == 12)) {
528 if (activeTimSequence > -1) {
529 deinitTalkObject(activeTimSequence);
530 activeTimSequence = -1;
531 }
532 objectChat((const char *)_unkBuf500Bytes, 0, vocHi, vocLo);
533 } else {
534 if (activeTimSequence != nextTimSequence) {
535 if (activeTimSequence > -1) {
536 deinitTalkObject(activeTimSequence);
537 activeTimSequence = -1;
538 }
539 initTalkObject(nextTimSequence);
540 activeTimSequence = nextTimSequence;
541 }
542 npcChatSequence((const char *)_unkBuf500Bytes, nextTimSequence, vocHi, vocLo);
543 }
544 }
545 }
546 }
547
548 if (activeTimSequence > -1)
549 deinitTalkObject(activeTimSequence);
550
551 _screen->showMouse();
552 }
553
initTalkObject(int index)554 void KyraEngine_HoF::initTalkObject(int index) {
555 TalkObject &object = _talkObjectList[index];
556
557 char STAFilename[13];
558 char ENDFilename[13];
559
560 strcpy(STAFilename, object.filename);
561 strcpy(_TLKFilename, object.filename);
562 strcpy(ENDFilename, object.filename);
563
564 strcat(STAFilename + 4, "_STA.TIM");
565 strcat(_TLKFilename + 4, "_TLK.TIM");
566 strcat(ENDFilename + 4, "_END.TIM");
567
568 _currentTalkSections.STATim = _tim->load(STAFilename, &_timOpcodes);
569 _currentTalkSections.TLKTim = _tim->load(_TLKFilename, &_timOpcodes);
570 _currentTalkSections.ENDTim = _tim->load(ENDFilename, &_timOpcodes);
571
572 if (object.scriptId != -1) {
573 _specialSceneScriptStateBackup[object.scriptId] = _specialSceneScriptState[object.scriptId];
574 _specialSceneScriptState[object.scriptId] = 1;
575 }
576
577 if (_currentTalkSections.STATim) {
578 _tim->resetFinishedFlag();
579 while (!shouldQuit() && !_tim->finished()) {
580 _tim->exec(_currentTalkSections.STATim, false);
581 if (_chatText)
582 updateWithText();
583 else
584 update();
585 delay(10);
586 }
587 }
588 }
589
deinitTalkObject(int index)590 void KyraEngine_HoF::deinitTalkObject(int index) {
591 TalkObject &object = _talkObjectList[index];
592
593 if (_currentTalkSections.ENDTim) {
594 _tim->resetFinishedFlag();
595 while (!shouldQuit() && !_tim->finished()) {
596 _tim->exec(_currentTalkSections.ENDTim, false);
597 if (_chatText)
598 updateWithText();
599 else
600 update();
601 delay(10);
602 }
603 }
604
605 if (object.scriptId != -1)
606 _specialSceneScriptState[object.scriptId] = _specialSceneScriptStateBackup[object.scriptId];
607
608 _tim->unload(_currentTalkSections.STATim);
609 _tim->unload(_currentTalkSections.TLKTim);
610 _tim->unload(_currentTalkSections.ENDTim);
611 }
612
npcChatSequence(const char * str,int objectId,int vocHigh,int vocLow)613 void KyraEngine_HoF::npcChatSequence(const char *str, int objectId, int vocHigh, int vocLow) {
614 _chatText = str;
615 _chatObject = objectId;
616 objectChatInit(str, objectId, vocHigh, vocLow);
617
618 if (!_currentTalkSections.TLKTim)
619 _currentTalkSections.TLKTim = _tim->load(_TLKFilename, &_timOpcodes);
620
621 setNextIdleAnimTimer();
622
623 uint32 ct = chatCalcDuration(str);
624 uint32 time = _system->getMillis();
625 _chatEndTime = time + (3 + ct) * _tickLength;
626 uint32 chatAnimEndTime = time + (3 + (ct >> 1)) * _tickLength;
627
628 if (_chatVocHigh >= 0) {
629 playVoice(_chatVocHigh, _chatVocLow);
630 _chatVocHigh = _chatVocLow = -1;
631 }
632
633 while (((textEnabled() && _chatEndTime > _system->getMillis()) || (speechEnabled() && snd_voiceIsPlaying())) && !(shouldQuit() || skipFlag())) {
634 if ((!speechEnabled() && chatAnimEndTime > _system->getMillis()) || (speechEnabled() && snd_voiceIsPlaying())) {
635 _tim->resetFinishedFlag();
636 while (!_tim->finished() && !skipFlag() && !shouldQuit()) {
637 if (_currentTalkSections.TLKTim)
638 _tim->exec(_currentTalkSections.TLKTim, false);
639 else
640 _tim->resetFinishedFlag();
641
642 updateWithText();
643 delay(10);
644 }
645
646 if (_currentTalkSections.TLKTim)
647 _tim->stopCurFunc();
648 }
649 updateWithText();
650 }
651
652 resetSkipFlag();
653
654 _tim->unload(_currentTalkSections.TLKTim);
655
656 _text->restoreScreen();
657 _chatText = 0;
658 _chatObject = -1;
659 setNextIdleAnimTimer();
660 }
661
setDlgIndex(int dlgIndex)662 void KyraEngine_HoF::setDlgIndex(int dlgIndex) {
663 if (dlgIndex == _mainCharacter.dlgIndex)
664 return;
665 memset(_newSceneDlgState, 0, 32);
666 for (int i = 0; i < 19; i++)
667 memset(_conversationState[i], -1, 14);
668 _chatAltFlag = false;
669 _mainCharacter.dlgIndex = dlgIndex;
670 }
671
672 } // End of namespace Kyra
673