aboutsummaryrefslogtreecommitdiff
path: root/engines/hopkins/talk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/hopkins/talk.cpp')
-rw-r--r--engines/hopkins/talk.cpp1081
1 files changed, 1081 insertions, 0 deletions
diff --git a/engines/hopkins/talk.cpp b/engines/hopkins/talk.cpp
new file mode 100644
index 0000000000..a16f6f5e4e
--- /dev/null
+++ b/engines/hopkins/talk.cpp
@@ -0,0 +1,1081 @@
+/* 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 "hopkins/talk.h"
+
+#include "hopkins/files.h"
+#include "hopkins/globals.h"
+#include "hopkins/graphics.h"
+#include "hopkins/hopkins.h"
+#include "hopkins/objects.h"
+
+#include "common/system.h"
+#include "common/endian.h"
+#include "common/file.h"
+#include "common/textconsole.h"
+
+namespace Hopkins {
+
+TalkManager::TalkManager(HopkinsEngine *vm) {
+ _vm = vm;
+ _characterBuffer = NULL;
+ _characterPalette = NULL;
+ _characterSprite = NULL;
+ _characterAnim = NULL;
+ _characterSize = 0;
+ _dialogueMesgId1 = _dialogueMesgId2 = _dialogueMesgId3 = _dialogueMesgId4 = 0;
+ _paletteBufferIdx = 0;
+}
+
+void TalkManager::startAnimatedCharacterDialogue(const Common::String &filename) {
+ Common::String spriteFilename;
+
+ _vm->_fontMan->hideText(5);
+ _vm->_fontMan->hideText(9);
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_graphicsMan->_scrollStatus = 1;
+ bool oldDisableInventFl = _vm->_globals->_disableInventFl;
+ _vm->_globals->_disableInventFl = true;
+ bool fileFoundFl = false;
+ _characterBuffer = _vm->_fileIO->searchCat(filename, RES_PER, fileFoundFl);
+ _characterSize = _vm->_fileIO->_catalogSize;
+ if (!fileFoundFl) {
+ _characterBuffer = _vm->_fileIO->loadFile(filename);
+ _characterSize = _vm->_fileIO->fileSize(filename);
+ }
+
+ _vm->_globals->_saveData->_data[svDialogField4] = 0;
+
+ getStringFromBuffer(40, spriteFilename, (const char *)_characterBuffer);
+ getStringFromBuffer(0, _questionsFilename, (const char *)_characterBuffer);
+ getStringFromBuffer(20, _answersFilename, (const char *)_characterBuffer);
+ if (_vm->_globals->_language == LANG_FR) {
+ _answersFilename = _questionsFilename = "RUE.TXT";
+ } else if (_vm->_globals->_language == LANG_EN) {
+ _answersFilename = _questionsFilename = "RUEAN.TXT";
+ } else if (_vm->_globals->_language == LANG_SP) {
+ _answersFilename = _questionsFilename = "RUEES.TXT";
+ }
+ _dialogueMesgId1 = READ_LE_INT16((uint16 *)_characterBuffer + 40);
+ _paletteBufferIdx = 20 * READ_LE_INT16((uint16 *)_characterBuffer + 42) + 110;
+ fileFoundFl = false;
+ _characterSprite = _vm->_fileIO->searchCat(spriteFilename, RES_SAN, fileFoundFl);
+ if (!fileFoundFl) {
+ _characterSprite = _vm->_objectsMan->loadSprite(spriteFilename);
+ } else {
+ _characterSprite = _vm->_objectsMan->loadSprite("RES_SAN.RES");
+ }
+
+ _vm->_graphicsMan->backupScreen();
+
+ if (!_vm->_graphicsMan->_lineNbr)
+ _vm->_graphicsMan->_scrollOffset = 0;
+ _vm->_graphicsMan->displayScreen(true);
+ _vm->_objectsMan->_charactersEnabledFl = true;
+ searchCharacterPalette(_paletteBufferIdx, false);
+ startCharacterAnim0(_paletteBufferIdx, false);
+ initCharacterAnim();
+ _dialogueMesgId2 = _dialogueMesgId1 + 1;
+ _dialogueMesgId3 = _dialogueMesgId1 + 2;
+ _dialogueMesgId4 = _dialogueMesgId1 + 3;
+ int oldMouseCursorId = _vm->_events->_mouseCursorId;
+ _vm->_events->_mouseCursorId = 4;
+ _vm->_events->changeMouseCursor(0);
+ if (!_vm->_globals->_introSpeechOffFl) {
+ int answer = 0;
+ int dlgAnswer;
+ do {
+ dlgAnswer = dialogQuestion(false);
+ if (dlgAnswer != _dialogueMesgId4)
+ answer = dialogAnswer(dlgAnswer, false);
+ if (answer == -1)
+ dlgAnswer = _dialogueMesgId4;
+ _vm->_events->refreshScreenAndEvents();
+ } while (dlgAnswer != _dialogueMesgId4);
+ }
+ if (_vm->_globals->_introSpeechOffFl) {
+ int idx = 1;
+ int answer;
+ do
+ answer = dialogAnswer(idx++, false);
+ while (answer != -1);
+ }
+ clearCharacterAnim();
+ _vm->_globals->_introSpeechOffFl = false;
+ _characterBuffer = _vm->_globals->freeMemory(_characterBuffer);
+ _characterSprite = _vm->_globals->freeMemory(_characterSprite);
+ _vm->_graphicsMan->displayScreen(false);
+
+ _vm->_graphicsMan->restoreScreen();
+
+ _vm->_objectsMan->_charactersEnabledFl = false;
+ _vm->_events->_mouseCursorId = oldMouseCursorId;
+
+ _vm->_events->changeMouseCursor(oldMouseCursorId);
+ _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
+
+ if (_vm->getIsDemo() == false)
+ _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
+
+ _vm->_graphicsMan->initColorTable(145, 150, _vm->_graphicsMan->_palette);
+ _vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
+ _vm->_graphicsMan->copy16BitRect(_vm->_graphicsMan->_backBuffer, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ memcpy(_vm->_graphicsMan->_frontBuffer, _vm->_graphicsMan->_backBuffer, 614399);
+ _vm->_globals->_disableInventFl = oldDisableInventFl;
+ _vm->_graphicsMan->updateScreen();
+ for (int i = 0; i <= 4; i++)
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_graphicsMan->_scrollStatus = 0;
+}
+
+void TalkManager::startStaticCharacterDialogue(const Common::String &filename) {
+ // TODO: The original disables the mouse cursor here
+ bool oldDisableInventFl = _vm->_globals->_disableInventFl;
+ _vm->_globals->_disableInventFl = true;
+ bool fileFoundFl = false;
+ _characterBuffer = _vm->_fileIO->searchCat(filename, RES_PER, fileFoundFl);
+ _characterSize = _vm->_fileIO->_catalogSize;
+ if (!fileFoundFl) {
+ _characterBuffer = _vm->_fileIO->loadFile(filename);
+ _characterSize = _vm->_fileIO->fileSize(filename);
+ }
+
+ _vm->_globals->_saveData->_data[svDialogField4] = 0;
+
+ getStringFromBuffer(0, _questionsFilename, (const char *)_characterBuffer);
+ getStringFromBuffer(20, _answersFilename, (const char *)_characterBuffer);
+
+ switch (_vm->_globals->_language) {
+ case LANG_EN:
+ _questionsFilename = "RUEAN.TXT";
+ _answersFilename = "RUEAN.TXT";
+ break;
+ case LANG_FR:
+ _questionsFilename = "RUE.TXT";
+ _answersFilename = "RUE.TXT";
+ break;
+ case LANG_SP:
+ _questionsFilename = "RUEES.TXT";
+ _answersFilename = "RUEES.TXT";
+ break;
+ }
+
+ _dialogueMesgId1 = READ_LE_INT16((uint16 *)_characterBuffer + 40);
+ _paletteBufferIdx = 20 * READ_LE_INT16((uint16 *)_characterBuffer + 42) + 110;
+ searchCharacterPalette(_paletteBufferIdx, false);
+ _dialogueMesgId2 = _dialogueMesgId1 + 1;
+ _dialogueMesgId3 = _dialogueMesgId1 + 2;
+ _dialogueMesgId4 = _dialogueMesgId1 + 3;
+ int oldMouseCursorId = _vm->_events->_mouseCursorId;
+ _vm->_events->_mouseCursorId = 4;
+ _vm->_events->changeMouseCursor(0);
+
+ if (!_vm->_globals->_introSpeechOffFl) {
+ int answer;
+ do {
+ answer = dialogQuestion(true);
+ if (answer != _dialogueMesgId4) {
+ if (dialogAnswer(answer, true) == -1)
+ answer = _dialogueMesgId4;
+ }
+ } while (answer != _dialogueMesgId4);
+ }
+
+ if (_vm->_globals->_introSpeechOffFl) {
+ int idx = 1;
+ int answer;
+ do
+ answer = dialogAnswer(idx++, true);
+ while (answer != -1);
+ }
+
+ _characterBuffer = _vm->_globals->freeMemory(_characterBuffer);
+ _vm->_events->_mouseCursorId = oldMouseCursorId;
+
+ _vm->_events->changeMouseCursor(oldMouseCursorId);
+ _vm->_graphicsMan->initColorTable(145, 150, _vm->_graphicsMan->_palette);
+ _vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
+ // TODO: The original re-enables the mouse cursor here
+ _vm->_globals->_disableInventFl = oldDisableInventFl;
+}
+
+void TalkManager::getStringFromBuffer(int srcStart, Common::String &dest, const char *srcData) {
+ dest = Common::String(srcData + srcStart);
+}
+
+int TalkManager::dialogQuestion(bool animatedFl) {
+ if (animatedFl) {
+ uint16 *bufPtr = (uint16 *)_characterBuffer + 48;
+ int curVal = READ_LE_INT16(bufPtr);
+ if (curVal != 0)
+ _vm->_objectsMan->setBobAnimation(curVal);
+ if (curVal != 1)
+ _vm->_objectsMan->setBobAnimation(READ_LE_INT16(bufPtr + 1));
+ if (curVal != 2)
+ _vm->_objectsMan->setBobAnimation(READ_LE_INT16(bufPtr + 2));
+ if (curVal != 3)
+ _vm->_objectsMan->setBobAnimation(READ_LE_INT16(bufPtr + 3));
+ if (curVal != 4)
+ _vm->_objectsMan->setBobAnimation(READ_LE_INT16(bufPtr + 4));
+ } else {
+ dialogWait();
+ }
+
+ int sentence1LineNumb = countBoxLines(_dialogueMesgId1, _questionsFilename);
+ int sentence2LineNumb = countBoxLines(_dialogueMesgId2, _questionsFilename);
+ int sentence3LineNumb = countBoxLines(_dialogueMesgId3, _questionsFilename);
+ int sentence4LineNumb = countBoxLines(_dialogueMesgId4, _questionsFilename);
+
+ int sentence4PosY = 420 - 20 * sentence4LineNumb;
+ int sentence3PosY = sentence4PosY - 20 * sentence3LineNumb;
+ int sentence2PosY = sentence3PosY - 20 * sentence2LineNumb;
+ int sentence1PosY = sentence2PosY - 20 * sentence1LineNumb;
+
+ _vm->_fontMan->initTextBuffers(5, _dialogueMesgId1, _questionsFilename, 5, sentence1PosY, 0, 65, 255);
+ _vm->_fontMan->initTextBuffers(6, _dialogueMesgId2, _questionsFilename, 5, sentence2PosY, 0, 65, 255);
+ _vm->_fontMan->initTextBuffers(7, _dialogueMesgId3, _questionsFilename, 5, sentence3PosY, 0, 65, 255);
+ _vm->_fontMan->initTextBuffers(8, _dialogueMesgId4, _questionsFilename, 5, sentence4PosY, 0, 65, 255);
+ _vm->_fontMan->showText(5);
+ _vm->_fontMan->showText(6);
+ _vm->_fontMan->showText(7);
+ _vm->_fontMan->showText(8);
+
+ int retVal = -1;
+ bool loopCond = false;
+ do {
+ int mousePosY = _vm->_events->getMouseY();
+ if (sentence1PosY < mousePosY && mousePosY < (sentence2PosY - 1)) {
+ _vm->_fontMan->setOptimalColor(6, 7, 8, 5);
+ retVal = _dialogueMesgId1;
+ }
+ if (sentence2PosY < mousePosY && mousePosY < (sentence3PosY - 1)) {
+ _vm->_fontMan->setOptimalColor(5, 7, 8, 6);
+ retVal = _dialogueMesgId2;
+ }
+ if (sentence3PosY < mousePosY && mousePosY < (sentence4PosY - 1)) {
+ _vm->_fontMan->setOptimalColor(5, 6, 8, 7);
+ retVal = _dialogueMesgId3;
+ }
+ if (sentence4PosY < mousePosY && mousePosY < 419) {
+ _vm->_fontMan->setOptimalColor(5, 6, 7, 8);
+ retVal = _dialogueMesgId4;
+ }
+
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_events->getMouseButton())
+ loopCond = true;
+ if (retVal == -1)
+ loopCond = false;
+ } while (!_vm->shouldQuit() && !loopCond);
+
+ _vm->_soundMan->mixVoice(retVal, 1);
+ _vm->_fontMan->hideText(5);
+ _vm->_fontMan->hideText(6);
+ _vm->_fontMan->hideText(7);
+ _vm->_fontMan->hideText(8);
+
+ if (animatedFl) {
+ uint16 *bufPtr = (uint16 *)_characterBuffer + 48;
+
+ int curVal = READ_LE_INT16(bufPtr);
+ if (curVal != 0)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+
+ curVal = READ_LE_INT16(bufPtr + 1);
+ if (curVal != 1)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+
+ curVal = READ_LE_INT16(bufPtr + 2);
+ if (curVal != 2)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+
+ curVal = READ_LE_INT16(bufPtr + 3);
+ if (curVal != 3)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+
+ curVal = READ_LE_INT16(bufPtr + 4);
+ if (curVal != 4)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+ } else {
+ dialogTalk();
+ }
+
+ _vm->_events->refreshScreenAndEvents();
+ return retVal;
+}
+
+int TalkManager::dialogAnswer(int idx, bool animatedFl) {
+ int charIdx;
+ byte *charBuf;
+ for (charBuf = _characterBuffer + 110, charIdx = 0; READ_LE_INT16(charBuf) != idx; charBuf += 20) {
+ ++charIdx;
+ if (READ_LE_INT16((uint16 *)_characterBuffer + 42) < charIdx)
+ return -1;
+ }
+
+ int mesgId = READ_LE_INT16((uint16 *)charBuf + 1);
+ int mesgPosX = READ_LE_INT16((uint16 *)charBuf + 2);
+ int mesgPosY = READ_LE_INT16((uint16 *)charBuf + 3);
+ int mesgLength = READ_LE_INT16((uint16 *)charBuf + 4);
+ _dialogueMesgId1 = READ_LE_INT16((uint16 *)charBuf + 5);
+ _dialogueMesgId2 = READ_LE_INT16((uint16 *)charBuf + 6);
+ _dialogueMesgId3 = READ_LE_INT16((uint16 *)charBuf + 7);
+ int frameNumb = READ_LE_INT16((uint16 *)charBuf + 8);
+
+ int curBufVal = READ_LE_INT16((uint16 *)charBuf + 9);
+ if (curBufVal)
+ _vm->_globals->_saveData->_data[svDialogField4] = curBufVal;
+
+ if (!frameNumb)
+ frameNumb = 10;
+ if (animatedFl) {
+ uint16 *bufPtr = (uint16 *)_characterBuffer + 43;
+ int curVal = READ_LE_INT16(bufPtr);
+ if (curVal)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+
+ curVal = READ_LE_INT16(bufPtr + 1);
+ if (curVal)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+
+ curVal = READ_LE_INT16(bufPtr + 2);
+ if (curVal)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+
+ curVal = READ_LE_INT16(bufPtr + 3);
+ if (curVal)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+
+ curVal = READ_LE_INT16(bufPtr + 4);
+ if (curVal)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+ } else {
+ dialogAnim();
+ }
+
+ bool displayedTxtFl = false;
+ if (!_vm->_soundMan->_textOffFl) {
+ _vm->_fontMan->initTextBuffers(9, mesgId, _answersFilename, mesgPosX, mesgPosY, 5, mesgLength, 252);
+ _vm->_fontMan->showText(9);
+ displayedTxtFl = true;
+ }
+ if (!_vm->_soundMan->mixVoice(mesgId, 1, displayedTxtFl)) {
+ _vm->_events->_curMouseButton = 0;
+ _vm->_events->_mouseButton = 0;
+
+ if (_vm->getIsDemo()) {
+ for (int i = 0; i < frameNumb; i++) {
+ _vm->_events->refreshScreenAndEvents();
+ }
+ } else {
+ for (int i = 0; i < frameNumb; i++) {
+ _vm->_events->refreshScreenAndEvents();
+ if (_vm->_events->_mouseButton || _vm->_events->_curMouseButton)
+ break;
+ if (_vm->_events->getMouseButton() && i + 1 > abs(frameNumb / 5))
+ break;
+ }
+ }
+ }
+
+ if (!_vm->_soundMan->_textOffFl)
+ _vm->_fontMan->hideText(9);
+ if (animatedFl) {
+ uint16 *bufPtr = (uint16 *)_characterBuffer + 43;
+ int curVal = READ_LE_INT16(bufPtr);
+ if (curVal)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+
+ curVal = READ_LE_INT16(bufPtr + 1);
+ if (curVal)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+
+ curVal = READ_LE_INT16(bufPtr + 2);
+ if (curVal)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+
+ curVal = READ_LE_INT16(bufPtr + 3);
+ if (curVal)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+
+ curVal = READ_LE_INT16(bufPtr + 4);
+ if (curVal)
+ _vm->_objectsMan->stopBobAnimation(curVal);
+ } else {
+ dialogEndTalk();
+ }
+ int result = 0;
+ if (!_dialogueMesgId1)
+ result = -1;
+
+ return result;
+}
+
+void TalkManager::searchCharacterPalette(int startIdx, bool dark) {
+ int palettePos = 0;
+ size_t curIdx = startIdx;
+ for (;;) {
+ if (READ_BE_UINT24(&_characterBuffer[curIdx]) == MKTAG24('P', 'A', 'L')) {
+ palettePos = curIdx;
+ break;
+ }
+ ++curIdx;
+ if (_characterSize == curIdx)
+ return;
+ }
+
+ _characterPalette = _characterBuffer + palettePos + 5;
+ _characterPalette[0] = 0;
+ _characterPalette[1] = 0;
+ _characterPalette[2] = 0;
+ _characterPalette[759] = 255;
+ _characterPalette[760] = 255;
+ _characterPalette[762] = 0;
+ _characterPalette[763] = 0;
+ _characterPalette[764] = 0;
+ _characterPalette[765] = 224;
+ _characterPalette[766] = 224;
+ _characterPalette[767] = 255;
+
+ if (!dark)
+ _characterPalette[761] = 86;
+ else
+ _characterPalette[761] = 255;
+
+ _vm->_graphicsMan->setPaletteVGA256(_characterPalette);
+ _vm->_graphicsMan->initColorTable(145, 150, _characterPalette);
+}
+
+void TalkManager::dialogWait() {
+ for (int idx = 26; idx <= 30; ++idx) {
+ if (_vm->_animMan->_animBqe[idx]._enabledFl)
+ displayBobDialogAnim(idx);
+ }
+}
+
+void TalkManager::dialogTalk() {
+ for (int idx = 26; idx <= 30; ++idx) {
+ if (_vm->_animMan->_animBqe[idx]._enabledFl)
+ _vm->_objectsMan->hideBob(idx);
+ }
+
+ for (int idx = 26; idx <= 30; ++idx) {
+ if (_vm->_animMan->_animBqe[idx]._enabledFl)
+ _vm->_objectsMan->resetBob(idx);
+ }
+}
+
+void TalkManager::dialogEndTalk() {
+ for (int idx = 21; idx <= 25; ++idx) {
+ if (_vm->_animMan->_animBqe[idx]._enabledFl)
+ _vm->_objectsMan->hideBob(idx);
+ }
+
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_events->refreshScreenAndEvents();
+
+ for (int idx = 21; idx <= 25; ++idx) {
+ if (_vm->_animMan->_animBqe[idx]._enabledFl)
+ _vm->_objectsMan->resetBob(idx);
+ }
+}
+
+int TalkManager::countBoxLines(int idx, const Common::String &file) {
+ _vm->_fontMan->_fontFixedWidth = 11;
+
+ // Build up the filename
+ Common::String filename;
+ Common::String dest;
+ filename = dest = file;
+ while (filename.lastChar() != '.')
+ filename.deleteLastChar();
+ filename += "IND";
+
+ Common::File f;
+ if (!f.open(filename))
+ error("Could not open file - %s", filename.c_str());
+ int filesize = f.size();
+ assert(filesize < 16188);
+
+ uint32 indexData[4047];
+ for (int i = 0; i < (filesize / 4); ++i)
+ indexData[i] = f.readUint32LE();
+ f.close();
+
+ if (!f.open(dest))
+ error("Error opening file - %s", dest.c_str());
+
+ f.seek(indexData[idx]);
+ byte *decryptBuf = _vm->_globals->allocMemory(2058);
+ assert(decryptBuf);
+
+ f.read(decryptBuf, 2048);
+ f.close();
+
+ // Decrypt buffer
+ byte *curDecryptPtr = decryptBuf;
+ for (int i = 0; i < 2048; i++) {
+ char curByte = *curDecryptPtr;
+ if ((byte)(curByte + 46) > 27) {
+ if ((byte)(curByte + 80) > 27) {
+ if ((curByte >= 'A' && curByte <= 'Z') || (curByte >= 'a' && curByte <= 'z'))
+ curByte = ' ';
+ } else {
+ curByte -= 79;
+ }
+ } else {
+ curByte += 111;
+ }
+ *curDecryptPtr = curByte;
+ curDecryptPtr++;
+ }
+
+ // Separate strings
+ for (int i = 0; i < 2048; i++) {
+ if ( decryptBuf[i] == 10 || decryptBuf[i] == 13)
+ decryptBuf[i] = 0;
+ }
+
+ // Check size of each strings in order to compute box width
+ int curBufIndx = 0;
+ int lineCount = 0;
+ int lineSize = 0;
+ char curChar;
+ do {
+ int curLineSize = 0;
+ for (;;) {
+ lineSize = curLineSize;
+ do {
+ curChar = decryptBuf[curBufIndx + curLineSize];
+ ++curLineSize;
+ } while (curChar != ' ' && curChar != '%');
+
+ if (curLineSize >= MIN_LETTERS_PER_LINE - 1) {
+ if (curChar == '%')
+ curChar = ' ';
+ break;
+ }
+
+ if (curChar == '%') {
+ lineSize = curLineSize;
+ break;
+ }
+ }
+ ++lineCount;
+ curBufIndx += lineSize;
+ } while (curChar != '%');
+ _vm->_globals->freeMemory(decryptBuf);
+ return lineCount;
+}
+
+void TalkManager::dialogAnim() {
+ for (int idx = 21; idx <= 25; ++idx) {
+ if (_vm->_animMan->_animBqe[idx]._enabledFl)
+ displayBobDialogAnim(idx);
+ }
+}
+
+void TalkManager::displayBobDialogAnim(int idx) {
+ _vm->_objectsMan->_priorityFl = true;
+ if (!_vm->_objectsMan->_bob[idx]._bobMode) {
+ _vm->_objectsMan->resetBob(idx);
+ byte *bqeData = _vm->_animMan->_animBqe[idx]._data;
+ int newMode = READ_LE_INT16(bqeData + 2);
+ if (!newMode)
+ newMode = 1;
+ if (READ_LE_INT16(bqeData + 24)) {
+ _vm->_objectsMan->_bob[idx]._isSpriteFl = true;
+ _vm->_objectsMan->_bob[idx]._zoomFactor = 0;
+ _vm->_objectsMan->_bob[idx]._flipFl = false;
+ _vm->_objectsMan->_bob[idx]._animData = _vm->_animMan->_animBqe[idx]._data;
+ _vm->_objectsMan->_bob[idx]._bobMode = 10;
+ bqeData = _characterSprite;
+ _vm->_objectsMan->_bob[idx]._spriteData = _characterSprite;
+ _vm->_objectsMan->_bob[idx]._bobModeChange = newMode;
+ _vm->_objectsMan->_bob[idx]._modeChangeCtr = -1;
+ _vm->_objectsMan->_bob[idx]._modeChangeUnused = 0;
+ }
+ }
+}
+
+void TalkManager::startCharacterAnim0(int startIdx, bool readOnlyFl) {
+ int animIdx = 0;
+ size_t curIdx = startIdx;
+ for (;;) {
+ if (READ_BE_UINT32(&_characterBuffer[curIdx]) == MKTAG('A', 'N', 'I', 'M') && _characterBuffer[curIdx + 4] == 1) {
+ animIdx = curIdx;
+ break;
+ }
+ ++curIdx;
+ if (_characterSize == curIdx)
+ return;
+ }
+ _characterAnim = _characterBuffer + animIdx + 25;
+ if (!readOnlyFl) {
+ int idx = 0;
+ do {
+ if (!READ_LE_INT16(&_characterAnim[2 * idx + 4]))
+ break;
+ if (_vm->_globals->_speed != 501)
+ _vm->_graphicsMan->fastDisplay(_characterSprite, _vm->_events->_startPos.x + READ_LE_INT16(&_characterAnim[2 * idx]),
+ READ_LE_INT16(&_characterAnim[2 * idx + 2]), _characterAnim[2 * idx + 8]);
+ idx += 5;
+ } while (_vm->_globals->_speed != 501);
+ }
+}
+
+/**
+ * Initialize character animation
+ */
+void TalkManager::initCharacterAnim() {
+ uint16 *bufPtr = (uint16 *)_characterBuffer + 43;
+ byte *animPtr = _characterBuffer + 110;
+ int curVal = READ_LE_INT16(bufPtr);
+ if (curVal)
+ searchCharacterAnim(21, animPtr, curVal, _characterSize);
+
+ curVal = READ_LE_INT16(bufPtr + 1);
+ if (curVal)
+ searchCharacterAnim(22, animPtr, curVal, _characterSize);
+
+ curVal = READ_LE_INT16(bufPtr + 2);
+ if (curVal)
+ searchCharacterAnim(23, animPtr, curVal, _characterSize);
+
+ curVal = READ_LE_INT16(bufPtr + 3);
+ if (curVal)
+ searchCharacterAnim(24, animPtr, curVal, _characterSize);
+
+ curVal = READ_LE_INT16(bufPtr + 4);
+ if (curVal)
+ searchCharacterAnim(25, animPtr, curVal, _characterSize);
+
+ curVal = READ_LE_INT16(bufPtr + 5);
+ if (curVal)
+ searchCharacterAnim(26, animPtr, curVal, _characterSize);
+
+ curVal = READ_LE_INT16(bufPtr + 6);
+ if (curVal)
+ searchCharacterAnim(27, animPtr, curVal, _characterSize);
+
+ curVal = READ_LE_INT16(bufPtr + 7);
+ if (curVal)
+ searchCharacterAnim(28, animPtr, curVal, _characterSize);
+
+ curVal = READ_LE_INT16(bufPtr + 8);
+ if (curVal)
+ searchCharacterAnim(29, animPtr, curVal, _characterSize);
+
+ curVal = READ_LE_INT16(bufPtr + 9);
+ if (curVal)
+ searchCharacterAnim(30, animPtr, curVal, _characterSize);
+}
+
+void TalkManager::clearCharacterAnim() {
+ for (int idx = 21; idx <= 34; ++idx) {
+ _vm->_animMan->_animBqe[idx]._data = _vm->_globals->freeMemory(_vm->_animMan->_animBqe[idx]._data);
+ _vm->_animMan->_animBqe[idx]._enabledFl = false;
+ }
+}
+
+bool TalkManager::searchCharacterAnim(int idx, const byte *bufPerso, int animId, int bufferSize) {
+ bool result = false;
+
+ for (int bufPos = 0; bufPos <= bufferSize; bufPos++) {
+ if (READ_BE_UINT32(bufPerso + bufPos) == MKTAG('A', 'N', 'I', 'M') && bufPerso[bufPos + 4] == animId) {
+ int bufIndx = bufPos + 5;
+ const byte *curPtr = bufPerso + bufIndx;
+ int animLength = 0;
+ bool loopCond = false;
+ do {
+ if (READ_BE_UINT32(curPtr) == MKTAG('A', 'N', 'I', 'M') || READ_BE_UINT24(curPtr) == MKTAG24('F', 'I', 'N'))
+ loopCond = true;
+ if (bufIndx > bufferSize) {
+ _vm->_animMan->_animBqe[idx]._enabledFl = false;
+ _vm->_animMan->_animBqe[idx]._data = NULL;
+ return false;
+ }
+ ++bufIndx;
+ ++animLength;
+ ++curPtr;
+ } while (!loopCond);
+ _vm->_animMan->_animBqe[idx]._data = _vm->_globals->allocMemory(animLength + 50);
+ _vm->_animMan->_animBqe[idx]._enabledFl = true;
+ memcpy(_vm->_animMan->_animBqe[idx]._data, (const byte *)(bufPerso + bufPos + 5), 20);
+ int bqeVal = READ_LE_INT16(bufPos + bufPerso + 29);
+ WRITE_LE_UINT16(_vm->_animMan->_animBqe[idx]._data + 20, READ_LE_INT16(bufPos + bufPerso + 25));
+ WRITE_LE_UINT16(_vm->_animMan->_animBqe[idx]._data + 22, READ_LE_INT16(bufPos + bufPerso + 27));
+ WRITE_LE_UINT16(_vm->_animMan->_animBqe[idx]._data + 24, bqeVal);
+ WRITE_LE_UINT16(_vm->_animMan->_animBqe[idx]._data + 26, READ_LE_INT16(bufPos + bufPerso + 31));
+ _vm->_animMan->_animBqe[idx]._data[28] = bufPerso[bufPos + 33];
+ _vm->_animMan->_animBqe[idx]._data[29] = bufPerso[bufPos + 34];
+ byte *bqeCurData = _vm->_animMan->_animBqe[idx]._data + 20;
+ const byte *curBufPerso = bufPos + bufPerso + 25;
+ for (int i = 1; i < 5000; i++) {
+ bqeCurData += 10;
+ curBufPerso += 10;
+ if (!bqeVal)
+ break;
+ bqeVal = READ_LE_INT16(curBufPerso + 4);
+ WRITE_LE_UINT16(bqeCurData, READ_LE_INT16(curBufPerso));
+ WRITE_LE_UINT16(bqeCurData + 2, READ_LE_INT16(curBufPerso + 2));
+ WRITE_LE_UINT16(bqeCurData + 4, bqeVal);
+ WRITE_LE_UINT16(bqeCurData + 6, READ_LE_INT16(curBufPerso + 6));
+ bqeCurData[8] = curBufPerso[8];
+ bqeCurData[9] = curBufPerso[9];
+ }
+ result = true;
+ }
+ if (READ_BE_UINT24(&bufPerso[bufPos]) == MKTAG24('F', 'I', 'N'))
+ result = true;
+
+ if (result)
+ break;
+ }
+
+ return result;
+}
+
+void TalkManager::handleAnswer(int zone, int verb) {
+ byte zoneObj = zone;
+ byte verbObj = verb;
+
+ bool outerLoopFl;
+ byte *ptr = NULL;
+ do {
+ outerLoopFl = false;
+ bool tagFound = false;
+ if (_vm->_globals->_answerBuffer == NULL)
+ return;
+
+ byte *curAnswerBuf = _vm->_globals->_answerBuffer;
+ for (;;) {
+ if (READ_BE_UINT24(curAnswerBuf) == MKTAG24('F', 'I', 'N'))
+ return;
+ if (READ_BE_UINT24(curAnswerBuf) == MKTAG24('C', 'O', 'D')) {
+ if (curAnswerBuf[3] == zoneObj && curAnswerBuf[4] == verbObj)
+ tagFound = true;
+ }
+ if (!tagFound)
+ curAnswerBuf++;
+ else
+ break;
+ }
+
+ // 'COD' tag found
+ curAnswerBuf += 5;
+ ptr = _vm->_globals->allocMemory(620);
+ assert(ptr);
+ memset(ptr, 0, 620);
+ uint16 curAnswerIdx = 0;
+ int idx = 0;
+ bool innerLoopCond = false;
+ do {
+ tagFound = false;
+ if (READ_BE_UINT16(&curAnswerBuf[curAnswerIdx]) == MKTAG16('F', 'C')) {
+ ++idx;
+ assert(idx < (620 / 20));
+
+ byte *answerBuf = (ptr + 20 * idx);
+ uint16 anwerIdx = 0;
+ do {
+ assert(anwerIdx < 20);
+ answerBuf[anwerIdx++] = curAnswerBuf[curAnswerIdx++];
+ if (READ_BE_UINT16(&curAnswerBuf[curAnswerIdx]) == MKTAG16('F', 'F')) {
+ tagFound = true;
+ answerBuf[anwerIdx] = 'F';
+ answerBuf[anwerIdx + 1] = 'F';
+ ++curAnswerIdx;
+ }
+ } while (!tagFound);
+ }
+ if (!tagFound) {
+ uint32 signature24 = READ_BE_UINT24(&curAnswerBuf[curAnswerIdx]);
+ if (signature24 == MKTAG24('C', 'O', 'D') || signature24 == MKTAG24('F', 'I', 'N'))
+ innerLoopCond = true;
+ }
+ curAnswerBuf += curAnswerIdx + 1;
+ curAnswerIdx = 0;
+ } while (!innerLoopCond);
+ innerLoopCond = false;
+ int lastOpcodeResult = 1;
+ do {
+ int opcodeType = _vm->_script->handleOpcode(ptr + 20 * lastOpcodeResult);
+ if (_vm->shouldQuit())
+ return;
+
+ if (opcodeType == 2)
+ // GOTO
+ lastOpcodeResult = _vm->_script->handleGoto(ptr + 20 * lastOpcodeResult);
+ else if (opcodeType == 3)
+ // IF
+ lastOpcodeResult = _vm->_script->handleIf(ptr, lastOpcodeResult);
+
+ if (lastOpcodeResult == -1)
+ error("Invalid IFF function");
+
+ if (opcodeType == 1 || opcodeType == 4)
+ // Already handled opcode or END IF
+ ++lastOpcodeResult;
+ else if (!opcodeType || opcodeType == 5)
+ // EXIT
+ innerLoopCond = true;
+ else if (opcodeType == 6) {
+ // JUMP
+ _vm->_globals->freeMemory(ptr);
+ zoneObj = _vm->_objectsMan->_jumpZone;
+ verbObj = _vm->_objectsMan->_jumpVerb;
+ outerLoopFl = true;
+ break;
+ }
+ } while (!innerLoopCond);
+ } while (outerLoopFl);
+ _vm->_globals->freeMemory(ptr);
+ _vm->_globals->_saveData->_data[svLastZoneNum] = 0;
+ return;
+}
+
+void TalkManager::handleForestAnswser(int zone, int verb) {
+ int indx = 0;
+ if (verb != 5 || _vm->_globals->_saveData->_data[svLastObjectIndex] != 4)
+ return;
+
+ if (zone == 22 || zone == 23) {
+ _vm->_objectsMan->setFlipSprite(0, false);
+ _vm->_objectsMan->setSpriteIndex(0, 62);
+ _vm->_objectsMan->showSpecialActionAnimationWithFlip(_vm->_objectsMan->_forestSprite, "2,3,4,5,6,7,8,9,10,11,12,-1,", 4, false);
+ if (zone == 22) {
+ _vm->_objectsMan->lockAnimX(6, _vm->_objectsMan->getBobPosX(3));
+ _vm->_objectsMan->lockAnimX(8, _vm->_objectsMan->getBobPosX(3));
+ } else { // zone == 23
+ _vm->_objectsMan->lockAnimX(6, _vm->_objectsMan->getBobPosX(4));
+ _vm->_objectsMan->lockAnimX(8, _vm->_objectsMan->getBobPosX(4));
+ }
+ _vm->_objectsMan->stopBobAnimation(3);
+ _vm->_objectsMan->stopBobAnimation(4);
+ _vm->_objectsMan->setBobAnimation(6);
+ _vm->_soundMan->playSample(1);
+ _vm->_objectsMan->showSpecialActionAnimation(_vm->_objectsMan->_forestSprite, "13,14,15,14,13,12,13,14,15,16,-1,", 4);
+ do
+ _vm->_events->refreshScreenAndEvents();
+ while (_vm->_objectsMan->getBobAnimDataIdx(6) < 12);
+ _vm->_objectsMan->stopBobAnimation(6);
+ _vm->_objectsMan->setBobAnimation(8);
+
+ switch (_vm->_globals->_screenId) {
+ case 35:
+ indx = 201;
+ break;
+ case 36:
+ indx = 203;
+ break;
+ case 37:
+ indx = 205;
+ break;
+ case 38:
+ indx = 207;
+ break;
+ case 39:
+ indx = 209;
+ break;
+ case 40:
+ indx = 211;
+ break;
+ case 41:
+ indx = 213;
+ break;
+ }
+ _vm->_globals->_saveData->_data[indx] = 2;
+ _vm->_linesMan->disableZone(22);
+ _vm->_linesMan->disableZone(23);
+ } else if (zone == 20 || zone == 21) {
+ _vm->_objectsMan->setFlipSprite(0, true);
+ _vm->_objectsMan->setSpriteIndex(0, 62);
+ _vm->_objectsMan->showSpecialActionAnimationWithFlip(_vm->_objectsMan->_forestSprite, "2,3,4,5,6,7,8,9,10,11,12,-1,", 4, true);
+ if (zone == 20) {
+ _vm->_objectsMan->lockAnimX(5, _vm->_objectsMan->getBobPosX(1));
+ _vm->_objectsMan->lockAnimX(7, _vm->_objectsMan->getBobPosX(1));
+ } else { // zone == 21
+ _vm->_objectsMan->lockAnimX(5, _vm->_objectsMan->getBobPosX(2));
+ _vm->_objectsMan->lockAnimX(7, _vm->_objectsMan->getBobPosX(2));
+ }
+ _vm->_objectsMan->stopBobAnimation(1);
+ _vm->_objectsMan->stopBobAnimation(2);
+ _vm->_objectsMan->setBobAnimation(5);
+ _vm->_soundMan->playSample(1);
+ _vm->_objectsMan->showSpecialActionAnimation(_vm->_objectsMan->_forestSprite, "13,14,15,14,13,12,13,14,15,16,-1,", 4);
+ do
+ _vm->_events->refreshScreenAndEvents();
+ while (_vm->_objectsMan->getBobAnimDataIdx(5) < 12);
+ _vm->_objectsMan->stopBobAnimation(5);
+ _vm->_objectsMan->setBobAnimation(7);
+ switch (_vm->_globals->_screenId) {
+ case 35:
+ indx = 200;
+ break;
+ case 36:
+ indx = 202;
+ break;
+ case 37:
+ indx = 204;
+ break;
+ case 38:
+ indx = 206;
+ break;
+ case 39:
+ indx = 208;
+ break;
+ case 40:
+ indx = 210;
+ break;
+ case 41:
+ indx = 212;
+ break;
+ }
+ _vm->_globals->_saveData->_data[indx] = 2;
+ _vm->_linesMan->disableZone(21);
+ _vm->_linesMan->disableZone(20);
+ }
+}
+
+void TalkManager::animateObject(const Common::String &filename) {
+ _vm->_fontMan->hideText(5);
+ _vm->_fontMan->hideText(9);
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_graphicsMan->_scrollStatus = 1;
+ _vm->_linesMan->clearAllZones();
+ _vm->_linesMan->resetLines();
+ _vm->_objectsMan->resetHidingItems();
+
+ for (int i = 0; i <= 44; i++)
+ _vm->_linesMan->_bobZone[i] = 0;
+
+ _vm->_objectsMan->_zoneNum = -1;
+ _vm->_events->_mouseCursorId = 4;
+ _vm->_events->changeMouseCursor(0);
+ bool fileFoundFl = false;
+ _characterBuffer = _vm->_fileIO->searchCat(filename, RES_PER, fileFoundFl);
+ _characterSize = _vm->_fileIO->_catalogSize;
+ if (!fileFoundFl) {
+ _characterBuffer = _vm->_fileIO->loadFile(filename);
+ _characterSize = _vm->_fileIO->fileSize(filename);
+ }
+ Common::String screenFilename;
+ Common::String spriteFilename;
+ Common::String curScreenFilename;
+ getStringFromBuffer(40, spriteFilename, (const char *)_characterBuffer);
+ getStringFromBuffer(0, screenFilename, (const char *)_characterBuffer);
+ getStringFromBuffer(20, curScreenFilename, (const char *)_characterBuffer);
+
+ if (curScreenFilename == "NULL")
+ curScreenFilename = Common::String::format("IM%d", _vm->_globals->_screenId);
+
+ fileFoundFl = false;
+ _characterSprite = _vm->_fileIO->searchCat(spriteFilename, RES_SAN, fileFoundFl);
+ if (!fileFoundFl)
+ _characterSprite = _vm->_objectsMan->loadSprite(spriteFilename);
+ else
+ _characterSprite = _vm->_objectsMan->loadSprite("RES_SAN.RES");
+
+ _vm->_graphicsMan->backupScreen();
+
+ if (!_vm->_graphicsMan->_lineNbr)
+ _vm->_graphicsMan->_scrollOffset = 0;
+ _vm->_graphicsMan->displayScreen(true);
+ _paletteBufferIdx = 20 * READ_LE_INT16((uint16 *)_characterBuffer + 42) + 110;
+ _vm->_graphicsMan->displayScreen(true);
+ _vm->_objectsMan->_charactersEnabledFl = true;
+ searchCharacterPalette(_paletteBufferIdx, true);
+ startCharacterAnim0(_paletteBufferIdx, false);
+ byte *oldAnswerBufferPtr = _vm->_globals->_answerBuffer;
+ _vm->_globals->_answerBuffer = NULL;
+ _vm->_globals->_freezeCharacterFl = true;
+ _vm->_objectsMan->loadLinkFile(screenFilename);
+ _vm->_objectsMan->_charactersEnabledFl = true;
+ _vm->_globals->_actionMoveTo = false;
+ _vm->_objectsMan->_zoneNum = -1;
+ initCharacterAnim();
+ dialogAnim();
+ dialogWait();
+ _vm->_graphicsMan->initScreen(screenFilename, 2, true);
+ _vm->_globals->_freezeCharacterFl = true;
+ _vm->_objectsMan->_forceZoneFl = true;
+ _vm->_objectsMan->_zoneNum = -1;
+ do {
+ int mouseButton = _vm->_events->getMouseButton();
+ if (mouseButton == 1)
+ _vm->_objectsMan->handleLeftButton();
+ else if (mouseButton == 2)
+ _vm->_objectsMan->handleRightButton();
+
+ _vm->_linesMan->checkZone();
+ if (_vm->_globals->_actionMoveTo)
+ _vm->_objectsMan->PARADISE();
+ _vm->_events->refreshScreenAndEvents();
+ } while (!_vm->_globals->_exitId);
+ dialogEndTalk();
+ dialogTalk();
+ clearCharacterAnim();
+ clearCharacterAnim();
+ _vm->_globals->_introSpeechOffFl = false;
+ _characterBuffer = _vm->_globals->freeMemory(_characterBuffer);
+ _characterSprite = _vm->_globals->freeMemory(_characterSprite);
+ _vm->_graphicsMan->displayScreen(false);
+ _vm->_linesMan->clearAllZones();
+ _vm->_linesMan->resetLines();
+ _vm->_objectsMan->resetHidingItems();
+ for (int i = 0; i <= 44; i++)
+ _vm->_linesMan->_bobZone[i] = 0;
+
+ _vm->_globals->freeMemory(_vm->_globals->_answerBuffer);
+ _vm->_globals->_answerBuffer = oldAnswerBufferPtr;
+ _vm->_objectsMan->_disableFl = true;
+ _vm->_objectsMan->loadLinkFile(curScreenFilename);
+ _vm->_graphicsMan->initScreen(curScreenFilename, 2, true);
+ _vm->_objectsMan->_disableFl = false;
+ _vm->_globals->_freezeCharacterFl = false;
+ if (_vm->_globals->_exitId == 101)
+ _vm->_globals->_exitId = 0;
+
+ _vm->_graphicsMan->restoreScreen();
+
+ _vm->_objectsMan->_charactersEnabledFl = false;
+ _vm->_events->_mouseCursorId = 4;
+ _vm->_events->changeMouseCursor(4);
+ _vm->_graphicsMan->setColorPercentage(253, 100, 100, 100);
+
+ if (!_vm->getIsDemo())
+ _vm->_graphicsMan->setColorPercentage(254, 0, 0, 0);
+
+ _vm->_graphicsMan->initColorTable(145, 150, _vm->_graphicsMan->_palette);
+ _vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
+ _vm->_graphicsMan->copy16BitRect(_vm->_graphicsMan->_backBuffer, _vm->_events->_startPos.x, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
+ _vm->_graphicsMan->setPaletteVGA256(_vm->_graphicsMan->_palette);
+ memcpy(_vm->_graphicsMan->_frontBuffer, _vm->_graphicsMan->_backBuffer, 614399);
+ _vm->_globals->_disableInventFl = false;
+ _vm->_graphicsMan->updateScreen();
+ for (int i = 0; i <= 4; i++)
+ _vm->_events->refreshScreenAndEvents();
+ _vm->_graphicsMan->_scrollStatus = 0;
+}
+
+} // End of namespace Hopkins