ScummVM
text_mr.cpp
Go to the documentation of this file.
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_mr.h"
24 #include "kyra/resource/resource.h"
25 
26 #include "common/system.h"
27 
28 namespace Kyra {
29 
31  : TextDisplayer(vm, screen), _vm(vm), _screen(screen) {
32 }
33 
34 char *TextDisplayer_MR::preprocessString(const char *str) {
35  if (_talkBuffer != str) {
36  assert(strlen(str) < sizeof(_talkBuffer) - 1);
37  strcpy(_talkBuffer, str);
38  }
39 
40  char *p = _talkBuffer;
41  while (*p) {
42  if (*p++ == '\r')
43  return _talkBuffer;
44  }
45 
46  p = _talkBuffer;
48  _screen->_charWidth = -2;
49 
50  const int maxTextWidth = (_vm->language() == 0) ? 176 : 240;
51  int textWidth = _screen->getTextWidth(p);
52 
53  if (textWidth > maxTextWidth) {
54  int count = 0, offs = 0;
55  if (textWidth > (3*maxTextWidth)) {
56  count = getCharLength(p, textWidth/4);
57  offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth));
58  p += count + offs;
59  // No update of textWidth here
60  }
61 
62  if (textWidth > (2*maxTextWidth)) {
63  count = getCharLength(p, textWidth/3);
64  offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth));
65  p += count + offs;
66  textWidth = _screen->getTextWidth(p);
67  }
68 
69  count = getCharLength(p, textWidth/2);
70  offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth));
71  p += count + offs;
72  textWidth = _screen->getTextWidth(p);
73 
74  if (textWidth > maxTextWidth) {
75  count = getCharLength(p, textWidth/2);
76  offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth));
77  }
78  }
79 
80  _screen->setFont(curFont);
81  return _talkBuffer;
82 }
83 
84 int TextDisplayer_MR::dropCRIntoString(char *str, int minOffs, int maxOffs) {
85  int offset = 0;
86  char *proc = str + minOffs;
87 
88  for (int i = minOffs; i < maxOffs; ++i) {
89  if (*proc == ' ') {
90  *proc = '\r';
91  return offset;
92  } else if (*proc == '-') {
93  memmove(proc+1, proc, strlen(proc)+1);
94  *(++proc) = '\r';
95  ++offset;
96  return offset;
97  }
98 
99  ++offset;
100  ++proc;
101 
102  if (!*proc)
103  return 0;
104  }
105 
106  offset = 0;
107  proc = str + minOffs;
108  for (int i = minOffs; i >= 0; --i) {
109  if (*proc == ' ') {
110  *proc = '\r';
111  return offset;
112  } else if (*proc == '-') {
113  memmove(proc+1, proc, strlen(proc)+1);
114  *(++proc) = '\r';
115  ++offset;
116  return offset;
117  }
118 
119  --offset;
120  --proc;
121 
122  if (!*proc)
123  return 0;
124  }
125 
126  *(str + minOffs) = '\r';
127  return 0;
128 }
129 
130 void TextDisplayer_MR::printText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2) {
131  if (_vm->_albumChatActive) {
132  c0 = 0xEE;
133  c1 = 0xE3;
134  c2 = 0x00;
135  }
136 
137  uint8 colorMap[] = { 0, 255, 240, 240 };
138  colorMap[3] = c1;
139  _screen->setTextColor(colorMap, 0, 3);
140  _screen->_charWidth = -2;
141  _screen->printText(str, x, y, c0, c2);
142  _screen->_charWidth = 0;
143 }
144 
146  _vm->restorePage3();
147  _vm->drawAnimObjects();
151 }
152 
153 void TextDisplayer_MR::calcWidestLineBounds(int &x1, int &x2, int w, int x) {
154  x1 = x;
155  x1 -= (w >> 1);
156  x2 = x1 + w + 1;
157 
158  if (x1 + w >= 311)
159  x1 = 311 - w - 1;
160 
161  if (x1 < 8)
162  x1 = 8;
163 
164  x2 = x1 + w + 1;
165 }
166 
167 #pragma mark -
168 
169 int KyraEngine_MR::chatGetType(const char *str) {
170  while (*str)
171  ++str;
172  --str;
173  switch (*str) {
174  case '!':
175  return 2;
176 
177  case ')':
178  return 3;
179 
180  case '?':
181  return 1;
182 
183  case '.':
184  default:
185  return 0;
186  }
187 }
188 
189 int KyraEngine_MR::chatCalcDuration(const char *str) {
190  return MAX<int>(120, strlen(str)*6);
191 }
192 
193 void KyraEngine_MR::objectChat(const char *str, int object, int vocHigh, int vocLow) {
194  if (_mainCharacter.animFrame == 87 || _mainCharacter.animFrame == 0xFFFF || _mainCharacter.x1 <= 0 || _mainCharacter.y1 <= 0)
195  return;
196 
197  _chatVocLow = _chatVocHigh = -1;
198  objectChatInit(str, object, vocHigh, vocLow);
199  _chatText = str;
200  _chatObject = object;
201  int chatType = chatGetType(str);
202 
203  if (_mainCharacter.facing > 7)
204  _mainCharacter.facing = 5;
205 
206  static const uint8 talkScriptTable[] = {
207  0x10, 0x11, 0x12, 0x13,
208  0x0C, 0x0D, 0x0E, 0x0F,
209  0x0C, 0x0D, 0x0E, 0x0F,
210  0x04, 0x05, 0x06, 0x07,
211  0x00, 0x01, 0x02, 0x03,
212  0x00, 0x01, 0x02, 0x03,
213  0x08, 0x09, 0x0A, 0x0B,
214  0x08, 0x09, 0x0A, 0x0B
215  };
216 
217  static const char *const talkFilenameTable[] = {
218  "MTFL00S.EMC", "MTFL00Q.EMC", "MTFL00E.EMC", "MTFL00T.EMC",
219  "MTFR00S.EMC", "MTFR00Q.EMC", "MTFR00E.EMC", "MTFR00T.EMC",
220  "MTL00S.EMC", "MTL00Q.EMC", "MTL00E.EMC", "MTL00T.EMC",
221  "MTR00S.EMC", "MTR00Q.EMC", "MTR00E.EMC", "MTR00T.EMC",
222  "MTA00S.EMC", "MTA00Q.EMC", "MTA00E.EMC", "MTA00T.EMC"
223  };
224 
225  int chat = talkScriptTable[chatType + _mainCharacter.facing * 4];
226  objectChatProcess(talkFilenameTable[chat]);
227  _text->restoreScreen();
228  _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
229  updateCharacterAnim(0);
230  _chatText = 0;
231  _chatObject = -1;
232  setNextIdleAnimTimer();
233 }
234 
235 void KyraEngine_MR::objectChatInit(const char *str, int object, int vocHigh, int vocLow) {
236  str = _text->preprocessString(str);
237  int lineNum = _text->buildMessageSubstrings(str);
238 
239  int xPos = 0, yPos = 0;
240 
241  if (!object) {
242  int scale = getScale(_mainCharacter.x1, _mainCharacter.y1);
243  yPos = _mainCharacter.y1 - ((_mainCharacter.height * scale) >> 8) - 8;
244  xPos = _mainCharacter.x1;
245  } else {
246  yPos = _talkObjectList[object].y;
247  xPos = _talkObjectList[object].x;
248  }
249 
250  yPos -= lineNum * 10;
251  yPos = MAX(yPos, 0);
252  _text->_talkMessageY = yPos;
253  _text->_talkMessageH = lineNum*10;
254 
255  int width = _text->getWidestLineWidth(lineNum);
256  _text->calcWidestLineBounds(xPos, yPos, width, xPos);
257  _text->_talkCoords.x = xPos;
258  _text->_talkCoords.w = width + 2;
259 
260  restorePage3();
261 
262  _chatTextEnabled = textEnabled();
263  if (_chatTextEnabled) {
264  objectChatPrintText(str, object);
265  _chatEndTime = _system->getMillis() + chatCalcDuration(str) * _tickLength;
266  } else {
267  _chatEndTime = _system->getMillis();
268  }
269 
270  if (speechEnabled()) {
271  _chatVocHigh = vocHigh;
272  _chatVocLow = vocLow;
273  } else {
274  _chatVocHigh = _chatVocLow = -1;
275  }
276 }
277 
278 void KyraEngine_MR::objectChatPrintText(const char *str, int object) {
279  int c1 = _talkObjectList[object].color;
280  str = _text->preprocessString(str);
281  int lineNum = _text->buildMessageSubstrings(str);
282  int maxWidth = _text->getWidestLineWidth(lineNum);
283  int x = (object == 0) ? _mainCharacter.x1 : _talkObjectList[object].x;
284  int cX1 = 0, cX2 = 0;
285  _text->calcWidestLineBounds(cX1, cX2, maxWidth, x);
286 
287  for (int i = 0; i < lineNum; ++i) {
288  str = &_text->_talkSubstrings[i*_text->maxSubstringLen()];
289 
290  int y = _text->_talkMessageY + i * 10;
291  x = _text->getCenterStringX(str, cX1, cX2);
292 
293  _text->printText(str, x, y, c1, 0xF0, 0);
294  }
295 }
296 
297 void KyraEngine_MR::objectChatProcess(const char *script) {
298  memset(&_chatScriptData, 0, sizeof(_chatScriptData));
299  memset(&_chatScriptState, 0, sizeof(_chatScriptState));
300 
301  _emc->load(script, &_chatScriptData, &_opcodesAnimation);
302  _emc->init(&_chatScriptState, &_chatScriptData);
303  _emc->start(&_chatScriptState, 0);
304  while (_emc->isValid(&_chatScriptState))
305  _emc->run(&_chatScriptState);
306 
307  if (_chatVocHigh >= 0) {
308  playVoice(_chatVocHigh, _chatVocLow);
309  _chatVocHigh = _chatVocLow = -1;
310  }
311 
312  _useFrameTable = true;
313  objectChatWaitToFinish();
314  _useFrameTable = false;
315 
316  _emc->unload(&_chatScriptData);
317 }
318 
320  int charAnimFrame = _mainCharacter.animFrame;
321  setCharacterAnimDim(_animShapeWidth, _animShapeHeight);
322 
323  _emc->init(&_chatScriptState, &_chatScriptData);
324  _emc->start(&_chatScriptState, 1);
325 
326  bool running = true;
327  const uint32 endTime = _chatEndTime;
328  resetSkipFlag();
329 
330  while (running && !shouldQuit()) {
331  if (!_emc->isValid(&_chatScriptState))
332  _emc->start(&_chatScriptState, 1);
333 
334  _animNeedUpdate = false;
335  while (!_animNeedUpdate && _emc->isValid(&_chatScriptState) && !shouldQuit())
336  _emc->run(&_chatScriptState);
337 
338  int curFrame = _animNewFrame;
339  uint32 delayTime = _animDelayTime;
340 
341  _mainCharacter.animFrame = curFrame;
342  updateCharacterAnim(0);
343 
344  uint32 nextFrame = _system->getMillis() + delayTime * _tickLength;
345 
346  while (_system->getMillis() < nextFrame && !shouldQuit()) {
347  updateWithText();
348 
349  const uint32 curTime = _system->getMillis();
350  if ((textEnabled() && !speechEnabled() && curTime > endTime) || (speechEnabled() && !snd_voiceIsPlaying()) || skipFlag()) {
351  snd_stopVoice();
352  resetSkipFlag();
353  nextFrame = curTime;
354  running = false;
355  }
356 
357  delay(10);
358  }
359  }
360 
361  _mainCharacter.animFrame = charAnimFrame;
362  updateCharacterAnim(0);
363  resetCharacterAnimDim();
364 }
365 
366 void KyraEngine_MR::badConscienceChat(const char *str, int vocHigh, int vocLow) {
367  if (!_badConscienceShown)
368  return;
369 
370  setNextIdleAnimTimer();
371  _chatVocHigh = _chatVocLow = -1;
372  objectChatInit(str, 1, vocHigh, vocLow);
373  _chatText = str;
374  _chatObject = 1;
375  badConscienceChatWaitToFinish();
376  updateSceneAnim(0x0E, _badConscienceFrameTable[_badConscienceAnim+16]);
377  _text->restoreScreen();
378  update();
379  _chatText = 0;
380  _chatObject = -1;
381 }
382 
384  if (_chatVocHigh) {
385  playVoice(_chatVocHigh, _chatVocLow);
386  _chatVocHigh = _chatVocLow = -1;
387  }
388 
389  bool running = true;
390  const uint32 endTime = _chatEndTime;
391  resetSkipFlag();
392 
393  uint32 nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(4, 8) * _tickLength;
394 
395  int frame = _badConscienceFrameTable[_badConscienceAnim+24];
396  while (running && !shouldQuit()) {
397  if (nextFrame < _system->getMillis()) {
398  ++frame;
399  if (_badConscienceFrameTable[_badConscienceAnim+32] < frame)
400  frame = _badConscienceFrameTable[_badConscienceAnim+24];
401 
402  updateSceneAnim(0x0E, frame);
403  updateWithText();
404 
405  nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(4, 8) * _tickLength;
406  }
407 
408  updateWithText();
409 
410  const uint32 curTime = _system->getMillis();
411  if ((textEnabled() && !speechEnabled() && curTime > endTime) || (speechEnabled() && !snd_voiceIsPlaying()) || skipFlag()) {
412  snd_stopVoice();
413  resetSkipFlag();
414  nextFrame = curTime;
415  running = false;
416  }
417 
418  delay(10);
419  }
420 }
421 
422 void KyraEngine_MR::goodConscienceChat(const char *str, int vocHigh, int vocLow) {
423  if (!_goodConscienceShown)
424  return;
425 
426  setNextIdleAnimTimer();
427  _chatVocHigh = _chatVocLow = -1;
428  objectChatInit(str, 87, vocHigh, vocLow);
429  _chatText = str;
430  _chatObject = 87;
431  goodConscienceChatWaitToFinish();
432  updateSceneAnim(0x0F, _goodConscienceFrameTable[_goodConscienceAnim+10]);
433  _text->restoreScreen();
434  update();
435  _chatText = 0;
436  _chatObject = -1;
437 }
438 
440  if (_chatVocHigh) {
441  playVoice(_chatVocHigh, _chatVocLow);
442  _chatVocHigh = _chatVocLow = -1;
443  }
444 
445  bool running = true;
446  const uint32 endTime = _chatEndTime;
447  resetSkipFlag();
448 
449  uint32 nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(3, 6) * _tickLength;
450 
451  int frame = _goodConscienceFrameTable[_goodConscienceAnim+15];
452  while (running && !shouldQuit()) {
453  if (nextFrame < _system->getMillis()) {
454  ++frame;
455  if (_goodConscienceFrameTable[_goodConscienceAnim+20] < frame)
456  frame = _goodConscienceFrameTable[_goodConscienceAnim+15];
457 
458  updateSceneAnim(0x0F, frame);
459  updateWithText();
460 
461  nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(3, 6) * _tickLength;
462  }
463 
464  updateWithText();
465 
466  const uint32 curTime = _system->getMillis();
467  if ((textEnabled() && !speechEnabled() && curTime > endTime) || (speechEnabled() && !snd_voiceIsPlaying()) || skipFlag()) {
468  snd_stopVoice();
469  resetSkipFlag();
470  nextFrame = curTime;
471  running = false;
472  }
473 
474  delay(10);
475  }
476 }
477 
478 void KyraEngine_MR::albumChat(const char *str, int vocHigh, int vocLow) {
479  _talkObjectList[1].x = 190;
480  _talkObjectList[1].y = 188;
481 
482  _chatVocHigh = _chatVocLow = -1;
483  _albumChatActive = true;
484  albumChatInit(str, 1, vocHigh, vocLow);
485  _albumChatActive = false;
486 
487  _chatText = str;
488  _chatObject = 1;
489  _screen->hideMouse();
490  albumChatWaitToFinish();
491  _screen->showMouse();
492 
493  _chatText = 0;
494  _chatObject = -1;
495 }
496 
497 void KyraEngine_MR::albumChatInit(const char *str, int object, int vocHigh, int vocLow) {
498  Common::String realString;
499 
500  while (*str) {
501  if (str[0] == '\\' && str[1] == 'r') {
502  realString += '\r';
503  ++str;
504  } else {
505  realString += *str;
506  }
507 
508  ++str;
509  }
510 
511  str = realString.c_str();
512 
513  str = _text->preprocessString(str);
514  int lineNum = _text->buildMessageSubstrings(str);
515 
516  int xPos = 0, yPos = 0;
517 
518  if (!object) {
519  int scale = getScale(_mainCharacter.x1, _mainCharacter.y1);
520  yPos = _mainCharacter.y1 - ((_mainCharacter.height * scale) >> 8) - 8;
521  xPos = _mainCharacter.x1;
522  } else {
523  yPos = _talkObjectList[object].y;
524  xPos = _talkObjectList[object].x;
525  }
526 
527  yPos -= lineNum * 10;
528  yPos = MAX(yPos, 0);
529  _text->_talkMessageY = yPos;
530  _text->_talkMessageH = lineNum*10;
531 
532  int width = _text->getWidestLineWidth(lineNum);
533  _text->calcWidestLineBounds(xPos, yPos, width, xPos);
534  _text->_talkCoords.x = xPos;
535  _text->_talkCoords.w = width + 2;
536 
537  _screen->hideMouse();
538 
539  if (textEnabled()) {
540  objectChatPrintText(str, object);
541  _chatEndTime = _system->getMillis() + chatCalcDuration(str) * _tickLength;
542  } else {
543  _chatEndTime = _system->getMillis();
544  }
545 
546  if (speechEnabled()) {
547  _chatVocHigh = vocHigh;
548  _chatVocLow = vocLow;
549  } else {
550  _chatVocHigh = _chatVocLow = -1;
551  }
552 
553  _screen->showMouse();
554 }
555 
557  if (_chatVocHigh) {
558  playVoice(_chatVocHigh, _chatVocLow);
559  _chatVocHigh = _chatVocLow = -1;
560  }
561 
562  bool running = true;
563  const uint32 endTime = _chatEndTime;
564  resetSkipFlag();
565 
566  uint32 nextFrame = 0;
567  int frame = 12;
568  while (running && !shouldQuit()) {
569  if (nextFrame < _system->getMillis()) {
570  ++frame;
571  if (frame > 22)
572  frame = 13;
573 
574  albumRestoreRect();
575  _album.wsa->displayFrame(frame, 2, -100, 90, 0x4000, 0, 0);
576  albumUpdateRect();
577 
578  nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(4, 8) * _tickLength;
579  }
580 
581  if (_album.nextPage != 14)
582  albumUpdateAnims();
583  else
585 
586  const uint32 curTime = _system->getMillis();
587  if ((textEnabled() && !speechEnabled() && curTime > endTime) || (speechEnabled() && !snd_voiceIsPlaying()) || skipFlag()) {
588  snd_stopVoice();
589  resetSkipFlag();
590  nextFrame = curTime;
591  running = false;
592  }
593 
594  delay(10);
595  }
596 }
597 
599  if (_noStartupChat)
600  return;
601 
602  int index = _mainCharacter.sceneId - _chapterLowestScene[_currentChapter];
603  if (_newSceneDlgState[index])
604  return;
605 
606  updateDlgBuffer();
607  int vocHighBase = 0, vocHighIndex = 0, index1 = 0, index2 = 0;
608  loadDlgHeader(vocHighBase, vocHighIndex, index1, index2);
609 
610  _cnvFile->seek(index1*6, SEEK_CUR);
611  _cnvFile->seek(index2*4, SEEK_CUR);
612  _cnvFile->seek(index*2, SEEK_CUR);
613  _cnvFile->seek(_cnvFile->readUint16LE(), SEEK_SET);
614 
615  _isStartupDialog = true;
616  processDialog(vocHighIndex, vocHighBase, 0);
617  _isStartupDialog = false;
618  _newSceneDlgState[index] = true;
619 }
620 
622  if (_cnvFile)
623  _cnvFile->seek(0, SEEK_SET);
624 
625  if (_curDlgIndex == _mainCharacter.dlgIndex && _curDlgChapter == _currentChapter && _curDlgLang == _lang)
626  return;
627 
628  Common::String dlgFile = Common::String::format("CH%.02d-S%.02d.%s", _currentChapter, _mainCharacter.dlgIndex, _languageExtension[_lang]);
629  Common::String cnvFile = Common::String::format("CH%.02d-S%.02d.CNV", _currentChapter, _mainCharacter.dlgIndex);
630 
631  delete _cnvFile;
632  delete _dlgBuffer;
633 
634  _res->exists(cnvFile.c_str(), true);
635  _res->exists(dlgFile.c_str(), true);
636  _cnvFile = _res->createReadStream(cnvFile);
637  _dlgBuffer = _res->createReadStream(dlgFile);
638  assert(_cnvFile);
639  assert(_dlgBuffer);
640 }
641 
642 void KyraEngine_MR::loadDlgHeader(int &vocHighBase, int &vocHighIndex, int &index1, int &index2) {
643  assert(_cnvFile);
644  vocHighIndex = _cnvFile->readSint16LE();
645  vocHighBase = _cnvFile->readSint16LE();
646  index1 = _cnvFile->readSint16LE();
647  index2 = _cnvFile->readSint16LE();
648 }
649 
651  if (_mainCharacter.dlgIndex != index) {
652  memset(_newSceneDlgState, 0, sizeof(_newSceneDlgState));
653  memset(_conversationState, -1, sizeof(_conversationState));
654  _chatAltFlag = false;
655  _mainCharacter.dlgIndex = index;
656  }
657 }
658 
660  uint16 dlgIndex = _mainCharacter.dlgIndex;
661 
662  if (_currentChapter == 1) {
663  static const uint8 dlgIndexMoodNice[] = { 0x0C, 0x0E, 0x10, 0x0F, 0x11 };
664  static const uint8 dlgIndexMoodNormal[] = { 0x00, 0x02, 0x04, 0x03, 0x05 };
665  static const uint8 dlgIndexMoodEvil[] = { 0x06, 0x08, 0x0A, 0x09, 0x0B };
666 
667  if (_malcolmsMood == 0)
668  dlgIndex = dlgIndexMoodNice[_characterShapeFile];
669  else if (_malcolmsMood == 1)
670  dlgIndex = dlgIndexMoodNormal[_characterShapeFile];
671  else if (_malcolmsMood == 2)
672  dlgIndex = dlgIndexMoodEvil[_characterShapeFile];
673  } else if (_currentChapter == 2) {
674  if (dlgIndex >= 8)
675  dlgIndex -= 4;
676  if (dlgIndex >= 4)
677  dlgIndex -= 4;
678 
679  if (_malcolmsMood == 0)
680  dlgIndex += 8;
681  else if (_malcolmsMood == 2)
682  dlgIndex += 4;
683  } else if (_currentChapter == 4) {
684  if (dlgIndex >= 10)
685  dlgIndex -= 5;
686  if (dlgIndex >= 5)
687  dlgIndex -= 5;
688 
689  if (_malcolmsMood == 0)
690  dlgIndex += 10;
691  else if (_malcolmsMood == 2)
692  dlgIndex += 5;
693  }
694 
695  _mainCharacter.dlgIndex = dlgIndex;
696 }
697 
698 void KyraEngine_MR::processDialog(int vocHighIndex, int vocHighBase, int funcNum) {
699  bool running = true;
700  int script = -1;
701  int vocHigh = -1, vocLow = -1;
702 
703  while (running) {
704  uint16 cmd = _cnvFile->readUint16LE();
705  int object = cmd - 12;
706 
707  if (cmd == 10) {
708  break;
709  } else if (cmd == 4) {
710  vocHighBase = _cnvFile->readUint16LE();
711  setDlgIndex(vocHighBase);
712  } else if (cmd == 11) {
713  int strSize = _cnvFile->readUint16LE();
714  vocLow = _cnvFile->readUint16LE();
715  _cnvFile->read(_stringBuffer, strSize);
716  _stringBuffer[strSize] = 0;
717  } else {
718  vocHigh = _vocHighTable[vocHighIndex-1] + vocHighBase;
719  vocLow = _cnvFile->readUint16LE();
720  getTableEntry(_dlgBuffer, vocLow, _stringBuffer);
721 
722  if (_isStartupDialog) {
723  delay(60*_tickLength, true);
724  _isStartupDialog = false;
725  }
726 
727  if (*_stringBuffer == 0)
728  continue;
729 
730  if (cmd != 12) {
731  if (object != script) {
732  if (script >= 0) {
733  dialogEndScript(script);
734  script = -1;
735  }
736 
737  dialogStartScript(object, funcNum);
738  script = object;
739  }
740 
741  npcChatSequence(_stringBuffer, object, vocHigh, vocLow);
742  } else {
743  if (script >= 0) {
744  dialogEndScript(script);
745  script = -1;
746  }
747 
748  objectChat(_stringBuffer, 0, vocHigh, vocLow);
749  playStudioSFX(_stringBuffer);
750  }
751  }
752  }
753 
754  if (script != -1)
755  dialogEndScript(script);
756 }
757 
758 void KyraEngine_MR::dialogStartScript(int object, int funcNum) {
759  _dialogSceneAnim = _talkObjectList[object].sceneAnim;
760  _dialogSceneScript = _talkObjectList[object].sceneScript;
761  if (_dialogSceneAnim >= 0 && _dialogSceneScript >= 0) {
762  _specialSceneScriptStateBackup[_dialogSceneScript] = _specialSceneScriptState[_dialogSceneScript];
763  _specialSceneScriptState[_dialogSceneScript] = true;
764  }
765 
766  _emc->init(&_dialogScriptState, &_dialogScriptData);
767  _emc->load(_talkObjectList[object].filename, &_dialogScriptData, &_opcodesDialog);
768 
769  _dialogScriptFuncStart = funcNum * 3 + 0;
770  _dialogScriptFuncProc = funcNum * 3 + 1;
771  _dialogScriptFuncEnd = funcNum * 3 + 2;
772 
773  _emc->start(&_dialogScriptState, _dialogScriptFuncStart);
774  while (_emc->isValid(&_dialogScriptState))
775  _emc->run(&_dialogScriptState);
776 }
777 
779  _emc->init(&_dialogScriptState, &_dialogScriptData);
780  _emc->start(&_dialogScriptState, _dialogScriptFuncEnd);
781 
782  while (_emc->isValid(&_dialogScriptState))
783  _emc->run(&_dialogScriptState);
784 
785  if (_dialogSceneAnim >= 0 && _dialogSceneScript >= 0) {
786  _specialSceneScriptState[_dialogSceneScript] = _specialSceneScriptStateBackup[_dialogSceneScript];
787  _dialogSceneScript = _dialogSceneAnim = -1;
788  }
789 
790  _emc->unload(&_dialogScriptData);
791 }
792 
793 void KyraEngine_MR::npcChatSequence(const char *str, int object, int vocHigh, int vocLow) {
794  _chatText = str;
795  _chatObject = object;
796  _chatVocHigh = _chatVocLow = -1;
797 
798  objectChatInit(str, object, vocHigh, vocLow);
799 
800  if (_chatVocHigh >= 0 && _chatVocLow >= 0) {
801  playVoice(_chatVocHigh, _chatVocLow);
802  _chatVocHigh = _chatVocLow = -1;
803  }
804 
805  _emc->init(&_dialogScriptState, &_dialogScriptData);
806  _emc->start(&_dialogScriptState, _dialogScriptFuncProc);
807 
808  resetSkipFlag();
809 
810  uint32 endTime = _chatEndTime;
811  bool running = true;
812  while (running && !shouldQuit()) {
813  if (!_emc->run(&_dialogScriptState)) {
814  _emc->init(&_dialogScriptState, &_dialogScriptData);
815  _emc->start(&_dialogScriptState, _dialogScriptFuncProc);
816  }
817 
818  const uint32 curTime = _system->getMillis();
819  if ((textEnabled() && !speechEnabled() && curTime > endTime) || (speechEnabled() && !snd_voiceIsPlaying()) || skipFlag()) {
820  snd_stopVoice();
821  resetSkipFlag();
822  running = false;
823  }
824  }
825  _text->restoreScreen();
826  _chatText = 0;
827  _chatObject= - 1;
828 }
829 
831  updateDlgBuffer();
832 
833  int index = (_mainCharacter.sceneId - _chapterLowestScene[_currentChapter]) * 2;
834 
835  int vocHighBase = 0, vocHighIndex = 0, index1 = 0, index2 = 0;
836  loadDlgHeader(vocHighBase, vocHighIndex, index1, index2);
837 
838  if (_chatAltFlag)
839  index++;
840  _chatAltFlag = !_chatAltFlag;
841 
842  _cnvFile->seek(index1*6, SEEK_CUR);
843  _cnvFile->seek(index*2, SEEK_CUR);
844  _cnvFile->seek(_cnvFile->readUint16LE(), SEEK_SET);
845 
846  processDialog(vocHighIndex, vocHighBase, 0);
847 }
848 
849 void KyraEngine_MR::doDialog(int dlgIndex, int funcNum) {
850  switch (_currentChapter-2) {
851  case 0:
852  dlgIndex -= 34;
853  break;
854 
855  case 1:
856  dlgIndex -= 54;
857  break;
858 
859  case 2:
860  dlgIndex -= 55;
861  break;
862 
863  case 3:
864  dlgIndex -= 70;
865  break;
866 
867  default:
868  break;
869  }
870 
871  updateDlgBuffer();
872 
873  int vocHighBase = 0, vocHighIndex = 0, index1 = 0, index2 = 0;
874  loadDlgHeader(vocHighBase, vocHighIndex, index1, index2);
875 
876  int convState = _conversationState[dlgIndex][vocHighBase];
877  uint32 offset = ((vocHighIndex == 1) ? dlgIndex - 1 : dlgIndex) * 6;
878  if (convState == -1) {
879  _cnvFile->seek(offset, SEEK_CUR);
880  _conversationState[dlgIndex][vocHighBase] = 0;
881  } else if (convState == 0 || convState == 2) {
882  _cnvFile->seek(offset+2, SEEK_CUR);
883  _conversationState[dlgIndex][vocHighBase] = 1;
884  } else {
885  _cnvFile->seek(offset+4, SEEK_CUR);
886  _conversationState[dlgIndex][vocHighBase] = 2;
887  }
888 
889  _cnvFile->seek(_cnvFile->readUint16LE(), SEEK_SET);
890 
891  processDialog(vocHighIndex, vocHighBase, funcNum);
892 }
893 
894 } // End of namespace Kyra
void objectChatPrintText(const char *text, int object)
Definition: text_mr.cpp:278
FontId setFont(FontId fontId)
Definition: screen.cpp:1395
int getTextWidth(const char *str)
Definition: screen.cpp:1416
unsigned short uint16
Definition: cdtypes.h:27
Simple string class for ScummVM.
Definition: str.h:49
Screen_MR * _screen
Definition: text_mr.h:47
void objectChatProcess(const char *script)
Definition: text_mr.cpp:297
unsigned int uint32
Definition: cdtypes.h:26
int count
Definition: voc.cpp:116
#define SEEK_CUR
Definition: gba_nds_fat.h:77
#define assert(s)
Definition: portdefs.h:77
uint16 _talkMessageH
Definition: text.h:54
void goodConscienceChat(const char *str, int vocHigh, int vocLow)
Definition: text_mr.cpp:422
int y
Definition: dialogs.cpp:409
uint16 _talkMessageY
Definition: text.h:53
void printText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2)
Definition: text_mr.cpp:130
void randomSceneChat()
Definition: text_mr.cpp:830
unsigned char uint8
Definition: cdtypes.h:28
TextDisplayer_MR(KyraEngine_MR *vm, Screen_MR *screen)
Definition: text_mr.cpp:30
void doDialog(int dlgIndex, int funcNum)
Definition: text_mr.cpp:849
static u8 delay
Definition: keys.cpp:86
KyraEngine_MR * _vm
Definition: text_mr.h:46
void albumChatWaitToFinish()
Definition: text_mr.cpp:556
uint32 offset
Definition: voc.cpp:110
#define SEEK_SET
Definition: gba_nds_fat.h:76
int _charWidth
Definition: screen.h:626
int chatCalcDuration(const char *text)
Definition: text_mr.cpp:189
int getMillis(bool skipRecord)
Definition: dsmain.cpp:2276
TalkCoords _talkCoords
Definition: text.h:75
void updateScreen()
Definition: screen.cpp:324
void printText(const char *str, int x, int y, uint8 color1, uint8 color2)
Definition: screen.cpp:1443
void albumChatInit(const char *str, int object, int vocHigh, int vocLow)
Definition: text_mr.cpp:497
int getCharLength(const char *str, int len)
Definition: text.cpp:54
char screen[320 *200]
Definition: gfxModule.cpp:39
const char * c_str() const
Definition: str.h:208
void hideMouse()
Definition: screen.cpp:3029
void copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage, int flags=0)
Definition: screen.cpp:1007
void objectChatWaitToFinish()
Definition: text_mr.cpp:319
void badConscienceChat(const char *str, int vocHigh, int vocLow)
Definition: text_mr.cpp:366
void refreshAnimObjects(int force)
void showMouse()
Definition: screen.cpp:3034
CruiseEngine * _vm
Definition: cruise.cpp:41
int dropCRIntoString(char *str, int minOffs, int maxOffs)
Definition: text_mr.cpp:84
void setDlgIndex(int index)
Definition: text_mr.cpp:650
Common::String filename
Definition: action.cpp:479
char _talkBuffer[1040]
Definition: text.h:73
SceneIndex index
Definition: action.cpp:432
uint16 width
Definition: thumbnail.cpp:41
This is the namespace of the Kyra engine.
Definition: chargen.cpp:37
void setTextColor(const uint8 *cmap, int a, int b)
Definition: screen.cpp:1339
void dialogEndScript(int object)
Definition: text_mr.cpp:778
int chatGetType(const char *text)
Definition: text_mr.cpp:169
void goodConscienceChatWaitToFinish()
Definition: text_mr.cpp:439
void dialogStartScript(int object, int funcNum)
Definition: text_mr.cpp:758
void malcolmSceneStartupChat()
Definition: text_mr.cpp:598
void loadDlgHeader(int &vocHighBase, int &vocHighIndex, int &index1, int &index2)
Definition: text_mr.cpp:642
void update()
Definition: cdaudio.cpp:249
void npcChatSequence(const char *str, int object, int vocHigh, int vocLow)
Definition: text_mr.cpp:793
int language() const
Definition: kyra_mr.h:59
static int playVoice(lua_State *L)
void objectChatInit(const char *text, int object, int vocHigh, int vocLow)
Definition: text_mr.cpp:235
uint8 frame
Definition: trainline.cpp:37
void updateDlgBuffer()
Definition: text_mr.cpp:621
void calcWidestLineBounds(int &x1, int &x2, int w, int x)
Definition: text_mr.cpp:153
void badConscienceChatWaitToFinish()
Definition: text_mr.cpp:383
T MAX(T a, T b)
Definition: util.h:50
static String format(const char *fmt,...) GCC_PRINTF(1
Print formatted data into a String object.
Definition: str.cpp:634
char * preprocessString(const char *str)
Definition: text_mr.cpp:34
#define proc(x)
ObjectIndex object
Definition: action.cpp:490
void albumChat(const char *str, int vocHigh, int vocLow)
Definition: text_mr.cpp:478
void processDialog(int vocHighIndex, int vocHighBase, int funcNum)
Definition: text_mr.cpp:698
void objectChat(const char *text, int object, int vocHigh, int vocLow)
Definition: text_mr.cpp:193