aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra/text/text_mr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/kyra/text/text_mr.cpp')
-rw-r--r--engines/kyra/text/text_mr.cpp894
1 files changed, 894 insertions, 0 deletions
diff --git a/engines/kyra/text/text_mr.cpp b/engines/kyra/text/text_mr.cpp
new file mode 100644
index 0000000000..8400700503
--- /dev/null
+++ b/engines/kyra/text/text_mr.cpp
@@ -0,0 +1,894 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kyra/text/text_mr.h"
+#include "kyra/resource/resource.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+TextDisplayer_MR::TextDisplayer_MR(KyraEngine_MR *vm, Screen_MR *screen)
+ : TextDisplayer(vm, screen), _vm(vm), _screen(screen) {
+}
+
+char *TextDisplayer_MR::preprocessString(const char *str) {
+ if (_talkBuffer != str) {
+ assert(strlen(str) < sizeof(_talkBuffer) - 1);
+ strcpy(_talkBuffer, str);
+ }
+
+ char *p = _talkBuffer;
+ while (*p) {
+ if (*p++ == '\r')
+ return _talkBuffer;
+ }
+
+ p = _talkBuffer;
+ Screen::FontId curFont = _screen->setFont(Screen::FID_8_FNT);
+ _screen->_charWidth = -2;
+
+ const int maxTextWidth = (_vm->language() == 0) ? 176 : 240;
+ int textWidth = _screen->getTextWidth(p);
+
+ if (textWidth > maxTextWidth) {
+ int count = 0, offs = 0;
+ if (textWidth > (3*maxTextWidth)) {
+ count = getCharLength(p, textWidth/4);
+ offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth));
+ p += count + offs;
+ // No update of textWidth here
+ }
+
+ if (textWidth > (2*maxTextWidth)) {
+ count = getCharLength(p, textWidth/3);
+ offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth));
+ p += count + offs;
+ textWidth = _screen->getTextWidth(p);
+ }
+
+ count = getCharLength(p, textWidth/2);
+ offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth));
+ p += count + offs;
+ textWidth = _screen->getTextWidth(p);
+
+ if (textWidth > maxTextWidth) {
+ count = getCharLength(p, textWidth/2);
+ offs = dropCRIntoString(p, count, getCharLength(p, maxTextWidth));
+ }
+ }
+
+ _screen->setFont(curFont);
+ return _talkBuffer;
+}
+
+int TextDisplayer_MR::dropCRIntoString(char *str, int minOffs, int maxOffs) {
+ int offset = 0;
+ char *proc = str + minOffs;
+
+ for (int i = minOffs; i < maxOffs; ++i) {
+ if (*proc == ' ') {
+ *proc = '\r';
+ return offset;
+ } else if (*proc == '-') {
+ memmove(proc+1, proc, strlen(proc)+1);
+ *(++proc) = '\r';
+ ++offset;
+ return offset;
+ }
+
+ ++offset;
+ ++proc;
+
+ if (!*proc)
+ return 0;
+ }
+
+ offset = 0;
+ proc = str + minOffs;
+ for (int i = minOffs; i >= 0; --i) {
+ if (*proc == ' ') {
+ *proc = '\r';
+ return offset;
+ } else if (*proc == '-') {
+ memmove(proc+1, proc, strlen(proc)+1);
+ *(++proc) = '\r';
+ ++offset;
+ return offset;
+ }
+
+ --offset;
+ --proc;
+
+ if (!*proc)
+ return 0;
+ }
+
+ *(str + minOffs) = '\r';
+ return 0;
+}
+
+void TextDisplayer_MR::printText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2) {
+ if (_vm->_albumChatActive) {
+ c0 = 0xEE;
+ c1 = 0xE3;
+ c2 = 0x00;
+ }
+
+ uint8 colorMap[] = { 0, 255, 240, 240 };
+ colorMap[3] = c1;
+ _screen->setTextColor(colorMap, 0, 3);
+ _screen->_charWidth = -2;
+ _screen->printText(str, x, y, c0, c2);
+ _screen->_charWidth = 0;
+}
+
+void TextDisplayer_MR::restoreScreen() {
+ _vm->restorePage3();
+ _vm->drawAnimObjects();
+ _screen->copyRegion(_talkCoords.x, _talkMessageY, _talkCoords.x, _talkMessageY, _talkCoords.w, _talkMessageH, 2, 0, Screen::CR_NO_P_CHECK);
+ _vm->flagAnimObjsForRefresh();
+ _vm->refreshAnimObjects(0);
+}
+
+void TextDisplayer_MR::calcWidestLineBounds(int &x1, int &x2, int w, int x) {
+ x1 = x;
+ x1 -= (w >> 1);
+ x2 = x1 + w + 1;
+
+ if (x1 + w >= 311)
+ x1 = 311 - w - 1;
+
+ if (x1 < 8)
+ x1 = 8;
+
+ x2 = x1 + w + 1;
+}
+
+#pragma mark -
+
+int KyraEngine_MR::chatGetType(const char *str) {
+ while (*str)
+ ++str;
+ --str;
+ switch (*str) {
+ case '!':
+ return 2;
+
+ case ')':
+ return 3;
+
+ case '?':
+ return 1;
+
+ case '.':
+ default:
+ return 0;
+ }
+}
+
+int KyraEngine_MR::chatCalcDuration(const char *str) {
+ return MAX<int>(120, strlen(str)*6);
+}
+
+void KyraEngine_MR::objectChat(const char *str, int object, int vocHigh, int vocLow) {
+ if (_mainCharacter.animFrame == 87 || _mainCharacter.animFrame == 0xFFFF || _mainCharacter.x1 <= 0 || _mainCharacter.y1 <= 0)
+ return;
+
+ _chatVocLow = _chatVocHigh = -1;
+ objectChatInit(str, object, vocHigh, vocLow);
+ _chatText = str;
+ _chatObject = object;
+ int chatType = chatGetType(str);
+
+ if (_mainCharacter.facing > 7)
+ _mainCharacter.facing = 5;
+
+ static const uint8 talkScriptTable[] = {
+ 0x10, 0x11, 0x12, 0x13,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03,
+ 0x00, 0x01, 0x02, 0x03,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x08, 0x09, 0x0A, 0x0B
+ };
+
+ static const char *const talkFilenameTable[] = {
+ "MTFL00S.EMC", "MTFL00Q.EMC", "MTFL00E.EMC", "MTFL00T.EMC",
+ "MTFR00S.EMC", "MTFR00Q.EMC", "MTFR00E.EMC", "MTFR00T.EMC",
+ "MTL00S.EMC", "MTL00Q.EMC", "MTL00E.EMC", "MTL00T.EMC",
+ "MTR00S.EMC", "MTR00Q.EMC", "MTR00E.EMC", "MTR00T.EMC",
+ "MTA00S.EMC", "MTA00Q.EMC", "MTA00E.EMC", "MTA00T.EMC"
+ };
+
+ int chat = talkScriptTable[chatType + _mainCharacter.facing * 4];
+ objectChatProcess(talkFilenameTable[chat]);
+ _text->restoreScreen();
+ _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
+ updateCharacterAnim(0);
+ _chatText = 0;
+ _chatObject = -1;
+ setNextIdleAnimTimer();
+}
+
+void KyraEngine_MR::objectChatInit(const char *str, int object, int vocHigh, int vocLow) {
+ str = _text->preprocessString(str);
+ int lineNum = _text->buildMessageSubstrings(str);
+
+ int xPos = 0, yPos = 0;
+
+ if (!object) {
+ int scale = getScale(_mainCharacter.x1, _mainCharacter.y1);
+ yPos = _mainCharacter.y1 - ((_mainCharacter.height * scale) >> 8) - 8;
+ xPos = _mainCharacter.x1;
+ } else {
+ yPos = _talkObjectList[object].y;
+ xPos = _talkObjectList[object].x;
+ }
+
+ yPos -= lineNum * 10;
+ yPos = MAX(yPos, 0);
+ _text->_talkMessageY = yPos;
+ _text->_talkMessageH = lineNum*10;
+
+ int width = _text->getWidestLineWidth(lineNum);
+ _text->calcWidestLineBounds(xPos, yPos, width, xPos);
+ _text->_talkCoords.x = xPos;
+ _text->_talkCoords.w = width + 2;
+
+ restorePage3();
+
+ _chatTextEnabled = textEnabled();
+ if (_chatTextEnabled) {
+ objectChatPrintText(str, object);
+ _chatEndTime = _system->getMillis() + chatCalcDuration(str) * _tickLength;
+ } else {
+ _chatEndTime = _system->getMillis();
+ }
+
+ if (speechEnabled()) {
+ _chatVocHigh = vocHigh;
+ _chatVocLow = vocLow;
+ } else {
+ _chatVocHigh = _chatVocLow = -1;
+ }
+}
+
+void KyraEngine_MR::objectChatPrintText(const char *str, int object) {
+ int c1 = _talkObjectList[object].color;
+ str = _text->preprocessString(str);
+ int lineNum = _text->buildMessageSubstrings(str);
+ int maxWidth = _text->getWidestLineWidth(lineNum);
+ int x = (object == 0) ? _mainCharacter.x1 : _talkObjectList[object].x;
+ int cX1 = 0, cX2 = 0;
+ _text->calcWidestLineBounds(cX1, cX2, maxWidth, x);
+
+ for (int i = 0; i < lineNum; ++i) {
+ str = &_text->_talkSubstrings[i*_text->maxSubstringLen()];
+
+ int y = _text->_talkMessageY + i * 10;
+ x = _text->getCenterStringX(str, cX1, cX2);
+
+ _text->printText(str, x, y, c1, 0xF0, 0);
+ }
+}
+
+void KyraEngine_MR::objectChatProcess(const char *script) {
+ memset(&_chatScriptData, 0, sizeof(_chatScriptData));
+ memset(&_chatScriptState, 0, sizeof(_chatScriptState));
+
+ _emc->load(script, &_chatScriptData, &_opcodesAnimation);
+ _emc->init(&_chatScriptState, &_chatScriptData);
+ _emc->start(&_chatScriptState, 0);
+ while (_emc->isValid(&_chatScriptState))
+ _emc->run(&_chatScriptState);
+
+ if (_chatVocHigh >= 0) {
+ playVoice(_chatVocHigh, _chatVocLow);
+ _chatVocHigh = _chatVocLow = -1;
+ }
+
+ _useFrameTable = true;
+ objectChatWaitToFinish();
+ _useFrameTable = false;
+
+ _emc->unload(&_chatScriptData);
+}
+
+void KyraEngine_MR::objectChatWaitToFinish() {
+ int charAnimFrame = _mainCharacter.animFrame;
+ setCharacterAnimDim(_animShapeWidth, _animShapeHeight);
+
+ _emc->init(&_chatScriptState, &_chatScriptData);
+ _emc->start(&_chatScriptState, 1);
+
+ bool running = true;
+ const uint32 endTime = _chatEndTime;
+ resetSkipFlag();
+
+ while (running && !shouldQuit()) {
+ if (!_emc->isValid(&_chatScriptState))
+ _emc->start(&_chatScriptState, 1);
+
+ _animNeedUpdate = false;
+ while (!_animNeedUpdate && _emc->isValid(&_chatScriptState) && !shouldQuit())
+ _emc->run(&_chatScriptState);
+
+ int curFrame = _animNewFrame;
+ uint32 delayTime = _animDelayTime;
+
+ _mainCharacter.animFrame = curFrame;
+ updateCharacterAnim(0);
+
+ uint32 nextFrame = _system->getMillis() + delayTime * _tickLength;
+
+ while (_system->getMillis() < nextFrame && !shouldQuit()) {
+ updateWithText();
+
+ const uint32 curTime = _system->getMillis();
+ if ((textEnabled() && !speechEnabled() && curTime > endTime) || (speechEnabled() && !snd_voiceIsPlaying()) || skipFlag()) {
+ snd_stopVoice();
+ resetSkipFlag();
+ nextFrame = curTime;
+ running = false;
+ }
+
+ delay(10);
+ }
+ }
+
+ _mainCharacter.animFrame = charAnimFrame;
+ updateCharacterAnim(0);
+ resetCharacterAnimDim();
+}
+
+void KyraEngine_MR::badConscienceChat(const char *str, int vocHigh, int vocLow) {
+ if (!_badConscienceShown)
+ return;
+
+ setNextIdleAnimTimer();
+ _chatVocHigh = _chatVocLow = -1;
+ objectChatInit(str, 1, vocHigh, vocLow);
+ _chatText = str;
+ _chatObject = 1;
+ badConscienceChatWaitToFinish();
+ updateSceneAnim(0x0E, _badConscienceFrameTable[_badConscienceAnim+16]);
+ _text->restoreScreen();
+ update();
+ _chatText = 0;
+ _chatObject = -1;
+}
+
+void KyraEngine_MR::badConscienceChatWaitToFinish() {
+ if (_chatVocHigh) {
+ playVoice(_chatVocHigh, _chatVocLow);
+ _chatVocHigh = _chatVocLow = -1;
+ }
+
+ bool running = true;
+ const uint32 endTime = _chatEndTime;
+ resetSkipFlag();
+
+ uint32 nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(4, 8) * _tickLength;
+
+ int frame = _badConscienceFrameTable[_badConscienceAnim+24];
+ while (running && !shouldQuit()) {
+ if (nextFrame < _system->getMillis()) {
+ ++frame;
+ if (_badConscienceFrameTable[_badConscienceAnim+32] < frame)
+ frame = _badConscienceFrameTable[_badConscienceAnim+24];
+
+ updateSceneAnim(0x0E, frame);
+ updateWithText();
+
+ nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(4, 8) * _tickLength;
+ }
+
+ updateWithText();
+
+ const uint32 curTime = _system->getMillis();
+ if ((textEnabled() && !speechEnabled() && curTime > endTime) || (speechEnabled() && !snd_voiceIsPlaying()) || skipFlag()) {
+ snd_stopVoice();
+ resetSkipFlag();
+ nextFrame = curTime;
+ running = false;
+ }
+
+ delay(10);
+ }
+}
+
+void KyraEngine_MR::goodConscienceChat(const char *str, int vocHigh, int vocLow) {
+ if (!_goodConscienceShown)
+ return;
+
+ setNextIdleAnimTimer();
+ _chatVocHigh = _chatVocLow = -1;
+ objectChatInit(str, 87, vocHigh, vocLow);
+ _chatText = str;
+ _chatObject = 87;
+ goodConscienceChatWaitToFinish();
+ updateSceneAnim(0x0F, _goodConscienceFrameTable[_goodConscienceAnim+10]);
+ _text->restoreScreen();
+ update();
+ _chatText = 0;
+ _chatObject = -1;
+}
+
+void KyraEngine_MR::goodConscienceChatWaitToFinish() {
+ if (_chatVocHigh) {
+ playVoice(_chatVocHigh, _chatVocLow);
+ _chatVocHigh = _chatVocLow = -1;
+ }
+
+ bool running = true;
+ const uint32 endTime = _chatEndTime;
+ resetSkipFlag();
+
+ uint32 nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(3, 6) * _tickLength;
+
+ int frame = _goodConscienceFrameTable[_goodConscienceAnim+15];
+ while (running && !shouldQuit()) {
+ if (nextFrame < _system->getMillis()) {
+ ++frame;
+ if (_goodConscienceFrameTable[_goodConscienceAnim+20] < frame)
+ frame = _goodConscienceFrameTable[_goodConscienceAnim+15];
+
+ updateSceneAnim(0x0F, frame);
+ updateWithText();
+
+ nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(3, 6) * _tickLength;
+ }
+
+ updateWithText();
+
+ const uint32 curTime = _system->getMillis();
+ if ((textEnabled() && !speechEnabled() && curTime > endTime) || (speechEnabled() && !snd_voiceIsPlaying()) || skipFlag()) {
+ snd_stopVoice();
+ resetSkipFlag();
+ nextFrame = curTime;
+ running = false;
+ }
+
+ delay(10);
+ }
+}
+
+void KyraEngine_MR::albumChat(const char *str, int vocHigh, int vocLow) {
+ _talkObjectList[1].x = 190;
+ _talkObjectList[1].y = 188;
+
+ _chatVocHigh = _chatVocLow = -1;
+ _albumChatActive = true;
+ albumChatInit(str, 1, vocHigh, vocLow);
+ _albumChatActive = false;
+
+ _chatText = str;
+ _chatObject = 1;
+ _screen->hideMouse();
+ albumChatWaitToFinish();
+ _screen->showMouse();
+
+ _chatText = 0;
+ _chatObject = -1;
+}
+
+void KyraEngine_MR::albumChatInit(const char *str, int object, int vocHigh, int vocLow) {
+ Common::String realString;
+
+ while (*str) {
+ if (str[0] == '\\' && str[1] == 'r') {
+ realString += '\r';
+ ++str;
+ } else {
+ realString += *str;
+ }
+
+ ++str;
+ }
+
+ str = realString.c_str();
+
+ str = _text->preprocessString(str);
+ int lineNum = _text->buildMessageSubstrings(str);
+
+ int xPos = 0, yPos = 0;
+
+ if (!object) {
+ int scale = getScale(_mainCharacter.x1, _mainCharacter.y1);
+ yPos = _mainCharacter.y1 - ((_mainCharacter.height * scale) >> 8) - 8;
+ xPos = _mainCharacter.x1;
+ } else {
+ yPos = _talkObjectList[object].y;
+ xPos = _talkObjectList[object].x;
+ }
+
+ yPos -= lineNum * 10;
+ yPos = MAX(yPos, 0);
+ _text->_talkMessageY = yPos;
+ _text->_talkMessageH = lineNum*10;
+
+ int width = _text->getWidestLineWidth(lineNum);
+ _text->calcWidestLineBounds(xPos, yPos, width, xPos);
+ _text->_talkCoords.x = xPos;
+ _text->_talkCoords.w = width + 2;
+
+ _screen->hideMouse();
+
+ if (textEnabled()) {
+ objectChatPrintText(str, object);
+ _chatEndTime = _system->getMillis() + chatCalcDuration(str) * _tickLength;
+ } else {
+ _chatEndTime = _system->getMillis();
+ }
+
+ if (speechEnabled()) {
+ _chatVocHigh = vocHigh;
+ _chatVocLow = vocLow;
+ } else {
+ _chatVocHigh = _chatVocLow = -1;
+ }
+
+ _screen->showMouse();
+}
+
+void KyraEngine_MR::albumChatWaitToFinish() {
+ if (_chatVocHigh) {
+ playVoice(_chatVocHigh, _chatVocLow);
+ _chatVocHigh = _chatVocLow = -1;
+ }
+
+ bool running = true;
+ const uint32 endTime = _chatEndTime;
+ resetSkipFlag();
+
+ uint32 nextFrame = 0;
+ int frame = 12;
+ while (running && !shouldQuit()) {
+ if (nextFrame < _system->getMillis()) {
+ ++frame;
+ if (frame > 22)
+ frame = 13;
+
+ albumRestoreRect();
+ _album.wsa->displayFrame(frame, 2, -100, 90, 0x4000, 0, 0);
+ albumUpdateRect();
+
+ nextFrame = _system->getMillis() + _rnd.getRandomNumberRng(4, 8) * _tickLength;
+ }
+
+ if (_album.nextPage != 14)
+ albumUpdateAnims();
+ else
+ _screen->updateScreen();
+
+ const uint32 curTime = _system->getMillis();
+ if ((textEnabled() && !speechEnabled() && curTime > endTime) || (speechEnabled() && !snd_voiceIsPlaying()) || skipFlag()) {
+ snd_stopVoice();
+ resetSkipFlag();
+ nextFrame = curTime;
+ running = false;
+ }
+
+ delay(10);
+ }
+}
+
+void KyraEngine_MR::malcolmSceneStartupChat() {
+ if (_noStartupChat)
+ return;
+
+ int index = _mainCharacter.sceneId - _chapterLowestScene[_currentChapter];
+ if (_newSceneDlgState[index])
+ return;
+
+ updateDlgBuffer();
+ int vocHighBase = 0, vocHighIndex = 0, index1 = 0, index2 = 0;
+ loadDlgHeader(vocHighBase, vocHighIndex, index1, index2);
+
+ _cnvFile->seek(index1*6, SEEK_CUR);
+ _cnvFile->seek(index2*4, SEEK_CUR);
+ _cnvFile->seek(index*2, SEEK_CUR);
+ _cnvFile->seek(_cnvFile->readUint16LE(), SEEK_SET);
+
+ _isStartupDialog = true;
+ processDialog(vocHighIndex, vocHighBase, 0);
+ _isStartupDialog = false;
+ _newSceneDlgState[index] = true;
+}
+
+void KyraEngine_MR::updateDlgBuffer() {
+ if (_cnvFile)
+ _cnvFile->seek(0, SEEK_SET);
+
+ if (_curDlgIndex == _mainCharacter.dlgIndex && _curDlgChapter == _currentChapter && _curDlgLang == _lang)
+ return;
+
+ Common::String dlgFile = Common::String::format("CH%.02d-S%.02d.%s", _currentChapter, _mainCharacter.dlgIndex, _languageExtension[_lang]);
+ Common::String cnvFile = Common::String::format("CH%.02d-S%.02d.CNV", _currentChapter, _mainCharacter.dlgIndex);
+
+ delete _cnvFile;
+ delete _dlgBuffer;
+
+ _res->exists(cnvFile.c_str(), true);
+ _res->exists(dlgFile.c_str(), true);
+ _cnvFile = _res->createReadStream(cnvFile);
+ _dlgBuffer = _res->createReadStream(dlgFile);
+ assert(_cnvFile);
+ assert(_dlgBuffer);
+}
+
+void KyraEngine_MR::loadDlgHeader(int &vocHighBase, int &vocHighIndex, int &index1, int &index2) {
+ assert(_cnvFile);
+ vocHighIndex = _cnvFile->readSint16LE();
+ vocHighBase = _cnvFile->readSint16LE();
+ index1 = _cnvFile->readSint16LE();
+ index2 = _cnvFile->readSint16LE();
+}
+
+void KyraEngine_MR::setDlgIndex(int index) {
+ if (_mainCharacter.dlgIndex != index) {
+ memset(_newSceneDlgState, 0, sizeof(_newSceneDlgState));
+ memset(_conversationState, -1, sizeof(_conversationState));
+ _chatAltFlag = false;
+ _mainCharacter.dlgIndex = index;
+ }
+}
+
+void KyraEngine_MR::updateDlgIndex() {
+ uint16 dlgIndex = _mainCharacter.dlgIndex;
+
+ if (_currentChapter == 1) {
+ static const uint8 dlgIndexMoodNice[] = { 0x0C, 0x0E, 0x10, 0x0F, 0x11 };
+ static const uint8 dlgIndexMoodNormal[] = { 0x00, 0x02, 0x04, 0x03, 0x05 };
+ static const uint8 dlgIndexMoodEvil[] = { 0x06, 0x08, 0x0A, 0x09, 0x0B };
+
+ if (_malcolmsMood == 0)
+ dlgIndex = dlgIndexMoodNice[_characterShapeFile];
+ else if (_malcolmsMood == 1)
+ dlgIndex = dlgIndexMoodNormal[_characterShapeFile];
+ else if (_malcolmsMood == 2)
+ dlgIndex = dlgIndexMoodEvil[_characterShapeFile];
+ } else if (_currentChapter == 2) {
+ if (dlgIndex >= 8)
+ dlgIndex -= 4;
+ if (dlgIndex >= 4)
+ dlgIndex -= 4;
+
+ if (_malcolmsMood == 0)
+ dlgIndex += 8;
+ else if (_malcolmsMood == 2)
+ dlgIndex += 4;
+ } else if (_currentChapter == 4) {
+ if (dlgIndex >= 10)
+ dlgIndex -= 5;
+ if (dlgIndex >= 5)
+ dlgIndex -= 5;
+
+ if (_malcolmsMood == 0)
+ dlgIndex += 10;
+ else if (_malcolmsMood == 2)
+ dlgIndex += 5;
+ }
+
+ _mainCharacter.dlgIndex = dlgIndex;
+}
+
+void KyraEngine_MR::processDialog(int vocHighIndex, int vocHighBase, int funcNum) {
+ bool running = true;
+ int script = -1;
+ int vocHigh = -1, vocLow = -1;
+
+ while (running) {
+ uint16 cmd = _cnvFile->readUint16LE();
+ int object = cmd - 12;
+
+ if (cmd == 10) {
+ break;
+ } else if (cmd == 4) {
+ vocHighBase = _cnvFile->readUint16LE();
+ setDlgIndex(vocHighBase);
+ } else if (cmd == 11) {
+ int strSize = _cnvFile->readUint16LE();
+ vocLow = _cnvFile->readUint16LE();
+ _cnvFile->read(_stringBuffer, strSize);
+ _stringBuffer[strSize] = 0;
+ } else {
+ vocHigh = _vocHighTable[vocHighIndex-1] + vocHighBase;
+ vocLow = _cnvFile->readUint16LE();
+ getTableEntry(_dlgBuffer, vocLow, _stringBuffer);
+
+ if (_isStartupDialog) {
+ delay(60*_tickLength, true);
+ _isStartupDialog = false;
+ }
+
+ if (*_stringBuffer == 0)
+ continue;
+
+ if (cmd != 12) {
+ if (object != script) {
+ if (script >= 0) {
+ dialogEndScript(script);
+ script = -1;
+ }
+
+ dialogStartScript(object, funcNum);
+ script = object;
+ }
+
+ npcChatSequence(_stringBuffer, object, vocHigh, vocLow);
+ } else {
+ if (script >= 0) {
+ dialogEndScript(script);
+ script = -1;
+ }
+
+ objectChat(_stringBuffer, 0, vocHigh, vocLow);
+ playStudioSFX(_stringBuffer);
+ }
+ }
+ }
+
+ if (script != -1)
+ dialogEndScript(script);
+}
+
+void KyraEngine_MR::dialogStartScript(int object, int funcNum) {
+ _dialogSceneAnim = _talkObjectList[object].sceneAnim;
+ _dialogSceneScript = _talkObjectList[object].sceneScript;
+ if (_dialogSceneAnim >= 0 && _dialogSceneScript >= 0) {
+ _specialSceneScriptStateBackup[_dialogSceneScript] = _specialSceneScriptState[_dialogSceneScript];
+ _specialSceneScriptState[_dialogSceneScript] = true;
+ }
+
+ _emc->init(&_dialogScriptState, &_dialogScriptData);
+ _emc->load(_talkObjectList[object].filename, &_dialogScriptData, &_opcodesDialog);
+
+ _dialogScriptFuncStart = funcNum * 3 + 0;
+ _dialogScriptFuncProc = funcNum * 3 + 1;
+ _dialogScriptFuncEnd = funcNum * 3 + 2;
+
+ _emc->start(&_dialogScriptState, _dialogScriptFuncStart);
+ while (_emc->isValid(&_dialogScriptState))
+ _emc->run(&_dialogScriptState);
+}
+
+void KyraEngine_MR::dialogEndScript(int object) {
+ _emc->init(&_dialogScriptState, &_dialogScriptData);
+ _emc->start(&_dialogScriptState, _dialogScriptFuncEnd);
+
+ while (_emc->isValid(&_dialogScriptState))
+ _emc->run(&_dialogScriptState);
+
+ if (_dialogSceneAnim >= 0 && _dialogSceneScript >= 0) {
+ _specialSceneScriptState[_dialogSceneScript] = _specialSceneScriptStateBackup[_dialogSceneScript];
+ _dialogSceneScript = _dialogSceneAnim = -1;
+ }
+
+ _emc->unload(&_dialogScriptData);
+}
+
+void KyraEngine_MR::npcChatSequence(const char *str, int object, int vocHigh, int vocLow) {
+ _chatText = str;
+ _chatObject = object;
+ _chatVocHigh = _chatVocLow = -1;
+
+ objectChatInit(str, object, vocHigh, vocLow);
+
+ if (_chatVocHigh >= 0 && _chatVocLow >= 0) {
+ playVoice(_chatVocHigh, _chatVocLow);
+ _chatVocHigh = _chatVocLow = -1;
+ }
+
+ _emc->init(&_dialogScriptState, &_dialogScriptData);
+ _emc->start(&_dialogScriptState, _dialogScriptFuncProc);
+
+ resetSkipFlag();
+
+ uint32 endTime = _chatEndTime;
+ bool running = true;
+ while (running && !shouldQuit()) {
+ if (!_emc->run(&_dialogScriptState)) {
+ _emc->init(&_dialogScriptState, &_dialogScriptData);
+ _emc->start(&_dialogScriptState, _dialogScriptFuncProc);
+ }
+
+ const uint32 curTime = _system->getMillis();
+ if ((textEnabled() && !speechEnabled() && curTime > endTime) || (speechEnabled() && !snd_voiceIsPlaying()) || skipFlag()) {
+ snd_stopVoice();
+ resetSkipFlag();
+ running = false;
+ }
+ }
+ _text->restoreScreen();
+ _chatText = 0;
+ _chatObject= - 1;
+}
+
+void KyraEngine_MR::randomSceneChat() {
+ updateDlgBuffer();
+
+ int index = (_mainCharacter.sceneId - _chapterLowestScene[_currentChapter]) * 2;
+
+ int vocHighBase = 0, vocHighIndex = 0, index1 = 0, index2 = 0;
+ loadDlgHeader(vocHighBase, vocHighIndex, index1, index2);
+
+ if (_chatAltFlag)
+ index++;
+ _chatAltFlag = !_chatAltFlag;
+
+ _cnvFile->seek(index1*6, SEEK_CUR);
+ _cnvFile->seek(index*2, SEEK_CUR);
+ _cnvFile->seek(_cnvFile->readUint16LE(), SEEK_SET);
+
+ processDialog(vocHighIndex, vocHighBase, 0);
+}
+
+void KyraEngine_MR::doDialog(int dlgIndex, int funcNum) {
+ switch (_currentChapter-2) {
+ case 0:
+ dlgIndex -= 34;
+ break;
+
+ case 1:
+ dlgIndex -= 54;
+ break;
+
+ case 2:
+ dlgIndex -= 55;
+ break;
+
+ case 3:
+ dlgIndex -= 70;
+ break;
+
+ default:
+ break;
+ }
+
+ updateDlgBuffer();
+
+ int vocHighBase = 0, vocHighIndex = 0, index1 = 0, index2 = 0;
+ loadDlgHeader(vocHighBase, vocHighIndex, index1, index2);
+
+ int convState = _conversationState[dlgIndex][vocHighBase];
+ uint32 offset = ((vocHighIndex == 1) ? dlgIndex - 1 : dlgIndex) * 6;
+ if (convState == -1) {
+ _cnvFile->seek(offset, SEEK_CUR);
+ _conversationState[dlgIndex][vocHighBase] = 0;
+ } else if (convState == 0 || convState == 2) {
+ _cnvFile->seek(offset+2, SEEK_CUR);
+ _conversationState[dlgIndex][vocHighBase] = 1;
+ } else {
+ _cnvFile->seek(offset+4, SEEK_CUR);
+ _conversationState[dlgIndex][vocHighBase] = 2;
+ }
+
+ _cnvFile->seek(_cnvFile->readUint16LE(), SEEK_SET);
+
+ processDialog(vocHighIndex, vocHighBase, funcNum);
+}
+
+} // End of namespace Kyra